[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: heimdal for ldap




Hi Johan,

I made a patch to improve error handling and also allow the
"whatever" to specify a base distinguished name. (Probably
it should let you specify an LDAP URL, but...) I removed
the code that traversed the server's namingcontexts looking
for a candidate: nice idea, but not very useful. I updated
the web page with a configuration example.

I also fixed a bug where LDAP_dn2principal() was searching
under the default DN, not at the principal's DN.

The patch is attached.

-- Luke

>From: joda@pdc.kth.se (Johan Danielsson)
>Subject: Re: heimdal for ldap
>To: "novice heimdal" <heimdal@rediffmail.com>
>Cc: <heimdal-discuss@sics.se>
>Date: 10 Aug 2001 09:35:34 +0200
>
>"novice  heimdal" <heimdal@rediffmail.com> writes:
>
>> now what do i need to do to have my principals stored in ldap not in
>> the default berkley db?
>
>You probably need something like:
>
>[kdc]
>        database = {
>                dbname = ldab:whatever
>                mkey_file = /path/to/mkey
>        }
>
>in your kdc.conf.
>
>I don't think the whatever part is currently used by the ldap, but in
>theory it should be something that describes the database. In the
>normal db-case it's a filename.
>
>I assume you've checked out Luke Howard's page on the matter:
>http://www.padl.com/~lukeh/heimdal/
>
>Is there anyone actually using this that can comment?
>
>/Johan

--- hdb-ldap.c.orig	Sat Aug 11 13:45:55 2001
+++ hdb-ldap.c	Sat Aug 11 14:18:54 2001
@@ -335,6 +335,7 @@
     if (ent->kvno != orig.kvno) {
 	rc = asprintf(&tmp, "%d", ent->kvno);
 	if (rc < 0) {
+	    krb5_set_error_string(context, "asprintf: out of memory");
 	    ret = ENOMEM;
 	    goto out;
 	}
@@ -390,6 +391,7 @@
 	    || (*(ent->max_life) != *(orig.max_life))) {
 	    rc = asprintf(&tmp, "%d", *(ent->max_life));
 	    if (rc < 0) {
+		krb5_set_error_string(context, "asprintf: out of memory");
 		ret = ENOMEM;
 		goto out;
 	    }
@@ -406,6 +408,7 @@
 	    || (*(ent->max_renew) != *(orig.max_renew))) {
 	    rc = asprintf(&tmp, "%d", *(ent->max_renew));
 	    if (rc < 0) {
+		krb5_set_error_string(context, "asprintf: out of memory");
 		ret = ENOMEM;
 		goto out;
 	    }
@@ -426,6 +429,7 @@
     if (memcmp(&oflags, &nflags, sizeof(HDBFlags))) {
 	rc = asprintf(&tmp, "%lu", nflags);
 	if (rc < 0) {
+	    krb5_set_error_string(context, "asprintf: out of memory");
 	    ret = ENOMEM;
 	    goto out;
 	}
@@ -457,6 +461,7 @@
 	len = length_Key(&new);
 	buf = malloc(len);
 	if (buf == NULL) {
+	    krb5_set_error_string(context, "malloc: out of memory");
 	    ret = ENOMEM;
 	    free_Key(&new);
 	    goto out;
@@ -487,6 +492,7 @@
 	for (i = 0; i < ent->etypes->len; i++) {
 	    rc = asprintf(&tmp, "%d", ent->etypes->val[i]);
 	    if (rc < 0) {
+		krb5_set_error_string(context, "asprintf: out of memory");
 		ret = ENOMEM;
 		goto out;
 	    }
@@ -524,17 +530,22 @@
 		  krb5_principal * principal)
 {
     krb5_error_code ret;
-    int rc;
+    int rc, limit = 1;
     char **values;
     LDAPMessage *res = NULL, *e;
 
-    rc = 1;
-    (void) ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, &rc);
-    rc = ldap_search_s((LDAP *) db->db, db->name, LDAP_SCOPE_BASE,
+    rc = ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, (const void *)&limit);
+    if (rc != LDAP_SUCCESS) {
+	krb5_set_error_string(context, "ldap_set_option: %s", ldap_err2string(rc));
+	ret = HDB_ERR_BADVERSION;
+	goto out;
+     }
+
+    rc = ldap_search_s((LDAP *) db->db, dn, LDAP_SCOPE_BASE,
 		       "(objectclass=krb5Principal)", krb5principal_attrs,
 		       0, &res);
-
     if (rc != LDAP_SUCCESS) {
+	krb5_set_error_string(context, "ldap_search_s: %s", ldap_err2string(rc));
 	ret = HDB_ERR_NOENTRY;
 	goto out;
     }
@@ -566,7 +577,7 @@
 		   LDAPMessage ** msg)
 {
     krb5_error_code ret;
-    int rc;
+    int rc, limit = 1;
     char *filter = NULL;
 
     (void) LDAP__connect(context, db);
@@ -576,16 +587,22 @@
 		 "(&(objectclass=krb5KDCEntry)(krb5PrincipalName=%s))",
 		 princname);
     if (rc < 0) {
+	krb5_set_error_string(context, "asprintf: out of memory");
 	ret = ENOMEM;
 	goto out;
     }
 
-    rc = 1;
-    (void) ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, (void *) &rc);
+    rc = ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, (const void *)&limit);
+    if (rc != LDAP_SUCCESS) {
+	krb5_set_error_string(context, "ldap_set_option: %s", ldap_err2string(rc));
+	ret = HDB_ERR_BADVERSION;
+	goto out;
+    }
 
     rc = ldap_search_s((LDAP *) db->db, db->name, LDAP_SCOPE_ONELEVEL, filter, 
 		       krb5kdcentry_attrs, 0, msg);
     if (rc != LDAP_SUCCESS) {
+	krb5_set_error_string(context, "ldap_search_s: %s", ldap_err2string(rc));
 	ret = HDB_ERR_NOENTRY;
 	goto out;
     }
@@ -659,6 +676,11 @@
 
 	ent->keys.len = ldap_count_values_len(keys);
 	ent->keys.val = (Key *) calloc(ent->keys.len, sizeof(Key));
+	if (ent->keys.val == NULL) {
+	    krb5_set_error_string(context, "calloc: out of memory");
+	    ret = ENOMEM;
+	    goto out;
+	}
 	for (i = 0; i < ent->keys.len; i++) {
 	    decode_Key((unsigned char *) keys[i]->bv_val,
 		       (size_t) keys[i]->bv_len, &ent->keys.val[i], &l);
@@ -699,6 +721,7 @@
 
     ent->modified_by = (Event *) malloc(sizeof(Event));
     if (ent->modified_by == NULL) {
+	krb5_set_error_string(context, "malloc: out of memory");
 	ret = ENOMEM;
 	goto out;
     }
@@ -719,6 +742,7 @@
 
     if ((ent->valid_start = (KerberosTime *) malloc(sizeof(KerberosTime)))
 	== NULL) {
+	krb5_set_error_string(context, "malloc: out of memory");
 	ret = ENOMEM;
 	goto out;
     }
@@ -732,7 +756,9 @@
     }
 
     if ((ent->valid_end = (KerberosTime *) malloc(sizeof(KerberosTime))) ==
-	NULL) {ret = ENOMEM;
+	NULL) {
+	krb5_set_error_string(context, "malloc: out of memory");
+	ret = ENOMEM;
 	goto out;
     }
     ret =
@@ -745,7 +771,9 @@
     }
 
     if ((ent->pw_end = (KerberosTime *) malloc(sizeof(KerberosTime))) ==
-	NULL) {ret = ENOMEM;
+	NULL) {
+	krb5_set_error_string(context, "malloc: out of memory");
+	ret = ENOMEM;
 	goto out;
     }
     ret =
