xref: /freebsd/crypto/heimdal/lib/hdb/hdb-ldap.c (revision 5e9cd1ae3e10592ed70e7575551cba1bbab04d84)
15e9cd1aeSAssar Westerlund /*
25e9cd1aeSAssar Westerlund  * Copyright (c) 1999 - 2001, PADL Software Pty Ltd.
35e9cd1aeSAssar Westerlund  * All rights reserved.
45e9cd1aeSAssar Westerlund  *
55e9cd1aeSAssar Westerlund  * Redistribution and use in source and binary forms, with or without
65e9cd1aeSAssar Westerlund  * modification, are permitted provided that the following conditions
75e9cd1aeSAssar Westerlund  * are met:
85e9cd1aeSAssar Westerlund  *
95e9cd1aeSAssar Westerlund  * 1. Redistributions of source code must retain the above copyright
105e9cd1aeSAssar Westerlund  *    notice, this list of conditions and the following disclaimer.
115e9cd1aeSAssar Westerlund  *
125e9cd1aeSAssar Westerlund  * 2. Redistributions in binary form must reproduce the above copyright
135e9cd1aeSAssar Westerlund  *    notice, this list of conditions and the following disclaimer in the
145e9cd1aeSAssar Westerlund  *    documentation and/or other materials provided with the distribution.
155e9cd1aeSAssar Westerlund  *
165e9cd1aeSAssar Westerlund  * 3. Neither the name of PADL Software  nor the names of its contributors
175e9cd1aeSAssar Westerlund  *    may be used to endorse or promote products derived from this software
185e9cd1aeSAssar Westerlund  *    without specific prior written permission.
195e9cd1aeSAssar Westerlund  *
205e9cd1aeSAssar Westerlund  * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
215e9cd1aeSAssar Westerlund  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
225e9cd1aeSAssar Westerlund  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
235e9cd1aeSAssar Westerlund  * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
245e9cd1aeSAssar Westerlund  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
255e9cd1aeSAssar Westerlund  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
265e9cd1aeSAssar Westerlund  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
275e9cd1aeSAssar Westerlund  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
285e9cd1aeSAssar Westerlund  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
295e9cd1aeSAssar Westerlund  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
305e9cd1aeSAssar Westerlund  * SUCH DAMAGE.
315e9cd1aeSAssar Westerlund  */
325e9cd1aeSAssar Westerlund 
335e9cd1aeSAssar Westerlund #include "hdb_locl.h"
345e9cd1aeSAssar Westerlund 
355e9cd1aeSAssar Westerlund RCSID("$Id: hdb-ldap.c,v 1.7 2001/01/30 16:59:08 assar Exp $");
365e9cd1aeSAssar Westerlund 
375e9cd1aeSAssar Westerlund #ifdef OPENLDAP
385e9cd1aeSAssar Westerlund 
395e9cd1aeSAssar Westerlund #include <ldap.h>
405e9cd1aeSAssar Westerlund #include <lber.h>
415e9cd1aeSAssar Westerlund #include <ctype.h>
425e9cd1aeSAssar Westerlund #include <sys/un.h>
435e9cd1aeSAssar Westerlund 
445e9cd1aeSAssar Westerlund static krb5_error_code LDAP__connect(krb5_context context, HDB * db);
455e9cd1aeSAssar Westerlund 
465e9cd1aeSAssar Westerlund static krb5_error_code
475e9cd1aeSAssar Westerlund LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
485e9cd1aeSAssar Westerlund 		   hdb_entry * ent);
495e9cd1aeSAssar Westerlund 
505e9cd1aeSAssar Westerlund static char *krb5kdcentry_attrs[] =
515e9cd1aeSAssar Westerlund     { "krb5PrincipalName", "cn", "krb5PrincipalRealm",
525e9cd1aeSAssar Westerlund     "krb5KeyVersionNumber", "krb5Key",
535e9cd1aeSAssar Westerlund     "krb5ValidStart", "krb5ValidEnd", "krb5PasswordEnd",
545e9cd1aeSAssar Westerlund     "krb5MaxLife", "krb5MaxRenew", "krb5KDCFlags", "krb5EncryptionType",
555e9cd1aeSAssar Westerlund     "modifiersName", "modifyTimestamp", "creatorsName", "createTimestamp",
565e9cd1aeSAssar Westerlund     NULL
575e9cd1aeSAssar Westerlund };
585e9cd1aeSAssar Westerlund 
595e9cd1aeSAssar Westerlund static char *krb5principal_attrs[] =
605e9cd1aeSAssar Westerlund     { "krb5PrincipalName", "cn", "krb5PrincipalRealm",
615e9cd1aeSAssar Westerlund     "modifiersName", "modifyTimestamp", "creatorsName", "createTimestamp",
625e9cd1aeSAssar Westerlund     NULL
635e9cd1aeSAssar Westerlund };
645e9cd1aeSAssar Westerlund 
655e9cd1aeSAssar Westerlund /* based on samba: source/passdb/ldap.c */
665e9cd1aeSAssar Westerlund static krb5_error_code
675e9cd1aeSAssar Westerlund LDAP_addmod_len(LDAPMod *** modlist, int modop, const char *attribute,
685e9cd1aeSAssar Westerlund 		unsigned char *value, size_t len)
695e9cd1aeSAssar Westerlund {
705e9cd1aeSAssar Westerlund     LDAPMod **mods = *modlist;
715e9cd1aeSAssar Westerlund     int i, j;
725e9cd1aeSAssar Westerlund 
735e9cd1aeSAssar Westerlund     if (mods == NULL) {
745e9cd1aeSAssar Westerlund 	mods = (LDAPMod **) calloc(1, sizeof(LDAPMod *));
755e9cd1aeSAssar Westerlund 	if (mods == NULL) {
765e9cd1aeSAssar Westerlund 	    return ENOMEM;
775e9cd1aeSAssar Westerlund 	}
785e9cd1aeSAssar Westerlund 	mods[0] = NULL;
795e9cd1aeSAssar Westerlund     }
805e9cd1aeSAssar Westerlund 
815e9cd1aeSAssar Westerlund     for (i = 0; mods[i] != NULL; ++i) {
825e9cd1aeSAssar Westerlund 	if ((mods[i]->mod_op & (~LDAP_MOD_BVALUES)) == modop
835e9cd1aeSAssar Westerlund 	    && (!strcasecmp(mods[i]->mod_type, attribute))) {
845e9cd1aeSAssar Westerlund 	    break;
855e9cd1aeSAssar Westerlund 	}
865e9cd1aeSAssar Westerlund     }
875e9cd1aeSAssar Westerlund 
885e9cd1aeSAssar Westerlund     if (mods[i] == NULL) {
895e9cd1aeSAssar Westerlund 	mods = (LDAPMod **) realloc(mods, (i + 2) * sizeof(LDAPMod *));
905e9cd1aeSAssar Westerlund 	if (mods == NULL) {
915e9cd1aeSAssar Westerlund 	    return ENOMEM;
925e9cd1aeSAssar Westerlund 	}
935e9cd1aeSAssar Westerlund 	mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
945e9cd1aeSAssar Westerlund 	if (mods[i] == NULL) {
955e9cd1aeSAssar Westerlund 	    return ENOMEM;
965e9cd1aeSAssar Westerlund 	}
975e9cd1aeSAssar Westerlund 	mods[i]->mod_op = modop | LDAP_MOD_BVALUES;
985e9cd1aeSAssar Westerlund 	mods[i]->mod_bvalues = NULL;
995e9cd1aeSAssar Westerlund 	mods[i]->mod_type = strdup(attribute);
1005e9cd1aeSAssar Westerlund 	if (mods[i]->mod_type == NULL) {
1015e9cd1aeSAssar Westerlund 	    return ENOMEM;
1025e9cd1aeSAssar Westerlund 	}
1035e9cd1aeSAssar Westerlund 	mods[i + 1] = NULL;
1045e9cd1aeSAssar Westerlund     }
1055e9cd1aeSAssar Westerlund 
1065e9cd1aeSAssar Westerlund     if (value != NULL) {
1075e9cd1aeSAssar Westerlund 	j = 0;
1085e9cd1aeSAssar Westerlund 	if (mods[i]->mod_bvalues != NULL) {
1095e9cd1aeSAssar Westerlund 	    for (; mods[i]->mod_bvalues[j] != NULL; j++);
1105e9cd1aeSAssar Westerlund 	}
1115e9cd1aeSAssar Westerlund 	mods[i]->mod_bvalues =
1125e9cd1aeSAssar Westerlund 	    (struct berval **) realloc(mods[i]->mod_bvalues,
1135e9cd1aeSAssar Westerlund 				       (j + 2) * sizeof(struct berval *));
1145e9cd1aeSAssar Westerlund 	if (mods[i]->mod_bvalues == NULL) {
1155e9cd1aeSAssar Westerlund 	    return ENOMEM;
1165e9cd1aeSAssar Westerlund 	}
1175e9cd1aeSAssar Westerlund 	/* Caller allocates memory on our behalf, unlike LDAP_addmod. */
1185e9cd1aeSAssar Westerlund 	mods[i]->mod_bvalues[j] =
1195e9cd1aeSAssar Westerlund 	    (struct berval *) malloc(sizeof(struct berval));
1205e9cd1aeSAssar Westerlund 	if (mods[i]->mod_bvalues[j] == NULL) {
1215e9cd1aeSAssar Westerlund 	    return ENOMEM;
1225e9cd1aeSAssar Westerlund 	}
1235e9cd1aeSAssar Westerlund 	mods[i]->mod_bvalues[j]->bv_val = value;
1245e9cd1aeSAssar Westerlund 	mods[i]->mod_bvalues[j]->bv_len = len;
1255e9cd1aeSAssar Westerlund 	mods[i]->mod_bvalues[j + 1] = NULL;
1265e9cd1aeSAssar Westerlund     }
1275e9cd1aeSAssar Westerlund     *modlist = mods;
1285e9cd1aeSAssar Westerlund     return 0;
1295e9cd1aeSAssar Westerlund }
1305e9cd1aeSAssar Westerlund 
1315e9cd1aeSAssar Westerlund static krb5_error_code
1325e9cd1aeSAssar Westerlund LDAP_addmod(LDAPMod *** modlist, int modop, const char *attribute,
1335e9cd1aeSAssar Westerlund 	    const char *value)
1345e9cd1aeSAssar Westerlund {
1355e9cd1aeSAssar Westerlund     LDAPMod **mods = *modlist;
1365e9cd1aeSAssar Westerlund     int i, j;
1375e9cd1aeSAssar Westerlund 
1385e9cd1aeSAssar Westerlund     if (mods == NULL) {
1395e9cd1aeSAssar Westerlund 	mods = (LDAPMod **) calloc(1, sizeof(LDAPMod *));
1405e9cd1aeSAssar Westerlund 	if (mods == NULL) {
1415e9cd1aeSAssar Westerlund 	    return ENOMEM;
1425e9cd1aeSAssar Westerlund 	}
1435e9cd1aeSAssar Westerlund 	mods[0] = NULL;
1445e9cd1aeSAssar Westerlund     }
1455e9cd1aeSAssar Westerlund 
1465e9cd1aeSAssar Westerlund     for (i = 0; mods[i] != NULL; ++i) {
1475e9cd1aeSAssar Westerlund 	if (mods[i]->mod_op == modop
1485e9cd1aeSAssar Westerlund 	    && (!strcasecmp(mods[i]->mod_type, attribute))) {
1495e9cd1aeSAssar Westerlund 	    break;
1505e9cd1aeSAssar Westerlund 	}
1515e9cd1aeSAssar Westerlund     }
1525e9cd1aeSAssar Westerlund 
1535e9cd1aeSAssar Westerlund     if (mods[i] == NULL) {
1545e9cd1aeSAssar Westerlund 	mods = (LDAPMod **) realloc(mods, (i + 2) * sizeof(LDAPMod *));
1555e9cd1aeSAssar Westerlund 	if (mods == NULL) {
1565e9cd1aeSAssar Westerlund 	    return ENOMEM;
1575e9cd1aeSAssar Westerlund 	}
1585e9cd1aeSAssar Westerlund 	mods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));
1595e9cd1aeSAssar Westerlund 	if (mods[i] == NULL) {
1605e9cd1aeSAssar Westerlund 	    return ENOMEM;
1615e9cd1aeSAssar Westerlund 	}
1625e9cd1aeSAssar Westerlund 	mods[i]->mod_op = modop;
1635e9cd1aeSAssar Westerlund 	mods[i]->mod_values = NULL;
1645e9cd1aeSAssar Westerlund 	mods[i]->mod_type = strdup(attribute);
1655e9cd1aeSAssar Westerlund 	if (mods[i]->mod_type == NULL) {
1665e9cd1aeSAssar Westerlund 	    return ENOMEM;
1675e9cd1aeSAssar Westerlund 	}
1685e9cd1aeSAssar Westerlund 	mods[i + 1] = NULL;
1695e9cd1aeSAssar Westerlund     }
1705e9cd1aeSAssar Westerlund 
1715e9cd1aeSAssar Westerlund     if (value != NULL) {
1725e9cd1aeSAssar Westerlund 	j = 0;
1735e9cd1aeSAssar Westerlund 	if (mods[i]->mod_values != NULL) {
1745e9cd1aeSAssar Westerlund 	    for (; mods[i]->mod_values[j] != NULL; j++);
1755e9cd1aeSAssar Westerlund 	}
1765e9cd1aeSAssar Westerlund 	mods[i]->mod_values = (char **) realloc(mods[i]->mod_values,
1775e9cd1aeSAssar Westerlund 						(j + 2) * sizeof(char *));
1785e9cd1aeSAssar Westerlund 	if (mods[i]->mod_values == NULL) {
1795e9cd1aeSAssar Westerlund 	    return ENOMEM;
1805e9cd1aeSAssar Westerlund 	}
1815e9cd1aeSAssar Westerlund 	mods[i]->mod_values[j] = strdup(value);
1825e9cd1aeSAssar Westerlund 	if (mods[i]->mod_values[j] == NULL) {
1835e9cd1aeSAssar Westerlund 	    return ENOMEM;
1845e9cd1aeSAssar Westerlund 	}
1855e9cd1aeSAssar Westerlund 	mods[i]->mod_values[j + 1] = NULL;
1865e9cd1aeSAssar Westerlund     }
1875e9cd1aeSAssar Westerlund     *modlist = mods;
1885e9cd1aeSAssar Westerlund     return 0;
1895e9cd1aeSAssar Westerlund }
1905e9cd1aeSAssar Westerlund 
1915e9cd1aeSAssar Westerlund static krb5_error_code
1925e9cd1aeSAssar Westerlund LDAP_addmod_generalized_time(LDAPMod *** mods, int modop,
1935e9cd1aeSAssar Westerlund 			     const char *attribute, KerberosTime * time)
1945e9cd1aeSAssar Westerlund {
1955e9cd1aeSAssar Westerlund     char buf[22];
1965e9cd1aeSAssar Westerlund     struct tm *tm;
1975e9cd1aeSAssar Westerlund 
1985e9cd1aeSAssar Westerlund     /* XXX not threadsafe */
1995e9cd1aeSAssar Westerlund     tm = gmtime(time);
2005e9cd1aeSAssar Westerlund     strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", tm);
2015e9cd1aeSAssar Westerlund 
2025e9cd1aeSAssar Westerlund     return LDAP_addmod(mods, modop, attribute, buf);
2035e9cd1aeSAssar Westerlund }
2045e9cd1aeSAssar Westerlund 
2055e9cd1aeSAssar Westerlund static krb5_error_code
2065e9cd1aeSAssar Westerlund LDAP_get_string_value(HDB * db, LDAPMessage * entry,
2075e9cd1aeSAssar Westerlund 		      const char *attribute, char **ptr)
2085e9cd1aeSAssar Westerlund {
2095e9cd1aeSAssar Westerlund     char **vals;
2105e9cd1aeSAssar Westerlund     int ret;
2115e9cd1aeSAssar Westerlund 
2125e9cd1aeSAssar Westerlund     vals = ldap_get_values((LDAP *) db->db, entry, (char *) attribute);
2135e9cd1aeSAssar Westerlund     if (vals == NULL) {
2145e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
2155e9cd1aeSAssar Westerlund     }
2165e9cd1aeSAssar Westerlund     *ptr = strdup(vals[0]);
2175e9cd1aeSAssar Westerlund     if (*ptr == NULL) {
2185e9cd1aeSAssar Westerlund 	ret = ENOMEM;
2195e9cd1aeSAssar Westerlund     } else {
2205e9cd1aeSAssar Westerlund 	ret = 0;
2215e9cd1aeSAssar Westerlund     }
2225e9cd1aeSAssar Westerlund 
2235e9cd1aeSAssar Westerlund     ldap_value_free(vals);
2245e9cd1aeSAssar Westerlund 
2255e9cd1aeSAssar Westerlund     return ret;
2265e9cd1aeSAssar Westerlund }
2275e9cd1aeSAssar Westerlund 
2285e9cd1aeSAssar Westerlund static krb5_error_code
2295e9cd1aeSAssar Westerlund LDAP_get_integer_value(HDB * db, LDAPMessage * entry,
2305e9cd1aeSAssar Westerlund 		       const char *attribute, int *ptr)
2315e9cd1aeSAssar Westerlund {
2325e9cd1aeSAssar Westerlund     char **vals;
2335e9cd1aeSAssar Westerlund 
2345e9cd1aeSAssar Westerlund     vals = ldap_get_values((LDAP *) db->db, entry, (char *) attribute);
2355e9cd1aeSAssar Westerlund     if (vals == NULL) {
2365e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
2375e9cd1aeSAssar Westerlund     }
2385e9cd1aeSAssar Westerlund     *ptr = atoi(vals[0]);
2395e9cd1aeSAssar Westerlund     ldap_value_free(vals);
2405e9cd1aeSAssar Westerlund     return 0;
2415e9cd1aeSAssar Westerlund }
2425e9cd1aeSAssar Westerlund 
2435e9cd1aeSAssar Westerlund static krb5_error_code
2445e9cd1aeSAssar Westerlund LDAP_get_generalized_time_value(HDB * db, LDAPMessage * entry,
2455e9cd1aeSAssar Westerlund 				const char *attribute, KerberosTime * kt)
2465e9cd1aeSAssar Westerlund {
2475e9cd1aeSAssar Westerlund     char *tmp, *gentime;
2485e9cd1aeSAssar Westerlund     struct tm tm;
2495e9cd1aeSAssar Westerlund     int ret;
2505e9cd1aeSAssar Westerlund 
2515e9cd1aeSAssar Westerlund     *kt = 0;
2525e9cd1aeSAssar Westerlund 
2535e9cd1aeSAssar Westerlund     ret = LDAP_get_string_value(db, entry, attribute, &gentime);
2545e9cd1aeSAssar Westerlund     if (ret != 0) {
2555e9cd1aeSAssar Westerlund 	return ret;
2565e9cd1aeSAssar Westerlund     }
2575e9cd1aeSAssar Westerlund 
2585e9cd1aeSAssar Westerlund     tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm);
2595e9cd1aeSAssar Westerlund     if (tmp == NULL) {
2605e9cd1aeSAssar Westerlund 	free(gentime);
2615e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
2625e9cd1aeSAssar Westerlund     }
2635e9cd1aeSAssar Westerlund 
2645e9cd1aeSAssar Westerlund     free(gentime);
2655e9cd1aeSAssar Westerlund 
2665e9cd1aeSAssar Westerlund     *kt = timegm(&tm);
2675e9cd1aeSAssar Westerlund 
2685e9cd1aeSAssar Westerlund     return 0;
2695e9cd1aeSAssar Westerlund }
2705e9cd1aeSAssar Westerlund 
2715e9cd1aeSAssar Westerlund static krb5_error_code
2725e9cd1aeSAssar Westerlund LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry * ent,
2735e9cd1aeSAssar Westerlund 		LDAPMessage * msg, LDAPMod *** pmods)
2745e9cd1aeSAssar Westerlund {
2755e9cd1aeSAssar Westerlund     krb5_error_code ret;
2765e9cd1aeSAssar Westerlund     krb5_boolean is_new_entry;
2775e9cd1aeSAssar Westerlund     int rc, i;
2785e9cd1aeSAssar Westerlund     char *tmp = NULL;
2795e9cd1aeSAssar Westerlund     LDAPMod **mods = NULL;
2805e9cd1aeSAssar Westerlund     hdb_entry orig;
2815e9cd1aeSAssar Westerlund     unsigned long oflags, nflags;
2825e9cd1aeSAssar Westerlund 
2835e9cd1aeSAssar Westerlund     if (msg != NULL) {
2845e9cd1aeSAssar Westerlund 	ret = LDAP_message2entry(context, db, msg, &orig);
2855e9cd1aeSAssar Westerlund 	if (ret != 0) {
2865e9cd1aeSAssar Westerlund 	    goto out;
2875e9cd1aeSAssar Westerlund 	}
2885e9cd1aeSAssar Westerlund 	is_new_entry = FALSE;
2895e9cd1aeSAssar Westerlund     } else {
2905e9cd1aeSAssar Westerlund 	/* to make it perfectly obvious we're depending on
2915e9cd1aeSAssar Westerlund 	 * orig being intiialized to zero */
2925e9cd1aeSAssar Westerlund 	memset(&orig, 0, sizeof(orig));
2935e9cd1aeSAssar Westerlund 	is_new_entry = TRUE;
2945e9cd1aeSAssar Westerlund     }
2955e9cd1aeSAssar Westerlund 
2965e9cd1aeSAssar Westerlund     if (is_new_entry) {
2975e9cd1aeSAssar Westerlund 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "top");
2985e9cd1aeSAssar Westerlund 	if (ret != 0) {
2995e9cd1aeSAssar Westerlund 	    goto out;
3005e9cd1aeSAssar Westerlund 	}
3015e9cd1aeSAssar Westerlund 	/* person is the structural object class */
3025e9cd1aeSAssar Westerlund 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "person");
3035e9cd1aeSAssar Westerlund 	if (ret != 0) {
3045e9cd1aeSAssar Westerlund 	    goto out;
3055e9cd1aeSAssar Westerlund 	}
3065e9cd1aeSAssar Westerlund 	ret =
3075e9cd1aeSAssar Westerlund 	    LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass",
3085e9cd1aeSAssar Westerlund 			"krb5Principal");
3095e9cd1aeSAssar Westerlund 	if (ret != 0) {
3105e9cd1aeSAssar Westerlund 	    goto out;
3115e9cd1aeSAssar Westerlund 	}
3125e9cd1aeSAssar Westerlund 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass",
3135e9cd1aeSAssar Westerlund 			  "krb5KDCEntry");
3145e9cd1aeSAssar Westerlund 	if (ret != 0) {
3155e9cd1aeSAssar Westerlund 	    goto out;
3165e9cd1aeSAssar Westerlund 	}
3175e9cd1aeSAssar Westerlund     }
3185e9cd1aeSAssar Westerlund 
3195e9cd1aeSAssar Westerlund     if (is_new_entry ||
3205e9cd1aeSAssar Westerlund 	krb5_principal_compare(context, ent->principal, orig.principal) ==
3215e9cd1aeSAssar Westerlund 	FALSE) {
3225e9cd1aeSAssar Westerlund 	ret = krb5_unparse_name(context, ent->principal, &tmp);
3235e9cd1aeSAssar Westerlund 	if (ret != 0) {
3245e9cd1aeSAssar Westerlund 	    goto out;
3255e9cd1aeSAssar Westerlund 	}
3265e9cd1aeSAssar Westerlund 	ret =
3275e9cd1aeSAssar Westerlund 	    LDAP_addmod(&mods, LDAP_MOD_REPLACE, "krb5PrincipalName", tmp);
3285e9cd1aeSAssar Westerlund 	if (ret != 0) {
3295e9cd1aeSAssar Westerlund 	    free(tmp);
3305e9cd1aeSAssar Westerlund 	    goto out;
3315e9cd1aeSAssar Westerlund 	}
3325e9cd1aeSAssar Westerlund 	free(tmp);
3335e9cd1aeSAssar Westerlund     }
3345e9cd1aeSAssar Westerlund 
3355e9cd1aeSAssar Westerlund     if (ent->kvno != orig.kvno) {
3365e9cd1aeSAssar Westerlund 	rc = asprintf(&tmp, "%d", ent->kvno);
3375e9cd1aeSAssar Westerlund 	if (rc < 0) {
3385e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
3395e9cd1aeSAssar Westerlund 	    goto out;
3405e9cd1aeSAssar Westerlund 	}
3415e9cd1aeSAssar Westerlund 	ret =
3425e9cd1aeSAssar Westerlund 	    LDAP_addmod(&mods, LDAP_MOD_REPLACE, "krb5KeyVersionNumber",
3435e9cd1aeSAssar Westerlund 			tmp);
3445e9cd1aeSAssar Westerlund 	free(tmp);
3455e9cd1aeSAssar Westerlund 	if (ret != 0) {
3465e9cd1aeSAssar Westerlund 	    goto out;
3475e9cd1aeSAssar Westerlund 	}
3485e9cd1aeSAssar Westerlund     }
3495e9cd1aeSAssar Westerlund 
3505e9cd1aeSAssar Westerlund     if (ent->valid_start) {
3515e9cd1aeSAssar Westerlund 	if (orig.valid_end == NULL
3525e9cd1aeSAssar Westerlund 	    || (*(ent->valid_start) != *(orig.valid_start))) {
3535e9cd1aeSAssar Westerlund 	    ret =
3545e9cd1aeSAssar Westerlund 		LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
3555e9cd1aeSAssar Westerlund 					     "krb5ValidStart",
3565e9cd1aeSAssar Westerlund 					     ent->valid_start);
3575e9cd1aeSAssar Westerlund 	    if (ret != 0) {
3585e9cd1aeSAssar Westerlund 		goto out;
3595e9cd1aeSAssar Westerlund 	    }
3605e9cd1aeSAssar Westerlund 	}
3615e9cd1aeSAssar Westerlund     }
3625e9cd1aeSAssar Westerlund 
3635e9cd1aeSAssar Westerlund     if (ent->valid_end) {
3645e9cd1aeSAssar Westerlund 	if (orig.valid_end == NULL
3655e9cd1aeSAssar Westerlund 	    || (*(ent->valid_end) != *(orig.valid_end))) {
3665e9cd1aeSAssar Westerlund 	    ret =
3675e9cd1aeSAssar Westerlund 		LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
3685e9cd1aeSAssar Westerlund 					     "krb5ValidEnd",
3695e9cd1aeSAssar Westerlund 					     ent->valid_end);
3705e9cd1aeSAssar Westerlund 	    if (ret != 0) {
3715e9cd1aeSAssar Westerlund 		goto out;
3725e9cd1aeSAssar Westerlund 	    }
3735e9cd1aeSAssar Westerlund 	}
3745e9cd1aeSAssar Westerlund     }
3755e9cd1aeSAssar Westerlund 
3765e9cd1aeSAssar Westerlund     if (ent->pw_end) {
3775e9cd1aeSAssar Westerlund 	if (orig.pw_end == NULL || (*(ent->pw_end) != *(orig.pw_end))) {
3785e9cd1aeSAssar Westerlund 	    ret =
3795e9cd1aeSAssar Westerlund 		LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
3805e9cd1aeSAssar Westerlund 					     "krb5PasswordEnd",
3815e9cd1aeSAssar Westerlund 					     ent->pw_end);
3825e9cd1aeSAssar Westerlund 	    if (ret != 0) {
3835e9cd1aeSAssar Westerlund 		goto out;
3845e9cd1aeSAssar Westerlund 	    }
3855e9cd1aeSAssar Westerlund 	}
3865e9cd1aeSAssar Westerlund     }
3875e9cd1aeSAssar Westerlund 
3885e9cd1aeSAssar Westerlund     if (ent->max_life) {
3895e9cd1aeSAssar Westerlund 	if (orig.max_life == NULL
3905e9cd1aeSAssar Westerlund 	    || (*(ent->max_life) != *(orig.max_life))) {
3915e9cd1aeSAssar Westerlund 	    rc = asprintf(&tmp, "%d", *(ent->max_life));
3925e9cd1aeSAssar Westerlund 	    if (rc < 0) {
3935e9cd1aeSAssar Westerlund 		ret = ENOMEM;
3945e9cd1aeSAssar Westerlund 		goto out;
3955e9cd1aeSAssar Westerlund 	    }
3965e9cd1aeSAssar Westerlund 	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "krb5MaxLife", tmp);
3975e9cd1aeSAssar Westerlund 	    free(tmp);
3985e9cd1aeSAssar Westerlund 	    if (ret != 0) {
3995e9cd1aeSAssar Westerlund 		goto out;
4005e9cd1aeSAssar Westerlund 	    }
4015e9cd1aeSAssar Westerlund 	}
4025e9cd1aeSAssar Westerlund     }
4035e9cd1aeSAssar Westerlund 
4045e9cd1aeSAssar Westerlund     if (ent->max_renew) {
4055e9cd1aeSAssar Westerlund 	if (orig.max_renew == NULL
4065e9cd1aeSAssar Westerlund 	    || (*(ent->max_renew) != *(orig.max_renew))) {
4075e9cd1aeSAssar Westerlund 	    rc = asprintf(&tmp, "%d", *(ent->max_renew));
4085e9cd1aeSAssar Westerlund 	    if (rc < 0) {
4095e9cd1aeSAssar Westerlund 		ret = ENOMEM;
4105e9cd1aeSAssar Westerlund 		goto out;
4115e9cd1aeSAssar Westerlund 	    }
4125e9cd1aeSAssar Westerlund 	    ret =
4135e9cd1aeSAssar Westerlund 		LDAP_addmod(&mods, LDAP_MOD_REPLACE, "krb5MaxRenew", tmp);
4145e9cd1aeSAssar Westerlund 	    free(tmp);
4155e9cd1aeSAssar Westerlund 	    if (ret != 0) {
4165e9cd1aeSAssar Westerlund 		goto out;
4175e9cd1aeSAssar Westerlund 	    }
4185e9cd1aeSAssar Westerlund 	}
4195e9cd1aeSAssar Westerlund     }
4205e9cd1aeSAssar Westerlund 
4215e9cd1aeSAssar Westerlund     memset(&oflags, 0, sizeof(oflags));
4225e9cd1aeSAssar Westerlund     memcpy(&oflags, &orig.flags, sizeof(HDBFlags));
4235e9cd1aeSAssar Westerlund     memset(&nflags, 0, sizeof(nflags));
4245e9cd1aeSAssar Westerlund     memcpy(&nflags, &ent->flags, sizeof(HDBFlags));
4255e9cd1aeSAssar Westerlund 
4265e9cd1aeSAssar Westerlund     if (memcmp(&oflags, &nflags, sizeof(HDBFlags))) {
4275e9cd1aeSAssar Westerlund 	rc = asprintf(&tmp, "%lu", nflags);
4285e9cd1aeSAssar Westerlund 	if (rc < 0) {
4295e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
4305e9cd1aeSAssar Westerlund 	    goto out;
4315e9cd1aeSAssar Westerlund 	}
4325e9cd1aeSAssar Westerlund 	ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "krb5KDCFlags", tmp);
4335e9cd1aeSAssar Westerlund 	free(tmp);
4345e9cd1aeSAssar Westerlund 	if (ret != 0) {
4355e9cd1aeSAssar Westerlund 	    goto out;
4365e9cd1aeSAssar Westerlund 	}
4375e9cd1aeSAssar Westerlund     }
4385e9cd1aeSAssar Westerlund 
4395e9cd1aeSAssar Westerlund     if (is_new_entry == FALSE && orig.keys.len > 0) {
4405e9cd1aeSAssar Westerlund 	/* for the moment, clobber and replace keys. */
4415e9cd1aeSAssar Westerlund 	ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5Key", NULL);
4425e9cd1aeSAssar Westerlund 	if (ret != 0) {
4435e9cd1aeSAssar Westerlund 	    goto out;
4445e9cd1aeSAssar Westerlund 	}
4455e9cd1aeSAssar Westerlund     }
4465e9cd1aeSAssar Westerlund 
4475e9cd1aeSAssar Westerlund     for (i = 0; i < ent->keys.len; i++) {
4485e9cd1aeSAssar Westerlund 	unsigned char *buf;
4495e9cd1aeSAssar Westerlund 	size_t len;
4505e9cd1aeSAssar Westerlund 	Key new;
4515e9cd1aeSAssar Westerlund 
4525e9cd1aeSAssar Westerlund 	ret = copy_Key(&ent->keys.val[i], &new);
4535e9cd1aeSAssar Westerlund 	if (ret != 0) {
4545e9cd1aeSAssar Westerlund 	    goto out;
4555e9cd1aeSAssar Westerlund 	}
4565e9cd1aeSAssar Westerlund 
4575e9cd1aeSAssar Westerlund 	len = length_Key(&new);
4585e9cd1aeSAssar Westerlund 	buf = malloc(len);
4595e9cd1aeSAssar Westerlund 	if (buf == NULL) {
4605e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
4615e9cd1aeSAssar Westerlund 	    free_Key(&new);
4625e9cd1aeSAssar Westerlund 	    goto out;
4635e9cd1aeSAssar Westerlund 	}
4645e9cd1aeSAssar Westerlund 
4655e9cd1aeSAssar Westerlund 	ret = encode_Key(buf + len - 1, len, &new, &len);
4665e9cd1aeSAssar Westerlund 	if (ret != 0) {
4675e9cd1aeSAssar Westerlund 	    free(buf);
4685e9cd1aeSAssar Westerlund 	    free_Key(&new);
4695e9cd1aeSAssar Westerlund 	    goto out;
4705e9cd1aeSAssar Westerlund 	}
4715e9cd1aeSAssar Westerlund 	free_Key(&new);
4725e9cd1aeSAssar Westerlund 
4735e9cd1aeSAssar Westerlund 	/* addmod_len _owns_ the key, doesn't need to copy it */
4745e9cd1aeSAssar Westerlund 	ret = LDAP_addmod_len(&mods, LDAP_MOD_ADD, "krb5Key", buf, len);
4755e9cd1aeSAssar Westerlund 	if (ret != 0) {
4765e9cd1aeSAssar Westerlund 	    goto out;
4775e9cd1aeSAssar Westerlund 	}
4785e9cd1aeSAssar Westerlund     }
4795e9cd1aeSAssar Westerlund 
4805e9cd1aeSAssar Westerlund     if (ent->etypes) {
4815e9cd1aeSAssar Westerlund 	/* clobber and replace encryption types. */
4825e9cd1aeSAssar Westerlund 	if (is_new_entry == FALSE) {
4835e9cd1aeSAssar Westerlund 	    ret =
4845e9cd1aeSAssar Westerlund 		LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5EncryptionType",
4855e9cd1aeSAssar Westerlund 			    NULL);
4865e9cd1aeSAssar Westerlund 	}
4875e9cd1aeSAssar Westerlund 	for (i = 0; i < ent->etypes->len; i++) {
4885e9cd1aeSAssar Westerlund 	    rc = asprintf(&tmp, "%d", ent->etypes->val[i]);
4895e9cd1aeSAssar Westerlund 	    if (rc < 0) {
4905e9cd1aeSAssar Westerlund 		ret = ENOMEM;
4915e9cd1aeSAssar Westerlund 		goto out;
4925e9cd1aeSAssar Westerlund 	    }
4935e9cd1aeSAssar Westerlund 	    free(tmp);
4945e9cd1aeSAssar Westerlund 	    ret =
4955e9cd1aeSAssar Westerlund 		LDAP_addmod(&mods, LDAP_MOD_ADD, "krb5EncryptionType",
4965e9cd1aeSAssar Westerlund 			    tmp);
4975e9cd1aeSAssar Westerlund 	    if (ret != 0) {
4985e9cd1aeSAssar Westerlund 		goto out;
4995e9cd1aeSAssar Westerlund 	    }
5005e9cd1aeSAssar Westerlund 	}
5015e9cd1aeSAssar Westerlund     }
5025e9cd1aeSAssar Westerlund 
5035e9cd1aeSAssar Westerlund     /* for clarity */
5045e9cd1aeSAssar Westerlund     ret = 0;
5055e9cd1aeSAssar Westerlund 
5065e9cd1aeSAssar Westerlund   out:
5075e9cd1aeSAssar Westerlund 
5085e9cd1aeSAssar Westerlund     if (ret == 0) {
5095e9cd1aeSAssar Westerlund 	*pmods = mods;
5105e9cd1aeSAssar Westerlund     } else if (mods != NULL) {
5115e9cd1aeSAssar Westerlund 	ldap_mods_free(mods, 1);
5125e9cd1aeSAssar Westerlund 	*pmods = NULL;
5135e9cd1aeSAssar Westerlund     }
5145e9cd1aeSAssar Westerlund 
5155e9cd1aeSAssar Westerlund     if (msg != NULL) {
5165e9cd1aeSAssar Westerlund 	hdb_free_entry(context, &orig);
5175e9cd1aeSAssar Westerlund     }
5185e9cd1aeSAssar Westerlund 
5195e9cd1aeSAssar Westerlund     return ret;
5205e9cd1aeSAssar Westerlund }
5215e9cd1aeSAssar Westerlund 
5225e9cd1aeSAssar Westerlund static krb5_error_code
5235e9cd1aeSAssar Westerlund LDAP_dn2principal(krb5_context context, HDB * db, const char *dn,
5245e9cd1aeSAssar Westerlund 		  krb5_principal * principal)
5255e9cd1aeSAssar Westerlund {
5265e9cd1aeSAssar Westerlund     krb5_error_code ret;
5275e9cd1aeSAssar Westerlund     int rc;
5285e9cd1aeSAssar Westerlund     char **values;
5295e9cd1aeSAssar Westerlund     LDAPMessage *res = NULL, *e;
5305e9cd1aeSAssar Westerlund 
5315e9cd1aeSAssar Westerlund     rc = 1;
5325e9cd1aeSAssar Westerlund     (void) ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, &rc);
5335e9cd1aeSAssar Westerlund     rc = ldap_search_s((LDAP *) db->db, db->name, LDAP_SCOPE_BASE,
5345e9cd1aeSAssar Westerlund 		       "(objectclass=krb5Principal)", krb5principal_attrs,
5355e9cd1aeSAssar Westerlund 		       0, &res);
5365e9cd1aeSAssar Westerlund 
5375e9cd1aeSAssar Westerlund     if (rc != LDAP_SUCCESS) {
5385e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
5395e9cd1aeSAssar Westerlund 	goto out;
5405e9cd1aeSAssar Westerlund     }
5415e9cd1aeSAssar Westerlund 
5425e9cd1aeSAssar Westerlund     e = ldap_first_entry((LDAP *) db->db, res);
5435e9cd1aeSAssar Westerlund     if (e == NULL) {
5445e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
5455e9cd1aeSAssar Westerlund 	goto out;
5465e9cd1aeSAssar Westerlund     }
5475e9cd1aeSAssar Westerlund 
5485e9cd1aeSAssar Westerlund     values = ldap_get_values((LDAP *) db->db, e, "krb5PrincipalName");
5495e9cd1aeSAssar Westerlund     if (values == NULL) {
5505e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
5515e9cd1aeSAssar Westerlund 	goto out;
5525e9cd1aeSAssar Westerlund     }
5535e9cd1aeSAssar Westerlund 
5545e9cd1aeSAssar Westerlund     ret = krb5_parse_name(context, values[0], principal);
5555e9cd1aeSAssar Westerlund     ldap_value_free(values);
5565e9cd1aeSAssar Westerlund 
5575e9cd1aeSAssar Westerlund   out:
5585e9cd1aeSAssar Westerlund     if (res != NULL) {
5595e9cd1aeSAssar Westerlund 	ldap_msgfree(res);
5605e9cd1aeSAssar Westerlund     }
5615e9cd1aeSAssar Westerlund     return ret;
5625e9cd1aeSAssar Westerlund }
5635e9cd1aeSAssar Westerlund 
5645e9cd1aeSAssar Westerlund static krb5_error_code
5655e9cd1aeSAssar Westerlund LDAP__lookup_princ(krb5_context context, HDB * db, const char *princname,
5665e9cd1aeSAssar Westerlund 		   LDAPMessage ** msg)
5675e9cd1aeSAssar Westerlund {
5685e9cd1aeSAssar Westerlund     krb5_error_code ret;
5695e9cd1aeSAssar Westerlund     int rc;
5705e9cd1aeSAssar Westerlund     char *filter = NULL;
5715e9cd1aeSAssar Westerlund 
5725e9cd1aeSAssar Westerlund     (void) LDAP__connect(context, db);
5735e9cd1aeSAssar Westerlund 
5745e9cd1aeSAssar Westerlund     rc =
5755e9cd1aeSAssar Westerlund 	asprintf(&filter,
5765e9cd1aeSAssar Westerlund 		 "(&(objectclass=krb5KDCEntry)(krb5PrincipalName=%s))",
5775e9cd1aeSAssar Westerlund 		 princname);
5785e9cd1aeSAssar Westerlund     if (rc < 0) {
5795e9cd1aeSAssar Westerlund 	ret = ENOMEM;
5805e9cd1aeSAssar Westerlund 	goto out;
5815e9cd1aeSAssar Westerlund     }
5825e9cd1aeSAssar Westerlund 
5835e9cd1aeSAssar Westerlund     rc = 1;
5845e9cd1aeSAssar Westerlund     (void) ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, (void *) &rc);
5855e9cd1aeSAssar Westerlund 
5865e9cd1aeSAssar Westerlund     rc = ldap_search_s((LDAP *) db->db, db->name, LDAP_SCOPE_ONELEVEL, filter,
5875e9cd1aeSAssar Westerlund 		       krb5kdcentry_attrs, 0, msg);
5885e9cd1aeSAssar Westerlund     if (rc != LDAP_SUCCESS) {
5895e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
5905e9cd1aeSAssar Westerlund 	goto out;
5915e9cd1aeSAssar Westerlund     }
5925e9cd1aeSAssar Westerlund 
5935e9cd1aeSAssar Westerlund     ret = 0;
5945e9cd1aeSAssar Westerlund 
5955e9cd1aeSAssar Westerlund   out:
5965e9cd1aeSAssar Westerlund     if (filter != NULL) {
5975e9cd1aeSAssar Westerlund 	free(filter);
5985e9cd1aeSAssar Westerlund     }
5995e9cd1aeSAssar Westerlund     return ret;
6005e9cd1aeSAssar Westerlund }
6015e9cd1aeSAssar Westerlund 
6025e9cd1aeSAssar Westerlund static krb5_error_code
6035e9cd1aeSAssar Westerlund LDAP_principal2message(krb5_context context, HDB * db,
6045e9cd1aeSAssar Westerlund 		       krb5_principal princ, LDAPMessage ** msg)
6055e9cd1aeSAssar Westerlund {
6065e9cd1aeSAssar Westerlund     char *princname = NULL;
6075e9cd1aeSAssar Westerlund     krb5_error_code ret;
6085e9cd1aeSAssar Westerlund 
6095e9cd1aeSAssar Westerlund     ret = krb5_unparse_name(context, princ, &princname);
6105e9cd1aeSAssar Westerlund     if (ret != 0) {
6115e9cd1aeSAssar Westerlund 	return ret;
6125e9cd1aeSAssar Westerlund     }
6135e9cd1aeSAssar Westerlund 
6145e9cd1aeSAssar Westerlund     ret = LDAP__lookup_princ(context, db, princname, msg);
6155e9cd1aeSAssar Westerlund     free(princname);
6165e9cd1aeSAssar Westerlund 
6175e9cd1aeSAssar Westerlund     return ret;
6185e9cd1aeSAssar Westerlund }
6195e9cd1aeSAssar Westerlund 
6205e9cd1aeSAssar Westerlund /*
6215e9cd1aeSAssar Westerlund  * Construct an hdb_entry from a directory entry.
6225e9cd1aeSAssar Westerlund  */
6235e9cd1aeSAssar Westerlund static krb5_error_code
6245e9cd1aeSAssar Westerlund LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
6255e9cd1aeSAssar Westerlund 		   hdb_entry * ent)
6265e9cd1aeSAssar Westerlund {
6275e9cd1aeSAssar Westerlund     char *unparsed_name = NULL, *dn = NULL;
6285e9cd1aeSAssar Westerlund     int ret;
6295e9cd1aeSAssar Westerlund     unsigned long tmp;
6305e9cd1aeSAssar Westerlund     struct berval **keys;
6315e9cd1aeSAssar Westerlund     char **values;
6325e9cd1aeSAssar Westerlund 
6335e9cd1aeSAssar Westerlund     memset(ent, 0, sizeof(*ent));
6345e9cd1aeSAssar Westerlund     memset(&ent->flags, 0, sizeof(HDBFlags));
6355e9cd1aeSAssar Westerlund 
6365e9cd1aeSAssar Westerlund     ret =
6375e9cd1aeSAssar Westerlund 	LDAP_get_string_value(db, msg, "krb5PrincipalName",
6385e9cd1aeSAssar Westerlund 			      &unparsed_name);
6395e9cd1aeSAssar Westerlund     if (ret != 0) {
6405e9cd1aeSAssar Westerlund 	return ret;
6415e9cd1aeSAssar Westerlund     }
6425e9cd1aeSAssar Westerlund 
6435e9cd1aeSAssar Westerlund     ret = krb5_parse_name(context, unparsed_name, &ent->principal);
6445e9cd1aeSAssar Westerlund     if (ret != 0) {
6455e9cd1aeSAssar Westerlund 	goto out;
6465e9cd1aeSAssar Westerlund     }
6475e9cd1aeSAssar Westerlund 
6485e9cd1aeSAssar Westerlund     ret =
6495e9cd1aeSAssar Westerlund 	LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber",
6505e9cd1aeSAssar Westerlund 			       &ent->kvno);
6515e9cd1aeSAssar Westerlund     if (ret != 0) {
6525e9cd1aeSAssar Westerlund 	ent->kvno = 0;
6535e9cd1aeSAssar Westerlund     }
6545e9cd1aeSAssar Westerlund 
6555e9cd1aeSAssar Westerlund     keys = ldap_get_values_len((LDAP *) db->db, msg, "krb5Key");
6565e9cd1aeSAssar Westerlund     if (keys != NULL) {
6575e9cd1aeSAssar Westerlund 	int i;
6585e9cd1aeSAssar Westerlund 	size_t l;
6595e9cd1aeSAssar Westerlund 
6605e9cd1aeSAssar Westerlund 	ent->keys.len = ldap_count_values_len(keys);
6615e9cd1aeSAssar Westerlund 	ent->keys.val = (Key *) calloc(ent->keys.len, sizeof(Key));
6625e9cd1aeSAssar Westerlund 	for (i = 0; i < ent->keys.len; i++) {
6635e9cd1aeSAssar Westerlund 	    decode_Key((unsigned char *) keys[i]->bv_val,
6645e9cd1aeSAssar Westerlund 		       (size_t) keys[i]->bv_len, &ent->keys.val[i], &l);
6655e9cd1aeSAssar Westerlund 	}
6665e9cd1aeSAssar Westerlund 	ber_bvecfree(keys);
6675e9cd1aeSAssar Westerlund     } else {
6685e9cd1aeSAssar Westerlund #if 1
6695e9cd1aeSAssar Westerlund 	/*
6705e9cd1aeSAssar Westerlund 	 * This violates the ASN1 but it allows a principal to
6715e9cd1aeSAssar Westerlund 	 * be related to a general directory entry without creating
6725e9cd1aeSAssar Westerlund 	 * the keys. Hopefully it's OK.
6735e9cd1aeSAssar Westerlund 	 */
6745e9cd1aeSAssar Westerlund 	ent->keys.len = 0;
6755e9cd1aeSAssar Westerlund 	ent->keys.val = NULL;
6765e9cd1aeSAssar Westerlund #else
6775e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
6785e9cd1aeSAssar Westerlund 	goto out;
6795e9cd1aeSAssar Westerlund #endif
6805e9cd1aeSAssar Westerlund     }
6815e9cd1aeSAssar Westerlund 
6825e9cd1aeSAssar Westerlund     ret =
6835e9cd1aeSAssar Westerlund 	LDAP_get_generalized_time_value(db, msg, "createTimestamp",
6845e9cd1aeSAssar Westerlund 					&ent->created_by.time);
6855e9cd1aeSAssar Westerlund     if (ret != 0) {
6865e9cd1aeSAssar Westerlund 	ent->created_by.time = time(NULL);
6875e9cd1aeSAssar Westerlund     }
6885e9cd1aeSAssar Westerlund 
6895e9cd1aeSAssar Westerlund     ent->created_by.principal = NULL;
6905e9cd1aeSAssar Westerlund 
6915e9cd1aeSAssar Westerlund     ret = LDAP_get_string_value(db, msg, "creatorsName", &dn);
6925e9cd1aeSAssar Westerlund     if (ret == 0) {
6935e9cd1aeSAssar Westerlund 	if (LDAP_dn2principal(context, db, dn, &ent->created_by.principal)
6945e9cd1aeSAssar Westerlund 	    != 0) {
6955e9cd1aeSAssar Westerlund 	    ent->created_by.principal = NULL;
6965e9cd1aeSAssar Westerlund 	}
6975e9cd1aeSAssar Westerlund 	free(dn);
6985e9cd1aeSAssar Westerlund     }
6995e9cd1aeSAssar Westerlund 
7005e9cd1aeSAssar Westerlund     ent->modified_by = (Event *) malloc(sizeof(Event));
7015e9cd1aeSAssar Westerlund     if (ent->modified_by == NULL) {
7025e9cd1aeSAssar Westerlund 	ret = ENOMEM;
7035e9cd1aeSAssar Westerlund 	goto out;
7045e9cd1aeSAssar Westerlund     }
7055e9cd1aeSAssar Westerlund     ret =
7065e9cd1aeSAssar Westerlund 	LDAP_get_generalized_time_value(db, msg, "modifyTimestamp",
7075e9cd1aeSAssar Westerlund 					&ent->modified_by->time);
7085e9cd1aeSAssar Westerlund     if (ret == 0) {
7095e9cd1aeSAssar Westerlund 	ret = LDAP_get_string_value(db, msg, "modifiersName", &dn);
7105e9cd1aeSAssar Westerlund 	if (LDAP_dn2principal
7115e9cd1aeSAssar Westerlund 	    (context, db, dn, &ent->modified_by->principal) != 0) {
7125e9cd1aeSAssar Westerlund 	    ent->modified_by->principal = NULL;
7135e9cd1aeSAssar Westerlund 	}
7145e9cd1aeSAssar Westerlund 	free(dn);
7155e9cd1aeSAssar Westerlund     } else {
7165e9cd1aeSAssar Westerlund 	free(ent->modified_by);
7175e9cd1aeSAssar Westerlund 	ent->modified_by = NULL;
7185e9cd1aeSAssar Westerlund     }
7195e9cd1aeSAssar Westerlund 
7205e9cd1aeSAssar Westerlund     if ((ent->valid_start = (KerberosTime *) malloc(sizeof(KerberosTime)))
7215e9cd1aeSAssar Westerlund 	== NULL) {
7225e9cd1aeSAssar Westerlund 	ret = ENOMEM;
7235e9cd1aeSAssar Westerlund 	goto out;
7245e9cd1aeSAssar Westerlund     }
7255e9cd1aeSAssar Westerlund     ret =
7265e9cd1aeSAssar Westerlund 	LDAP_get_generalized_time_value(db, msg, "krb5ValidStart",
7275e9cd1aeSAssar Westerlund 					ent->valid_start);
7285e9cd1aeSAssar Westerlund     if (ret != 0) {
7295e9cd1aeSAssar Westerlund 	/* OPTIONAL */
7305e9cd1aeSAssar Westerlund 	free(ent->valid_start);
7315e9cd1aeSAssar Westerlund 	ent->valid_start = NULL;
7325e9cd1aeSAssar Westerlund     }
7335e9cd1aeSAssar Westerlund 
7345e9cd1aeSAssar Westerlund     if ((ent->valid_end = (KerberosTime *) malloc(sizeof(KerberosTime))) ==
7355e9cd1aeSAssar Westerlund 	NULL) {ret = ENOMEM;
7365e9cd1aeSAssar Westerlund 	goto out;
7375e9cd1aeSAssar Westerlund     }
7385e9cd1aeSAssar Westerlund     ret =
7395e9cd1aeSAssar Westerlund 	LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd",
7405e9cd1aeSAssar Westerlund 					ent->valid_end);
7415e9cd1aeSAssar Westerlund     if (ret != 0) {
7425e9cd1aeSAssar Westerlund 	/* OPTIONAL */
7435e9cd1aeSAssar Westerlund 	free(ent->valid_end);
7445e9cd1aeSAssar Westerlund 	ent->valid_end = NULL;
7455e9cd1aeSAssar Westerlund     }
7465e9cd1aeSAssar Westerlund 
7475e9cd1aeSAssar Westerlund     if ((ent->pw_end = (KerberosTime *) malloc(sizeof(KerberosTime))) ==
7485e9cd1aeSAssar Westerlund 	NULL) {ret = ENOMEM;
7495e9cd1aeSAssar Westerlund 	goto out;
7505e9cd1aeSAssar Westerlund     }
7515e9cd1aeSAssar Westerlund     ret =
7525e9cd1aeSAssar Westerlund 	LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd",
7535e9cd1aeSAssar Westerlund 					ent->pw_end);
7545e9cd1aeSAssar Westerlund     if (ret != 0) {
7555e9cd1aeSAssar Westerlund 	/* OPTIONAL */
7565e9cd1aeSAssar Westerlund 	free(ent->pw_end);
7575e9cd1aeSAssar Westerlund 	ent->pw_end = NULL;
7585e9cd1aeSAssar Westerlund     }
7595e9cd1aeSAssar Westerlund 
7605e9cd1aeSAssar Westerlund     ent->max_life = (int *) malloc(sizeof(int));
7615e9cd1aeSAssar Westerlund     if (ent->max_life == NULL) {
7625e9cd1aeSAssar Westerlund 	ret = ENOMEM;
7635e9cd1aeSAssar Westerlund 	goto out;
7645e9cd1aeSAssar Westerlund     }
7655e9cd1aeSAssar Westerlund     ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", ent->max_life);
7665e9cd1aeSAssar Westerlund     if (ret != 0) {
7675e9cd1aeSAssar Westerlund 	free(ent->max_life);
7685e9cd1aeSAssar Westerlund 	ent->max_life = NULL;
7695e9cd1aeSAssar Westerlund     }
7705e9cd1aeSAssar Westerlund 
7715e9cd1aeSAssar Westerlund     ent->max_renew = (int *) malloc(sizeof(int));
7725e9cd1aeSAssar Westerlund     if (ent->max_renew == NULL) {
7735e9cd1aeSAssar Westerlund 	ret = ENOMEM;
7745e9cd1aeSAssar Westerlund 	goto out;
7755e9cd1aeSAssar Westerlund     }
7765e9cd1aeSAssar Westerlund     ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", ent->max_renew);
7775e9cd1aeSAssar Westerlund     if (ret != 0) {
7785e9cd1aeSAssar Westerlund 	free(ent->max_renew);
7795e9cd1aeSAssar Westerlund 	ent->max_renew = NULL;
7805e9cd1aeSAssar Westerlund     }
7815e9cd1aeSAssar Westerlund 
7825e9cd1aeSAssar Westerlund     values = ldap_get_values((LDAP *) db->db, msg, "krb5KDCFlags");
7835e9cd1aeSAssar Westerlund     if (values != NULL) {
7845e9cd1aeSAssar Westerlund 	tmp = strtoul(values[0], (char **) NULL, 10);
7855e9cd1aeSAssar Westerlund 	if (tmp == ULONG_MAX && errno == ERANGE) {
7865e9cd1aeSAssar Westerlund 	    ret = ERANGE;
7875e9cd1aeSAssar Westerlund 	    goto out;
7885e9cd1aeSAssar Westerlund 	}
7895e9cd1aeSAssar Westerlund     } else {
7905e9cd1aeSAssar Westerlund 	tmp = 0;
7915e9cd1aeSAssar Westerlund     }
7925e9cd1aeSAssar Westerlund     memcpy(&ent->flags, &tmp, sizeof(HDBFlags));
7935e9cd1aeSAssar Westerlund 
7945e9cd1aeSAssar Westerlund     values = ldap_get_values((LDAP *) db->db, msg, "krb5EncryptionType");
7955e9cd1aeSAssar Westerlund     if (values != NULL) {
7965e9cd1aeSAssar Westerlund 	int i;
7975e9cd1aeSAssar Westerlund 
7985e9cd1aeSAssar Westerlund 	ent->etypes = malloc(sizeof(*(ent->etypes)));
7995e9cd1aeSAssar Westerlund 	if (ent->etypes == NULL) {
8005e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
8015e9cd1aeSAssar Westerlund 	    goto out;
8025e9cd1aeSAssar Westerlund 	}
8035e9cd1aeSAssar Westerlund 	ent->etypes->len = ldap_count_values(values);
8045e9cd1aeSAssar Westerlund 	ent->etypes->val = calloc(ent->etypes->len, sizeof(int));
8055e9cd1aeSAssar Westerlund 	for (i = 0; i < ent->etypes->len; i++) {
8065e9cd1aeSAssar Westerlund 	    ent->etypes->val[i] = atoi(values[i]);
8075e9cd1aeSAssar Westerlund 	}
8085e9cd1aeSAssar Westerlund 	ldap_value_free(values);
8095e9cd1aeSAssar Westerlund     }
8105e9cd1aeSAssar Westerlund 
8115e9cd1aeSAssar Westerlund     ret = 0;
8125e9cd1aeSAssar Westerlund 
8135e9cd1aeSAssar Westerlund   out:
8145e9cd1aeSAssar Westerlund     if (unparsed_name != NULL) {
8155e9cd1aeSAssar Westerlund 	free(unparsed_name);
8165e9cd1aeSAssar Westerlund     }
8175e9cd1aeSAssar Westerlund 
8185e9cd1aeSAssar Westerlund     if (ret != 0) {
8195e9cd1aeSAssar Westerlund 	/* I don't think this frees ent itself. */
8205e9cd1aeSAssar Westerlund 	hdb_free_entry(context, ent);
8215e9cd1aeSAssar Westerlund     }
8225e9cd1aeSAssar Westerlund 
8235e9cd1aeSAssar Westerlund     return ret;
8245e9cd1aeSAssar Westerlund }
8255e9cd1aeSAssar Westerlund 
8265e9cd1aeSAssar Westerlund static krb5_error_code LDAP_close(krb5_context context, HDB * db)
8275e9cd1aeSAssar Westerlund {
8285e9cd1aeSAssar Westerlund     LDAP *ld = (LDAP *) db->db;
8295e9cd1aeSAssar Westerlund 
8305e9cd1aeSAssar Westerlund     ldap_unbind(ld);
8315e9cd1aeSAssar Westerlund     db->db = NULL;
8325e9cd1aeSAssar Westerlund     return 0;
8335e9cd1aeSAssar Westerlund }
8345e9cd1aeSAssar Westerlund 
8355e9cd1aeSAssar Westerlund static krb5_error_code
8365e9cd1aeSAssar Westerlund LDAP_lock(krb5_context context, HDB * db, int operation)
8375e9cd1aeSAssar Westerlund {
8385e9cd1aeSAssar Westerlund     return 0;
8395e9cd1aeSAssar Westerlund }
8405e9cd1aeSAssar Westerlund 
8415e9cd1aeSAssar Westerlund static krb5_error_code LDAP_unlock(krb5_context context, HDB * db)
8425e9cd1aeSAssar Westerlund {
8435e9cd1aeSAssar Westerlund     return 0;
8445e9cd1aeSAssar Westerlund }
8455e9cd1aeSAssar Westerlund 
8465e9cd1aeSAssar Westerlund static krb5_error_code
8475e9cd1aeSAssar Westerlund LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry * entry)
8485e9cd1aeSAssar Westerlund {
8495e9cd1aeSAssar Westerlund     int msgid, rc, parserc;
8505e9cd1aeSAssar Westerlund     krb5_error_code ret;
8515e9cd1aeSAssar Westerlund     LDAPMessage *e;
8525e9cd1aeSAssar Westerlund 
8535e9cd1aeSAssar Westerlund     msgid = db->openp;		/* BOGUS OVERLOADING */
8545e9cd1aeSAssar Westerlund     if (msgid < 0) {
8555e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
8565e9cd1aeSAssar Westerlund     }
8575e9cd1aeSAssar Westerlund 
8585e9cd1aeSAssar Westerlund     do {
8595e9cd1aeSAssar Westerlund 	rc = ldap_result((LDAP *) db->db, msgid, LDAP_MSG_ONE, NULL, &e);
8605e9cd1aeSAssar Westerlund 	switch (rc) {
8615e9cd1aeSAssar Westerlund 	case LDAP_RES_SEARCH_ENTRY:
8625e9cd1aeSAssar Westerlund 	    /* We have an entry. Parse it. */
8635e9cd1aeSAssar Westerlund 	    ret = LDAP_message2entry(context, db, e, entry);
8645e9cd1aeSAssar Westerlund 	    ldap_msgfree(e);
8655e9cd1aeSAssar Westerlund 	    break;
8665e9cd1aeSAssar Westerlund 	case LDAP_RES_SEARCH_RESULT:
8675e9cd1aeSAssar Westerlund 	    /* We're probably at the end of the results. If not, abandon. */
8685e9cd1aeSAssar Westerlund 	    parserc =
8695e9cd1aeSAssar Westerlund 		ldap_parse_result((LDAP *) db->db, e, NULL, NULL, NULL,
8705e9cd1aeSAssar Westerlund 				  NULL, NULL, 1);
8715e9cd1aeSAssar Westerlund 	    if (parserc != LDAP_SUCCESS
8725e9cd1aeSAssar Westerlund 		&& parserc != LDAP_MORE_RESULTS_TO_RETURN) {
8735e9cd1aeSAssar Westerlund 		ldap_abandon((LDAP *) db->db, msgid);
8745e9cd1aeSAssar Westerlund 	    }
8755e9cd1aeSAssar Westerlund 	    ret = HDB_ERR_NOENTRY;
8765e9cd1aeSAssar Westerlund 	    db->openp = -1;
8775e9cd1aeSAssar Westerlund 	    break;
8785e9cd1aeSAssar Westerlund 	case 0:
8795e9cd1aeSAssar Westerlund 	case -1:
8805e9cd1aeSAssar Westerlund 	default:
8815e9cd1aeSAssar Westerlund 	    /* Some unspecified error (timeout?). Abandon. */
8825e9cd1aeSAssar Westerlund 	    ldap_msgfree(e);
8835e9cd1aeSAssar Westerlund 	    ldap_abandon((LDAP *) db->db, msgid);
8845e9cd1aeSAssar Westerlund 	    ret = HDB_ERR_NOENTRY;
8855e9cd1aeSAssar Westerlund 	    db->openp = -1;
8865e9cd1aeSAssar Westerlund 	    break;
8875e9cd1aeSAssar Westerlund 	}
8885e9cd1aeSAssar Westerlund     } while (rc == LDAP_RES_SEARCH_REFERENCE);
8895e9cd1aeSAssar Westerlund 
8905e9cd1aeSAssar Westerlund     if (ret == 0) {
8915e9cd1aeSAssar Westerlund 	if (db->master_key_set && (flags & HDB_F_DECRYPT)) {
8925e9cd1aeSAssar Westerlund 	    ret = hdb_unseal_keys(context, db, entry);
8935e9cd1aeSAssar Westerlund 	    if (ret)
8945e9cd1aeSAssar Westerlund 		hdb_free_entry(context,entry);
8955e9cd1aeSAssar Westerlund 	}
8965e9cd1aeSAssar Westerlund     }
8975e9cd1aeSAssar Westerlund 
8985e9cd1aeSAssar Westerlund     return ret;
8995e9cd1aeSAssar Westerlund }
9005e9cd1aeSAssar Westerlund 
9015e9cd1aeSAssar Westerlund static krb5_error_code
9025e9cd1aeSAssar Westerlund LDAP_firstkey(krb5_context context, HDB * db, unsigned flags,
9035e9cd1aeSAssar Westerlund 	      hdb_entry * entry)
9045e9cd1aeSAssar Westerlund {
9055e9cd1aeSAssar Westerlund     int msgid;
9065e9cd1aeSAssar Westerlund 
9075e9cd1aeSAssar Westerlund     (void) LDAP__connect(context, db);
9085e9cd1aeSAssar Westerlund 
9095e9cd1aeSAssar Westerlund     msgid = LDAP_NO_LIMIT;
9105e9cd1aeSAssar Westerlund     (void) ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, &msgid);
9115e9cd1aeSAssar Westerlund 
9125e9cd1aeSAssar Westerlund     msgid = ldap_search((LDAP *) db->db, db->name,
9135e9cd1aeSAssar Westerlund 			LDAP_SCOPE_ONELEVEL, "(objectclass=krb5KDCEntry)",
9145e9cd1aeSAssar Westerlund 			krb5kdcentry_attrs, 0);
9155e9cd1aeSAssar Westerlund     if (msgid < 0) {
9165e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
9175e9cd1aeSAssar Westerlund     }
9185e9cd1aeSAssar Westerlund 
9195e9cd1aeSAssar Westerlund     db->openp = msgid;
9205e9cd1aeSAssar Westerlund 
9215e9cd1aeSAssar Westerlund     return LDAP_seq(context, db, flags, entry);
9225e9cd1aeSAssar Westerlund }
9235e9cd1aeSAssar Westerlund 
9245e9cd1aeSAssar Westerlund static krb5_error_code
9255e9cd1aeSAssar Westerlund LDAP_nextkey(krb5_context context, HDB * db, unsigned flags,
9265e9cd1aeSAssar Westerlund 	     hdb_entry * entry)
9275e9cd1aeSAssar Westerlund {
9285e9cd1aeSAssar Westerlund     return LDAP_seq(context, db, flags, entry);
9295e9cd1aeSAssar Westerlund }
9305e9cd1aeSAssar Westerlund 
9315e9cd1aeSAssar Westerlund static krb5_error_code
9325e9cd1aeSAssar Westerlund LDAP_rename(krb5_context context, HDB * db, const char *new_name)
9335e9cd1aeSAssar Westerlund {
9345e9cd1aeSAssar Westerlund     return HDB_ERR_DB_INUSE;
9355e9cd1aeSAssar Westerlund }
9365e9cd1aeSAssar Westerlund 
9375e9cd1aeSAssar Westerlund static krb5_boolean LDAP__is_user_namingcontext(const char *ctx,
9385e9cd1aeSAssar Westerlund 						char *const *subschema)
9395e9cd1aeSAssar Westerlund {
9405e9cd1aeSAssar Westerlund     char *const *p;
9415e9cd1aeSAssar Westerlund 
9425e9cd1aeSAssar Westerlund     if (!strcasecmp(ctx, "CN=MONITOR")
9435e9cd1aeSAssar Westerlund 	|| !strcasecmp(ctx, "CN=CONFIG")) {
9445e9cd1aeSAssar Westerlund 	return FALSE;
9455e9cd1aeSAssar Westerlund     }
9465e9cd1aeSAssar Westerlund 
9475e9cd1aeSAssar Westerlund     if (subschema != NULL) {
9485e9cd1aeSAssar Westerlund 	for (p = subschema; *p != NULL; p++) {
9495e9cd1aeSAssar Westerlund 	    if (!strcasecmp(ctx, *p)) {
9505e9cd1aeSAssar Westerlund 		return FALSE;
9515e9cd1aeSAssar Westerlund 	    }
9525e9cd1aeSAssar Westerlund 	}
9535e9cd1aeSAssar Westerlund     }
9545e9cd1aeSAssar Westerlund 
9555e9cd1aeSAssar Westerlund     return TRUE;
9565e9cd1aeSAssar Westerlund }
9575e9cd1aeSAssar Westerlund 
9585e9cd1aeSAssar Westerlund static krb5_error_code LDAP__connect(krb5_context context, HDB * db)
9595e9cd1aeSAssar Westerlund {
9605e9cd1aeSAssar Westerlund     int rc;
9615e9cd1aeSAssar Westerlund     krb5_error_code ret;
9625e9cd1aeSAssar Westerlund     char *attrs[] = { "namingContexts", "subschemaSubentry", NULL };
9635e9cd1aeSAssar Westerlund     LDAPMessage *res = NULL, *e;
9645e9cd1aeSAssar Westerlund 
9655e9cd1aeSAssar Westerlund     if (db->db != NULL) {
9665e9cd1aeSAssar Westerlund 	/* connection has been opened. ping server. */
9675e9cd1aeSAssar Westerlund 	struct sockaddr_un addr;
9685e9cd1aeSAssar Westerlund 	socklen_t len;
9695e9cd1aeSAssar Westerlund 	int sd;
9705e9cd1aeSAssar Westerlund 
9715e9cd1aeSAssar Westerlund 	if (ldap_get_option((LDAP *) db->db, LDAP_OPT_DESC, &sd) == 0 &&
9725e9cd1aeSAssar Westerlund 	    getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
9735e9cd1aeSAssar Westerlund 	    /* the other end has died. reopen. */
9745e9cd1aeSAssar Westerlund 	    LDAP_close(context, db);
9755e9cd1aeSAssar Westerlund 	}
9765e9cd1aeSAssar Westerlund     }
9775e9cd1aeSAssar Westerlund 
9785e9cd1aeSAssar Westerlund     if (db->db != NULL) {
9795e9cd1aeSAssar Westerlund 	/* server is UP */
9805e9cd1aeSAssar Westerlund 	return 0;
9815e9cd1aeSAssar Westerlund     }
9825e9cd1aeSAssar Westerlund 
9835e9cd1aeSAssar Westerlund     rc = ldap_initialize((LDAP **) & db->db, "ldapi:///");
9845e9cd1aeSAssar Westerlund     if (rc != LDAP_SUCCESS) {
9855e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
9865e9cd1aeSAssar Westerlund     }
9875e9cd1aeSAssar Westerlund 
9885e9cd1aeSAssar Westerlund     rc = LDAP_VERSION3;
9895e9cd1aeSAssar Westerlund     (void) ldap_set_option((LDAP *) db->db, LDAP_OPT_PROTOCOL_VERSION, &rc);
9905e9cd1aeSAssar Westerlund 
9915e9cd1aeSAssar Westerlund     /* XXX set db->name to the search base */
9925e9cd1aeSAssar Westerlund     rc = ldap_search_s((LDAP *) db->db, "", LDAP_SCOPE_BASE,
9935e9cd1aeSAssar Westerlund 		       "(objectclass=*)", attrs, 0, &res);
9945e9cd1aeSAssar Westerlund     if (rc != LDAP_SUCCESS) {
9955e9cd1aeSAssar Westerlund 	ret = HDB_ERR_BADVERSION;
9965e9cd1aeSAssar Westerlund 	goto out;
9975e9cd1aeSAssar Westerlund     }
9985e9cd1aeSAssar Westerlund 
9995e9cd1aeSAssar Westerlund     e = ldap_first_entry((LDAP *) db->db, res);
10005e9cd1aeSAssar Westerlund     if (e == NULL) {
10015e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
10025e9cd1aeSAssar Westerlund 	goto out;
10035e9cd1aeSAssar Westerlund     }
10045e9cd1aeSAssar Westerlund 
10055e9cd1aeSAssar Westerlund     if (db->name == NULL) {
10065e9cd1aeSAssar Westerlund 	char **contexts = NULL, **schema_contexts, **p;
10075e9cd1aeSAssar Westerlund 
10085e9cd1aeSAssar Westerlund 	contexts = ldap_get_values((LDAP *) db->db, e, "namingContexts");
10095e9cd1aeSAssar Westerlund 	if (contexts == NULL) {
10105e9cd1aeSAssar Westerlund 	    ret = HDB_ERR_NOENTRY;
10115e9cd1aeSAssar Westerlund 	    goto out;
10125e9cd1aeSAssar Westerlund 	}
10135e9cd1aeSAssar Westerlund 
10145e9cd1aeSAssar Westerlund 	schema_contexts =
10155e9cd1aeSAssar Westerlund 	    ldap_get_values((LDAP *) db->db, e, "subschemaSubentry");
10165e9cd1aeSAssar Westerlund 
10175e9cd1aeSAssar Westerlund 	if (db->name != NULL) {
10185e9cd1aeSAssar Westerlund 	    free(db->name);
10195e9cd1aeSAssar Westerlund 	    db->name = NULL;
10205e9cd1aeSAssar Westerlund 	}
10215e9cd1aeSAssar Westerlund 
10225e9cd1aeSAssar Westerlund 	for (p = contexts; *p != NULL; p++) {
10235e9cd1aeSAssar Westerlund 	    if (LDAP__is_user_namingcontext(*p, schema_contexts)) {
10245e9cd1aeSAssar Westerlund 		break;
10255e9cd1aeSAssar Westerlund 	    }
10265e9cd1aeSAssar Westerlund 	}
10275e9cd1aeSAssar Westerlund 
10285e9cd1aeSAssar Westerlund 	db->name = strdup(*p);
10295e9cd1aeSAssar Westerlund 	if (db->name == NULL) {
10305e9cd1aeSAssar Westerlund 	    ldap_value_free(contexts);
10315e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
10325e9cd1aeSAssar Westerlund 	    goto out;
10335e9cd1aeSAssar Westerlund 	}
10345e9cd1aeSAssar Westerlund 
10355e9cd1aeSAssar Westerlund 	ldap_value_free(contexts);
10365e9cd1aeSAssar Westerlund 	if (schema_contexts != NULL) {
10375e9cd1aeSAssar Westerlund 	    ldap_value_free(schema_contexts);
10385e9cd1aeSAssar Westerlund 	}
10395e9cd1aeSAssar Westerlund     }
10405e9cd1aeSAssar Westerlund 
10415e9cd1aeSAssar Westerlund     ret = 0;
10425e9cd1aeSAssar Westerlund 
10435e9cd1aeSAssar Westerlund   out:
10445e9cd1aeSAssar Westerlund 
10455e9cd1aeSAssar Westerlund     if (res != NULL) {
10465e9cd1aeSAssar Westerlund 	ldap_msgfree(res);
10475e9cd1aeSAssar Westerlund     }
10485e9cd1aeSAssar Westerlund 
10495e9cd1aeSAssar Westerlund     if (ret != 0) {
10505e9cd1aeSAssar Westerlund 	if (db->db != NULL) {
10515e9cd1aeSAssar Westerlund 	    ldap_unbind((LDAP *) db->db);
10525e9cd1aeSAssar Westerlund 	    db->db = NULL;
10535e9cd1aeSAssar Westerlund 	}
10545e9cd1aeSAssar Westerlund     }
10555e9cd1aeSAssar Westerlund 
10565e9cd1aeSAssar Westerlund     return ret;
10575e9cd1aeSAssar Westerlund }
10585e9cd1aeSAssar Westerlund 
10595e9cd1aeSAssar Westerlund static krb5_error_code
10605e9cd1aeSAssar Westerlund LDAP_open(krb5_context context, HDB * db, int flags, mode_t mode)
10615e9cd1aeSAssar Westerlund {
10625e9cd1aeSAssar Westerlund     krb5_error_code ret;
10635e9cd1aeSAssar Westerlund 
10645e9cd1aeSAssar Westerlund     /* Not the right place for this. */
10655e9cd1aeSAssar Westerlund #ifdef HAVE_SIGACTION
10665e9cd1aeSAssar Westerlund     {
10675e9cd1aeSAssar Westerlund 	struct sigaction sa;
10685e9cd1aeSAssar Westerlund 
10695e9cd1aeSAssar Westerlund 	sa.sa_flags = 0;
10705e9cd1aeSAssar Westerlund 	sa.sa_handler = SIG_IGN;
10715e9cd1aeSAssar Westerlund 	sigemptyset(&sa.sa_mask);
10725e9cd1aeSAssar Westerlund 
10735e9cd1aeSAssar Westerlund 	sigaction(SIGPIPE, &sa, NULL);
10745e9cd1aeSAssar Westerlund     }
10755e9cd1aeSAssar Westerlund #else
10765e9cd1aeSAssar Westerlund     signal(SIGPIPE, SIG_IGN);
10775e9cd1aeSAssar Westerlund #endif
10785e9cd1aeSAssar Westerlund 
10795e9cd1aeSAssar Westerlund     if (db->name != NULL) {
10805e9cd1aeSAssar Westerlund 	free(db->name);
10815e9cd1aeSAssar Westerlund 	db->name = NULL;
10825e9cd1aeSAssar Westerlund     }
10835e9cd1aeSAssar Westerlund 
10845e9cd1aeSAssar Westerlund     ret = LDAP__connect(context, db);
10855e9cd1aeSAssar Westerlund     if (ret != 0) {
10865e9cd1aeSAssar Westerlund 	return ret;
10875e9cd1aeSAssar Westerlund     }
10885e9cd1aeSAssar Westerlund 
10895e9cd1aeSAssar Westerlund     return ret;
10905e9cd1aeSAssar Westerlund }
10915e9cd1aeSAssar Westerlund 
10925e9cd1aeSAssar Westerlund static krb5_error_code
10935e9cd1aeSAssar Westerlund LDAP_fetch(krb5_context context, HDB * db, unsigned flags,
10945e9cd1aeSAssar Westerlund 	   hdb_entry * entry)
10955e9cd1aeSAssar Westerlund {
10965e9cd1aeSAssar Westerlund     LDAPMessage *msg, *e;
10975e9cd1aeSAssar Westerlund     krb5_error_code ret;
10985e9cd1aeSAssar Westerlund 
10995e9cd1aeSAssar Westerlund     ret = LDAP_principal2message(context, db, entry->principal, &msg);
11005e9cd1aeSAssar Westerlund     if (ret != 0) {
11015e9cd1aeSAssar Westerlund 	return ret;
11025e9cd1aeSAssar Westerlund     }
11035e9cd1aeSAssar Westerlund 
11045e9cd1aeSAssar Westerlund     e = ldap_first_entry((LDAP *) db->db, msg);
11055e9cd1aeSAssar Westerlund     if (e == NULL) {
11065e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
11075e9cd1aeSAssar Westerlund 	goto out;
11085e9cd1aeSAssar Westerlund     }
11095e9cd1aeSAssar Westerlund 
11105e9cd1aeSAssar Westerlund     ret = LDAP_message2entry(context, db, e, entry);
11115e9cd1aeSAssar Westerlund     if (ret == 0) {
11125e9cd1aeSAssar Westerlund 	if (db->master_key_set && (flags & HDB_F_DECRYPT)) {
11135e9cd1aeSAssar Westerlund 	    ret = hdb_unseal_keys(context, db, entry);
11145e9cd1aeSAssar Westerlund 	    if (ret)
11155e9cd1aeSAssar Westerlund 		hdb_free_entry(context,entry);
11165e9cd1aeSAssar Westerlund 	}
11175e9cd1aeSAssar Westerlund     }
11185e9cd1aeSAssar Westerlund 
11195e9cd1aeSAssar Westerlund   out:
11205e9cd1aeSAssar Westerlund     ldap_msgfree(msg);
11215e9cd1aeSAssar Westerlund 
11225e9cd1aeSAssar Westerlund     return ret;
11235e9cd1aeSAssar Westerlund }
11245e9cd1aeSAssar Westerlund 
11255e9cd1aeSAssar Westerlund static krb5_error_code
11265e9cd1aeSAssar Westerlund LDAP_store(krb5_context context, HDB * db, unsigned flags,
11275e9cd1aeSAssar Westerlund 	   hdb_entry * entry)
11285e9cd1aeSAssar Westerlund {
11295e9cd1aeSAssar Westerlund     LDAPMod **mods = NULL;
11305e9cd1aeSAssar Westerlund     krb5_error_code ret;
11315e9cd1aeSAssar Westerlund     LDAPMessage *msg = NULL, *e = NULL;
11325e9cd1aeSAssar Westerlund     char *dn = NULL, *name = NULL;
11335e9cd1aeSAssar Westerlund 
11345e9cd1aeSAssar Westerlund     ret = krb5_unparse_name(context, entry->principal, &name);
11355e9cd1aeSAssar Westerlund     if (ret != 0) {
11365e9cd1aeSAssar Westerlund 	goto out;
11375e9cd1aeSAssar Westerlund     }
11385e9cd1aeSAssar Westerlund 
11395e9cd1aeSAssar Westerlund     ret = LDAP__lookup_princ(context, db, name, &msg);
11405e9cd1aeSAssar Westerlund     if (ret == 0) {
11415e9cd1aeSAssar Westerlund 	e = ldap_first_entry((LDAP *) db->db, msg);
11425e9cd1aeSAssar Westerlund     }
11435e9cd1aeSAssar Westerlund 
11445e9cd1aeSAssar Westerlund     ret = hdb_seal_keys(context, db, entry);
11455e9cd1aeSAssar Westerlund     if (ret)
11465e9cd1aeSAssar Westerlund 	goto out;
11475e9cd1aeSAssar Westerlund 
11485e9cd1aeSAssar Westerlund     /* turn new entry into LDAPMod array */
11495e9cd1aeSAssar Westerlund     ret = LDAP_entry2mods(context, db, entry, e, &mods);
11505e9cd1aeSAssar Westerlund     if (ret != 0) {
11515e9cd1aeSAssar Westerlund 	goto out;
11525e9cd1aeSAssar Westerlund     }
11535e9cd1aeSAssar Westerlund 
11545e9cd1aeSAssar Westerlund     if (e == NULL) {
11555e9cd1aeSAssar Westerlund 	/* Doesn't exist yet. */
11565e9cd1aeSAssar Westerlund 	char *p;
11575e9cd1aeSAssar Westerlund 
11585e9cd1aeSAssar Westerlund 	e = NULL;
11595e9cd1aeSAssar Westerlund 
11605e9cd1aeSAssar Westerlund 	/* normalize the naming attribute */
11615e9cd1aeSAssar Westerlund 	for (p = name; *p != '\0'; p++) {
11625e9cd1aeSAssar Westerlund 	    *p = (char) tolower((int) *p);
11635e9cd1aeSAssar Westerlund 	}
11645e9cd1aeSAssar Westerlund 
11655e9cd1aeSAssar Westerlund 	/*
11665e9cd1aeSAssar Westerlund 	 * We could do getpwnam() on the local component of
11675e9cd1aeSAssar Westerlund 	 * the principal to find cn/sn but that's probably
11685e9cd1aeSAssar Westerlund 	 * bad thing to do from inside a KDC. Better leave
11695e9cd1aeSAssar Westerlund 	 * it to management tools.
11705e9cd1aeSAssar Westerlund 	 */
11715e9cd1aeSAssar Westerlund 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "cn", name);
11725e9cd1aeSAssar Westerlund 	if (ret < 0) {
11735e9cd1aeSAssar Westerlund 	    goto out;
11745e9cd1aeSAssar Westerlund 	}
11755e9cd1aeSAssar Westerlund 
11765e9cd1aeSAssar Westerlund 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "sn", name);
11775e9cd1aeSAssar Westerlund 	if (ret < 0) {
11785e9cd1aeSAssar Westerlund 	    goto out;
11795e9cd1aeSAssar Westerlund 	}
11805e9cd1aeSAssar Westerlund 
11815e9cd1aeSAssar Westerlund 	ret = asprintf(&dn, "cn=%s,%s", name, db->name);
11825e9cd1aeSAssar Westerlund 	if (ret < 0) {
11835e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
11845e9cd1aeSAssar Westerlund 	    goto out;
11855e9cd1aeSAssar Westerlund 	}
11865e9cd1aeSAssar Westerlund     } else if (flags & HDB_F_REPLACE) {
11875e9cd1aeSAssar Westerlund 	/* Entry exists, and we're allowed to replace it. */
11885e9cd1aeSAssar Westerlund 	dn = ldap_get_dn((LDAP *) db->db, e);
11895e9cd1aeSAssar Westerlund     } else {
11905e9cd1aeSAssar Westerlund 	/* Entry exists, but we're not allowed to replace it. Bail. */
11915e9cd1aeSAssar Westerlund 	ret = HDB_ERR_EXISTS;
11925e9cd1aeSAssar Westerlund 	goto out;
11935e9cd1aeSAssar Westerlund     }
11945e9cd1aeSAssar Westerlund 
11955e9cd1aeSAssar Westerlund     /* write entry into directory */
11965e9cd1aeSAssar Westerlund     if (e == NULL) {
11975e9cd1aeSAssar Westerlund 	/* didn't exist before */
11985e9cd1aeSAssar Westerlund 	ret = ldap_add_s((LDAP *) db->db, dn, mods);
11995e9cd1aeSAssar Westerlund     } else {
12005e9cd1aeSAssar Westerlund 	/* already existed, send deltas only */
12015e9cd1aeSAssar Westerlund 	ret = ldap_modify_s((LDAP *) db->db, dn, mods);
12025e9cd1aeSAssar Westerlund     }
12035e9cd1aeSAssar Westerlund 
12045e9cd1aeSAssar Westerlund     if (ret == LDAP_SUCCESS) {
12055e9cd1aeSAssar Westerlund 	ret = 0;
12065e9cd1aeSAssar Westerlund     } else {
12075e9cd1aeSAssar Westerlund 	ret = HDB_ERR_CANT_LOCK_DB;
12085e9cd1aeSAssar Westerlund     }
12095e9cd1aeSAssar Westerlund 
12105e9cd1aeSAssar Westerlund   out:
12115e9cd1aeSAssar Westerlund     /* free stuff */
12125e9cd1aeSAssar Westerlund     if (dn != NULL) {
12135e9cd1aeSAssar Westerlund 	free(dn);
12145e9cd1aeSAssar Westerlund     }
12155e9cd1aeSAssar Westerlund 
12165e9cd1aeSAssar Westerlund     if (msg != NULL) {
12175e9cd1aeSAssar Westerlund 	ldap_msgfree(msg);
12185e9cd1aeSAssar Westerlund     }
12195e9cd1aeSAssar Westerlund 
12205e9cd1aeSAssar Westerlund     if (mods != NULL) {
12215e9cd1aeSAssar Westerlund 	ldap_mods_free(mods, 1);
12225e9cd1aeSAssar Westerlund     }
12235e9cd1aeSAssar Westerlund 
12245e9cd1aeSAssar Westerlund     if (name != NULL) {
12255e9cd1aeSAssar Westerlund 	free(name);
12265e9cd1aeSAssar Westerlund     }
12275e9cd1aeSAssar Westerlund 
12285e9cd1aeSAssar Westerlund     return ret;
12295e9cd1aeSAssar Westerlund }
12305e9cd1aeSAssar Westerlund 
12315e9cd1aeSAssar Westerlund static krb5_error_code
12325e9cd1aeSAssar Westerlund LDAP_remove(krb5_context context, HDB * db, hdb_entry * entry)
12335e9cd1aeSAssar Westerlund {
12345e9cd1aeSAssar Westerlund     krb5_error_code ret;
12355e9cd1aeSAssar Westerlund     LDAPMessage *msg, *e;
12365e9cd1aeSAssar Westerlund     char *dn = NULL;
12375e9cd1aeSAssar Westerlund 
12385e9cd1aeSAssar Westerlund     ret = LDAP_principal2message(context, db, entry->principal, &msg);
12395e9cd1aeSAssar Westerlund     if (ret != 0) {
12405e9cd1aeSAssar Westerlund 	goto out;
12415e9cd1aeSAssar Westerlund     }
12425e9cd1aeSAssar Westerlund 
12435e9cd1aeSAssar Westerlund     e = ldap_first_entry((LDAP *) db->db, msg);
12445e9cd1aeSAssar Westerlund     if (e == NULL) {
12455e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
12465e9cd1aeSAssar Westerlund 	goto out;
12475e9cd1aeSAssar Westerlund     }
12485e9cd1aeSAssar Westerlund 
12495e9cd1aeSAssar Westerlund     dn = ldap_get_dn((LDAP *) db->db, e);
12505e9cd1aeSAssar Westerlund     if (dn == NULL) {
12515e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
12525e9cd1aeSAssar Westerlund 	goto out;
12535e9cd1aeSAssar Westerlund     }
12545e9cd1aeSAssar Westerlund 
12555e9cd1aeSAssar Westerlund     ret = LDAP_NO_LIMIT;
12565e9cd1aeSAssar Westerlund     (void) ldap_set_option((LDAP *) db->db, LDAP_OPT_SIZELIMIT, &ret);
12575e9cd1aeSAssar Westerlund 
12585e9cd1aeSAssar Westerlund     ret = ldap_delete_s((LDAP *) db->db, dn);
12595e9cd1aeSAssar Westerlund     if (ret == LDAP_SUCCESS) {
12605e9cd1aeSAssar Westerlund 	ret = 0;
12615e9cd1aeSAssar Westerlund     } else {
12625e9cd1aeSAssar Westerlund 	ret = HDB_ERR_CANT_LOCK_DB;
12635e9cd1aeSAssar Westerlund     }
12645e9cd1aeSAssar Westerlund 
12655e9cd1aeSAssar Westerlund   out:
12665e9cd1aeSAssar Westerlund     if (dn != NULL) {
12675e9cd1aeSAssar Westerlund 	free(dn);
12685e9cd1aeSAssar Westerlund     }
12695e9cd1aeSAssar Westerlund 
12705e9cd1aeSAssar Westerlund     if (msg != NULL) {
12715e9cd1aeSAssar Westerlund 	ldap_msgfree(msg);
12725e9cd1aeSAssar Westerlund     }
12735e9cd1aeSAssar Westerlund 
12745e9cd1aeSAssar Westerlund     return ret;
12755e9cd1aeSAssar Westerlund }
12765e9cd1aeSAssar Westerlund 
12775e9cd1aeSAssar Westerlund static krb5_error_code
12785e9cd1aeSAssar Westerlund LDAP__get(krb5_context context, HDB * db, krb5_data key, krb5_data * reply)
12795e9cd1aeSAssar Westerlund {
12805e9cd1aeSAssar Westerlund     fprintf(stderr, "LDAP__get not implemented\n");
12815e9cd1aeSAssar Westerlund     abort();
12825e9cd1aeSAssar Westerlund     return 0;
12835e9cd1aeSAssar Westerlund }
12845e9cd1aeSAssar Westerlund 
12855e9cd1aeSAssar Westerlund static krb5_error_code
12865e9cd1aeSAssar Westerlund LDAP__put(krb5_context context, HDB * db, int replace,
12875e9cd1aeSAssar Westerlund 	  krb5_data key, krb5_data value)
12885e9cd1aeSAssar Westerlund {
12895e9cd1aeSAssar Westerlund     fprintf(stderr, "LDAP__put not implemented\n");
12905e9cd1aeSAssar Westerlund     abort();
12915e9cd1aeSAssar Westerlund     return 0;
12925e9cd1aeSAssar Westerlund }
12935e9cd1aeSAssar Westerlund 
12945e9cd1aeSAssar Westerlund static krb5_error_code
12955e9cd1aeSAssar Westerlund LDAP__del(krb5_context context, HDB * db, krb5_data key)
12965e9cd1aeSAssar Westerlund {
12975e9cd1aeSAssar Westerlund     fprintf(stderr, "LDAP__del not implemented\n");
12985e9cd1aeSAssar Westerlund     abort();
12995e9cd1aeSAssar Westerlund     return 0;
13005e9cd1aeSAssar Westerlund }
13015e9cd1aeSAssar Westerlund 
13025e9cd1aeSAssar Westerlund static krb5_error_code LDAP_destroy(krb5_context context, HDB * db)
13035e9cd1aeSAssar Westerlund {
13045e9cd1aeSAssar Westerlund     krb5_error_code ret;
13055e9cd1aeSAssar Westerlund 
13065e9cd1aeSAssar Westerlund     ret = hdb_clear_master_key(context, db);
13075e9cd1aeSAssar Westerlund     free(db->name);
13085e9cd1aeSAssar Westerlund     free(db);
13095e9cd1aeSAssar Westerlund 
13105e9cd1aeSAssar Westerlund     return ret;
13115e9cd1aeSAssar Westerlund }
13125e9cd1aeSAssar Westerlund 
13135e9cd1aeSAssar Westerlund krb5_error_code
13145e9cd1aeSAssar Westerlund hdb_ldap_create(krb5_context context, HDB ** db, const char *filename)
13155e9cd1aeSAssar Westerlund {
13165e9cd1aeSAssar Westerlund     *db = malloc(sizeof(**db));
13175e9cd1aeSAssar Westerlund     if (*db == NULL)
13185e9cd1aeSAssar Westerlund 	return ENOMEM;
13195e9cd1aeSAssar Westerlund 
13205e9cd1aeSAssar Westerlund     (*db)->db = NULL;
13215e9cd1aeSAssar Westerlund /*    (*db)->name = strdup(filename); */
13225e9cd1aeSAssar Westerlund     (*db)->name = NULL;
13235e9cd1aeSAssar Westerlund     (*db)->master_key_set = 0;
13245e9cd1aeSAssar Westerlund     (*db)->openp = 0;
13255e9cd1aeSAssar Westerlund     (*db)->open = LDAP_open;
13265e9cd1aeSAssar Westerlund     (*db)->close = LDAP_close;
13275e9cd1aeSAssar Westerlund     (*db)->fetch = LDAP_fetch;
13285e9cd1aeSAssar Westerlund     (*db)->store = LDAP_store;
13295e9cd1aeSAssar Westerlund     (*db)->remove = LDAP_remove;
13305e9cd1aeSAssar Westerlund     (*db)->firstkey = LDAP_firstkey;
13315e9cd1aeSAssar Westerlund     (*db)->nextkey = LDAP_nextkey;
13325e9cd1aeSAssar Westerlund     (*db)->lock = LDAP_lock;
13335e9cd1aeSAssar Westerlund     (*db)->unlock = LDAP_unlock;
13345e9cd1aeSAssar Westerlund     (*db)->rename = LDAP_rename;
13355e9cd1aeSAssar Westerlund     /* can we ditch these? */
13365e9cd1aeSAssar Westerlund     (*db)->_get = LDAP__get;
13375e9cd1aeSAssar Westerlund     (*db)->_put = LDAP__put;
13385e9cd1aeSAssar Westerlund     (*db)->_del = LDAP__del;
13395e9cd1aeSAssar Westerlund     (*db)->destroy = LDAP_destroy;
13405e9cd1aeSAssar Westerlund 
13415e9cd1aeSAssar Westerlund     return 0;
13425e9cd1aeSAssar Westerlund }
13435e9cd1aeSAssar Westerlund 
13445e9cd1aeSAssar Westerlund #endif				/* OPENLDAP */
1345