summaryrefslogtreecommitdiffstats
path: root/daemons/ipa-kdb
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2011-05-20 01:26:46 -0400
committerSimo Sorce <ssorce@redhat.com>2011-08-26 08:24:49 -0400
commit6e010fedaa33face61fd521c9f94e5a6058bfd5f (patch)
treef876a8e0e0d1f9ff659c69372f822edc405f6f47 /daemons/ipa-kdb
parent579a1599151f6964673afa39188e64c1d9dd23cc (diff)
downloadfreeipa-6e010fedaa33face61fd521c9f94e5a6058bfd5f.tar.gz
freeipa-6e010fedaa33face61fd521c9f94e5a6058bfd5f.tar.xz
freeipa-6e010fedaa33face61fd521c9f94e5a6058bfd5f.zip
ipa-kdb: initialize module functions
Initialize module also on ipadb_create invocation. This is what kdb5_util expects.
Diffstat (limited to 'daemons/ipa-kdb')
-rw-r--r--daemons/ipa-kdb/Makefile.am1
-rw-r--r--daemons/ipa-kdb/ipa_kdb.c346
-rw-r--r--daemons/ipa-kdb/ipa_kdb.h43
3 files changed, 384 insertions, 6 deletions
diff --git a/daemons/ipa-kdb/Makefile.am b/daemons/ipa-kdb/Makefile.am
index 30076241f..309618a29 100644
--- a/daemons/ipa-kdb/Makefile.am
+++ b/daemons/ipa-kdb/Makefile.am
@@ -8,6 +8,7 @@ INCLUDES = \
-DLIBDIR=\""$(libdir)"\" \
-DLIBEXECDIR=\""$(libexecdir)"\" \
-DDATADIR=\""$(datadir)"\" \
+ -DLDAPIDIR=\""$(localstatedir)/run"\" \
$(AM_CFLAGS) \
$(LDAP_CFLAGS) \
$(KRB5_CFLAGS) \
diff --git a/daemons/ipa-kdb/ipa_kdb.c b/daemons/ipa-kdb/ipa_kdb.c
index ba0bd2f0c..aa0c154a2 100644
--- a/daemons/ipa-kdb/ipa_kdb.c
+++ b/daemons/ipa-kdb/ipa_kdb.c
@@ -20,35 +20,369 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <kdb.h>
+#include "ipa_kdb.h"
+
+struct ipadb_context *ipadb_get_context(krb5_context kcontext)
+{
+ void *db_ctx;
+ krb5_error_code kerr;
+
+ kerr = krb5_db_get_context(kcontext, &db_ctx);
+ if (kerr != 0) {
+ return NULL;
+ }
+
+ return (struct ipadb_context *)db_ctx;
+}
+
+static void ipadb_context_free(krb5_context kcontext,
+ struct ipadb_context **ctx)
+{
+ if (*ctx != NULL) {
+ free((*ctx)->uri);
+ /* ldap free lcontext */
+ if ((*ctx)->lcontext) {
+ ldap_unbind_ext_s((*ctx)->lcontext, NULL, NULL);
+ }
+ krb5_free_default_realm(kcontext, (*ctx)->realm);
+ free(*ctx);
+ *ctx = NULL;
+ }
+}
+
+#define LDAPI_URI_PREFIX "ldapi://"
+#define LDAPI_PATH_PREFIX "%2fslapd-"
+#define SOCKET_SUFFIX ".socket"
+#define APPEND_PATH_PART(pos, part) \
+ do { \
+ int partlen = strlen(part); \
+ strncpy(pos, part, partlen + 1); \
+ p += partlen; \
+ } while (0)
+
+static char *ipadb_realm_to_ldapi_uri(char *realm)
+{
+ char *uri = NULL;
+ char *p;
+ const char *q;
+ int len;
+
+ /* uri length, assume worst case for LDAPIDIR */
+ len = strlen(LDAPI_URI_PREFIX) + strlen(LDAPIDIR) * 3
+ + strlen(LDAPI_PATH_PREFIX) + strlen(realm)
+ + strlen(SOCKET_SUFFIX) + 1;
+
+ /* worst case they are all '/' to escape */
+ uri = malloc(len);
+ if (!uri) {
+ return NULL;
+ }
+ p = uri;
+
+ APPEND_PATH_PART(p, LDAPI_URI_PREFIX);
+
+ /* copy path and escape '/' to '%2f' */
+ for (q = LDAPIDIR; *q; q++) {
+ if (*q == '/') {
+ strncpy(p, "%2f", 3);
+ p += 3;
+ } else {
+ *p = *q;
+ p++;
+ }
+ }
+
+ APPEND_PATH_PART(p, LDAPI_PATH_PREFIX);
+
+ /* copy realm and convert '.' to '-' */
+ for (q = realm; *q; q++) {
+ if (*q == '.') {
+ *p = '-';
+ } else {
+ *p = *q;
+ }
+ p++;
+ }
+
+ /* terminate string */
+ APPEND_PATH_PART(p, SOCKET_SUFFIX);
+
+ return uri;
+}
+
+/* in IPA the base is always derived from the realm name */
+static char *ipadb_get_base_from_realm(krb5_context kcontext)
+{
+ krb5_error_code kerr;
+ char *realm = NULL;
+ char *base = NULL;
+ char *tmp;
+ size_t bi, ri;
+ size_t len;
+
+ kerr = krb5_get_default_realm(kcontext, &realm);
+ if (kerr != 0) {
+ return NULL;
+ }
+
+ bi = 3;
+ len = strlen(realm) + 3 + 1;
+
+ base = malloc(len);
+ if (!base) {
+ goto done;
+ }
+ strcpy(base, "dc=");
+
+ /* convert EXAMPLE.COM in dc=example,dc=com */
+ for (ri = 0; realm[ri]; ri++) {
+ if (realm[ri] == '.') {
+ len += 4;
+ tmp = realloc(base, len);
+ if (!tmp) {
+ free(base);
+ base = NULL;
+ goto done;
+ }
+ base = tmp;
+ strcpy(&base[bi], ",dc=");
+ bi += 4;
+ } else {
+ base[bi] = tolower(realm[ri]);
+ bi++;
+ }
+ }
+ base[bi] = '\0';
+
+done:
+ krb5_free_default_realm(kcontext, realm);
+ return base;
+}
+
+int ipadb_get_connection(struct ipadb_context *ipactx)
+{
+ struct berval **vals = NULL;
+ struct timeval tv = { 5, 0 };
+ LDAPMessage *res = NULL;
+ LDAPMessage *first;
+ krb5_key_salt_tuple *kst;
+ int n_kst;
+ int ret;
+ int v3;
+ int i;
+ char **cvals = NULL;
+ int c = 0;
+
+ if (!ipactx->uri) {
+ return EINVAL;
+ }
+
+ /* free existing conneciton if any */
+ if (ipactx->lcontext) {
+ ldap_unbind_ext_s(ipactx->lcontext, NULL, NULL);
+ ipactx->lcontext = NULL;
+ }
+
+ ret = ldap_initialize(&ipactx->lcontext, ipactx->uri);
+ if (ret != LDAP_SUCCESS) {
+ goto done;
+ }
+
+ /* make sure we talk LDAPv3 */
+ v3 = LDAP_VERSION3;
+ ret = ldap_set_option(ipactx->lcontext, LDAP_OPT_PROTOCOL_VERSION, &v3);
+ if (ret != LDAP_OPT_SUCCESS) {
+ goto done;
+ }
+
+ ret = ldap_set_option(ipactx->lcontext, LDAP_OPT_NETWORK_TIMEOUT, &tv);
+ if (ret != LDAP_OPT_SUCCESS) {
+ goto done;
+ }
+
+ ret = ldap_set_option(ipactx->lcontext, LDAP_OPT_TIMEOUT, &tv);
+ if (ret != LDAP_OPT_SUCCESS) {
+ goto done;
+ }
+
+ ret = ldap_sasl_bind_s(ipactx->lcontext,
+ NULL, "EXTERNAL",
+ NULL, NULL, NULL, NULL);
+ if (ret != LDAP_SUCCESS) {
+ goto done;
+ }
+
+ /* TODO: search rootdse */
+
+ ret = ipadb_simple_search(ipactx,
+ ipactx->realm_base, LDAP_SCOPE_BASE,
+ "(objectclass=*)", NULL, &res);
+ if (ret) {
+ goto done;
+ }
+
+ first = ldap_first_entry(ipactx->lcontext, res);
+ if (!first) {
+ goto done;
+ }
+
+ vals = ldap_get_values_len(ipactx->lcontext, first,
+ "krbSupportedEncSaltTypes");
+ if (!vals || !vals[0]) {
+ goto done;
+ }
+
+ for (c = 0; vals[c]; c++) /* count */ ;
+ cvals = calloc(c, sizeof(char *));
+ if (!cvals) {
+ ret = ENOMEM;
+ goto done;
+ }
+ for (i = 0; i < c; i++) {
+ cvals[i] = strndup(vals[i]->bv_val, vals[i]->bv_len);
+ if (!cvals[i]) {
+ ret = ENOMEM;
+ goto done;
+ }
+ }
+
+ ret = parse_bval_key_salt_tuples(ipactx->kcontext,
+ (const char * const *)cvals, c,
+ &kst, &n_kst);
+ if (ret) {
+ goto done;
+ }
+
+ if (ipactx->supp_encs) {
+ free(ipactx->supp_encs);
+ }
+ ipactx->supp_encs = kst;
+ ipactx->n_supp_encs = n_kst;
+
+ ret = 0;
+
+done:
+ if (ret) {
+ if (ipactx->lcontext) {
+ ldap_unbind_ext_s(ipactx->lcontext, NULL, NULL);
+ ipactx->lcontext = NULL;
+ }
+ if (ret == LDAP_SERVER_DOWN) {
+ return ETIMEDOUT;
+ }
+ return EIO;
+ }
+
+ ldap_value_free_len(vals);
+ for (i = 0; i < c; i++) {
+ free(cvals[i]);
+ }
+ free(cvals);
+
+ return 0;
+}
+
+/* INTERFACE */
static krb5_error_code ipadb_init_library(void)
{
- return KRB5_PLUGIN_OP_NOTSUPP;
+ return 0;
}
static krb5_error_code ipadb_fini_library(void)
{
- return KRB5_PLUGIN_OP_NOTSUPP;
+ return 0;
}
static krb5_error_code ipadb_init_module(krb5_context kcontext,
char *conf_section,
char **db_args, int mode)
{
- return KRB5_PLUGIN_OP_NOTSUPP;
+ struct ipadb_context *ipactx;
+ krb5_error_code kerr;
+ int ret;
+ int i;
+
+ /* make sure the context is freed to avoid leaking it */
+ ipactx = ipadb_get_context(kcontext);
+ ipadb_context_free(kcontext, &ipactx);
+
+ /* only check for unsupported 'temporary' value for now */
+ for (i = 0; db_args != NULL && db_args[i] != NULL; i++) {
+
+ if (strncmp(db_args[i], "temporary", 9) == 0) {
+ krb5_set_error_message(kcontext, EINVAL,
+ "Plugin requires -update argument!");
+ return EINVAL;
+ }
+ }
+
+ ipactx = calloc(1, sizeof(struct ipadb_context));
+ if (!ipactx) {
+ return ENOMEM;
+ }
+
+ ipactx->kcontext = kcontext;
+
+ kerr = krb5_get_default_realm(kcontext, &ipactx->realm);
+ if (kerr != 0) {
+ ret = EINVAL;
+ goto fail;
+ }
+
+ ipactx->uri = ipadb_realm_to_ldapi_uri(ipactx->realm);
+ if (!ipactx->uri) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ipactx->base = ipadb_get_base_from_realm(kcontext);
+ if (!ipactx->base) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = asprintf(&ipactx->realm_base, "cn=%s,cn=kerberos,%s",
+ ipactx->realm, ipactx->base);
+ if (ret == -1) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = ipadb_get_connection(ipactx);
+ if (ret != 0) {
+ /* not a fatal failure, as the LDAP server may be temporarily down */
+ /* TODO: spam syslog with this error */
+ }
+
+ kerr = krb5_db_set_context(kcontext, ipactx);
+ if (kerr != 0) {
+ ret = EACCES;
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ ipadb_context_free(kcontext, &ipactx);
+ return ret;
}
static krb5_error_code ipadb_fini_module(krb5_context kcontext)
{
- return KRB5_PLUGIN_OP_NOTSUPP;
+ struct ipadb_context *ipactx;
+
+ ipactx = ipadb_get_context(kcontext);
+ ipadb_context_free(kcontext, &ipactx);
+
+ return 0;
}
static krb5_error_code ipadb_create(krb5_context kcontext,
char *conf_section,
char **db_args)
{
- return KRB5_PLUGIN_OP_NOTSUPP;
+ return ipadb_init_module(kcontext, conf_section, db_args, 0);
}
static krb5_error_code ipadb_get_age(krb5_context kcontext,
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
new file mode 100644
index 000000000..f91498a21
--- /dev/null
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -0,0 +1,43 @@
+/*
+ * MIT Kerberos KDC database backend for FreeIPA
+ *
+ * Authors: Simo Sorce <ssorce@redhat.com>
+ *
+ * Copyright (C) 2011 Simo Sorce, Red Hat
+ * see file 'COPYING' for use and warranty information
+ *
+ * This program is free software you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE 1
+#endif
+
+#include <errno.h>
+#include <kdb.h>
+#include <ldap.h>
+
+struct ipadb_context {
+ char *uri;
+ char *base;
+ char *realm;
+ char *realm_base;
+ LDAP *lcontext;
+ krb5_context kcontext;
+ krb5_key_salt_tuple *supp_encs;
+ int n_supp_encs;
+};
+
+struct ipadb_context *ipadb_get_context(krb5_context kcontext);
+int ipadb_get_connection(struct ipadb_context *ipactx);