@@ -759,6 +787,7 @@
 
     ent->max_life = (int *) malloc(sizeof(int));
     if (ent->max_life == NULL) {
+	krb5_set_error_string(context, "malloc: out of memory");
 	ret = ENOMEM;
 	goto out;
     }
@@ -770,6 +799,7 @@
 
     ent->max_renew = (int *) malloc(sizeof(int));
     if (ent->max_renew == NULL) {
+	krb5_set_error_string(context, "malloc: out of memory");
 	ret = ENOMEM;
 	goto out;
     }
@@ -783,6 +813,7 @@
     if (values != NULL) {
 	tmp = strtoul(values[0], (char **) NULL, 10);
 	if (tmp == ULONG_MAX && errno == ERANGE) {
+	    krb5_set_error_string(context, "strtoul: could not convert flag");
 	    ret = ERANGE;
 	    goto out;
 	}
@@ -797,6 +828,7 @@
 
 	ent->etypes = malloc(sizeof(*(ent->etypes)));
 	if (ent->etypes == NULL) {
+	    krb5_set_error_string(context, "malloc: out of memory");
 	    ret = ENOMEM;
 	    goto out;
 	}
@@ -825,10 +857,9 @@
 
 static krb5_error_code LDAP_close(krb5_context context, HDB * db)
 {
-    LDAP *ld = (LDAP *) db->db;
-
-    ldap_unbind(ld);
+    ldap_unbind_ext((LDAP *) db->db, NULL, NULL);
     db->db = NULL;
+
     return 0;
 }
 
@@ -870,6 +901,7 @@
 				  NULL, NULL, 1);
 	    if (parserc != LDAP_SUCCESS
 		&& parserc != LDAP_MORE_RESULTS_TO_RETURN) {
+	        krb5_set_error_string(context, "ldap_parse_result: %s", ldap_err2string(parserc));
 		ldap_abandon((LDAP *) db->db, msgid);
 	    }
 	    ret = HDB_ERR_NOENTRY;
@@ -902,12 +934,15 @@
 LDAP_firstkey(krb5_context context, HDB * db, unsigned flags,
 	      hdb_entry * entry)
 {
-    int msgid;
+    int msgid, limit = LDAP_NO_LIMIT, rc;
 
     (void) LDAP__connect(context, db);
 
-    msgid = LDAP_NO_LIMIT;
-    (void) ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, &msgid);
+    rc = ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, (const void *)&limit);
+    if (rc != LDAP_SUCCESS) {
+	krb5_set_error_string(context, "ldap_set_option: %s", ldap_err2string(rc));
+	return HDB_ERR_BADVERSION;
+    }
 
     msgid = ldap_search((LDAP *) db->db, db->name,
 			LDAP_SCOPE_ONELEVEL, "(objectclass=krb5KDCEntry)",
@@ -934,33 +969,10 @@
     return HDB_ERR_DB_INUSE;
 }
 
-static krb5_boolean LDAP__is_user_namingcontext(const char *ctx,
-						char *const *subschema)
-{
-    char *const *p;
-
-    if (!strcasecmp(ctx, "CN=MONITOR")
-	|| !strcasecmp(ctx, "CN=CONFIG")) {
-	return FALSE;
-    }
-
-    if (subschema != NULL) {
-	for (p = subschema; *p != NULL; p++) {
-	    if (!strcasecmp(ctx, *p)) {
-		return FALSE;
-	    }
-	}
-    }
-
-    return TRUE;
-}
-
 static krb5_error_code LDAP__connect(krb5_context context, HDB * db)
 {
-    int rc;
+    int rc, version = LDAP_VERSION3;
     krb5_error_code ret;
-    char *attrs[] = { "namingContexts", "subschemaSubentry", NULL };
-    LDAPMessage *res = NULL, *e;
 
     if (db->db != NULL) {
 	/* connection has been opened. ping server. */
@@ -982,111 +994,38 @@
 
     rc = ldap_initialize((LDAP **) & db->db, "ldapi:///");
     if (rc != LDAP_SUCCESS) {
+	krb5_set_error_string(context, "ldap_initialize: %s", ldap_err2string(rc));
 	return HDB_ERR_NOENTRY;
     }
 
-    rc = LDAP_VERSION3;
-    (void) ldap_set_option((LDAP *) db->db, LDAP_OPT_PROTOCOL_VERSION, &rc);
-
-    /* XXX set db->name to the search base */
-    rc = ldap_search_s((LDAP *) db->db, "", LDAP_SCOPE_BASE,
-		       "(objectclass=*)", attrs, 0, &res);
+    rc = ldap_set_option((LDAP *) db->db, LDAP_OPT_PROTOCOL_VERSION, (const void *)&version);
     if (rc != LDAP_SUCCESS) {
-	ret = HDB_ERR_BADVERSION;
-	goto out;
-    }
-
-    e = ldap_first_entry((LDAP *) db->db, res);
-    if (e == NULL) {
-	ret = HDB_ERR_NOENTRY;
-	goto out;
+	krb5_set_error_string(context, "ldap_set_option: %s", ldap_err2string(rc));
+	ldap_unbind_ext((LDAP *) db->db, NULL, NULL);
+	db->db = NULL;
+	return HDB_ERR_BADVERSION;
     }
 
-    if (db->name == NULL) {
-	char **contexts = NULL, **schema_contexts, **p;
-
-	contexts = ldap_get_values((LDAP *) db->db, e, "namingContexts");
-	if (contexts == NULL) {
-	    ret = HDB_ERR_NOENTRY;
-	    goto out;
-	}
-
-	schema_contexts =
-	    ldap_get_values((LDAP *) db->db, e, "subschemaSubentry");
-
-	if (db->name != NULL) {
-	    free(db->name);
-	    db->name = NULL;
-	}
-
-	for (p = contexts; *p != NULL; p++) {
-	    if (LDAP__is_user_namingcontext(*p, schema_contexts)) {
-		break;
-	    }
-	}
-
-	db->name = strdup(*p);
-	if (db->name == NULL) {
-	    ldap_value_free(contexts);
-	    ret = ENOMEM;
-	    goto out;
-	}
-
-	ldap_value_free(contexts);
-	if (schema_contexts != NULL) {
-	    ldap_value_free(schema_contexts);
-	}
-    }
-
-    ret = 0;
-
-  out:
-
-    if (res != NULL) {
-	ldap_msgfree(res);
-    }
-
-    if (ret != 0) {
-	if (db->db != NULL) {
-	    ldap_unbind((LDAP *) db->db);
-	    db->db = NULL;
-	}
-    }
-
-    return ret;
+    return 0;
 }
 
 static krb5_error_code
 LDAP_open(krb5_context context, HDB * db, int flags, mode_t mode)
 {
-    krb5_error_code ret;
-
     /* Not the right place for this. */
 #ifdef HAVE_SIGACTION
-    {
-	struct sigaction sa;
+    struct sigaction sa;
 
-	sa.sa_flags = 0;
-	sa.sa_handler = SIG_IGN;
-	sigemptyset(&sa.sa_mask);
+    sa.sa_flags = 0;
+    sa.sa_handler = SIG_IGN;
+    sigemptyset(&sa.sa_mask);
 
-	sigaction(SIGPIPE, &sa, NULL);
-    }
+    sigaction(SIGPIPE, &sa, NULL);
 #else
     signal(SIGPIPE, SIG_IGN);
-#endif
+#endif /* HAVE_SIGACTION */
 
-    if (db->name != NULL) {
-	free(db->name);
-	db->name = NULL;
-    }
-
-    ret = LDAP__connect(context, db);
-    if (ret != 0) {
-	return ret;
-    }
-
-    return ret;
+    return LDAP__connect(context, db);
 }
 
 static krb5_error_code
@@ -1128,6 +1067,8 @@
 {
     LDAPMod **mods = NULL;
     krb5_error_code ret;
+    const char *errfn;
+    int rc;
     LDAPMessage *msg = NULL, *e = NULL;
     char *dn = NULL, *name = NULL;
 
@@ -1142,8 +1083,9 @@
     }
 
     ret = hdb_seal_keys(context, db, entry);
-    if (ret)
+    if (ret != 0) {
 	goto out;
+    }
 
     /* turn new entry into LDAPMod array */
     ret = LDAP_entry2mods(context, db, entry, e, &mods);
@@ -1178,8 +1120,14 @@
 	    goto out;
 	}
 
-	ret = asprintf(&dn, "cn=%s,%s", name, db->name);
+	if (db->name != NULL) {
+	    ret = asprintf(&dn, "cn=%s,%s", name, db->name);
+	} else {
+	    /* A bit bogus, but we don't have a search base */
+	    ret = asprintf(&dn, "cn=%s", name, db->name);
+	}
 	if (ret < 0) {
+	    krb5_set_error_string(context, "asprintf: out of memory");
 	    ret = ENOMEM;
 	    goto out;
 	}
@@ -1195,15 +1143,18 @@
     /* write entry into directory */
     if (e == NULL) {
 	/* didn't exist before */
-	ret = ldap_add_s((LDAP *) db->db, dn, mods);
+	rc = ldap_add_s((LDAP *) db->db, dn, mods);
+	errfn = "ldap_add_s";
     } else {
 	/* already existed, send deltas only */
-	ret = ldap_modify_s((LDAP *) db->db, dn, mods);
+	rc = ldap_modify_s((LDAP *) db->db, dn, mods);
+	errfn = "ldap_modify_s";
     }
 
-    if (ret == LDAP_SUCCESS) {
+    if (rc == LDAP_SUCCESS) {
 	ret = 0;
     } else {
+	krb5_set_error_string(context, "%s: %s", ldap_err2string(rc));
 	ret = HDB_ERR_CANT_LOCK_DB;
     }
 
@@ -1234,6 +1185,7 @@
     krb5_error_code ret;
     LDAPMessage *msg, *e;
     char *dn = NULL;
+    int rc, limit = LDAP_NO_LIMIT;
 
     ret = LDAP_principal2message(context, db, entry->principal, &msg);
     if (ret != 0) {
@@ -1252,13 +1204,18 @@
 	goto out;
     }
 
-    ret = LDAP_NO_LIMIT;
-    (void) ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, &ret);
+    rc = ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, (const void *)&limit);
+    if (rc != LDAP_SUCCESS) {
+	krb5_set_error_string(context, "ldap_set_option: %s", ldap_err2string(rc));
+	ret = HDB_ERR_BADVERSION;
+	goto out;
+    }
 
-    ret = ldap_delete_s((LDAP *) db->db, dn);
-    if (ret == LDAP_SUCCESS) {
+    rc = ldap_delete_s((LDAP *) db->db, dn);
+    if (rc == LDAP_SUCCESS) {
 	ret = 0;
     } else {
+	krb5_set_error_string(context, "ldap_delete_s: %s", ldap_err2string(rc));
 	ret = HDB_ERR_CANT_LOCK_DB;
     }
 
@@ -1304,22 +1261,44 @@
     krb5_error_code ret;
 
     ret = hdb_clear_master_key(context, db);
-    free(db->name);
+    if (db->name != NULL) {
+	free(db->name);
+    }
     free(db);
 
     return ret;
 }
 
 krb5_error_code
-hdb_ldap_create(krb5_context context, HDB ** db, const char *filename)
+hdb_ldap_create(krb5_context context, HDB ** db, const char *arg)
 {
     *db = malloc(sizeof(**db));
-    if (*db == NULL)
+    if (*db == NULL) {
+	krb5_set_error_string(context, "malloc: out of memory");
 	return ENOMEM;
+    }
 
     (*db)->db = NULL;
-/*    (*db)->name = strdup(filename); */
-    (*db)->name = NULL;
+
+    if (arg == NULL || arg[0] == '\0') {
+	/*
+	 * if no argument specified in the configuration file
+	 * then use NULL, which tells OpenLDAP to look in
+	 * the ldap.conf file. This doesn't work for
+	 * writing entries because we don't know where to
+	 * put new principals.
+	 */
+	(*db)->name = NULL;
+    } else {
+	(*db)->name = strdup(arg); 
+	if ((*db)->name == NULL) {
+	    krb5_set_error_string(context, "strdup: out of memory");
+	    free(*db);
+	    *db = NULL;
+	    return ENOMEM;
+	}
+    }
+
     (*db)->master_key_set = 0;
     (*db)->openp = 0;
     (*db)->open = LDAP_open;
--
Luke Howard | lukehoward.com
PADL Software | www.padl.com