xref: /freebsd/crypto/heimdal/lib/hdb/hdb-ldap.c (revision a0d7d68a2dd818ce84e37e1ff20c8849cda6d853)
15e9cd1aeSAssar Westerlund /*
2c19800e8SDoug Rabson  * Copyright (c) 1999-2001, 2003, PADL Software Pty Ltd.
3c19800e8SDoug Rabson  * Copyright (c) 2004, Andrew Bartlett.
4ae771770SStanislav Sedov  * Copyright (c) 2003 - 2008, Kungliga Tekniska Högskolan.
55e9cd1aeSAssar Westerlund  * All rights reserved.
65e9cd1aeSAssar Westerlund  *
75e9cd1aeSAssar Westerlund  * Redistribution and use in source and binary forms, with or without
85e9cd1aeSAssar Westerlund  * modification, are permitted provided that the following conditions
95e9cd1aeSAssar Westerlund  * are met:
105e9cd1aeSAssar Westerlund  *
115e9cd1aeSAssar Westerlund  * 1. Redistributions of source code must retain the above copyright
125e9cd1aeSAssar Westerlund  *    notice, this list of conditions and the following disclaimer.
135e9cd1aeSAssar Westerlund  *
145e9cd1aeSAssar Westerlund  * 2. Redistributions in binary form must reproduce the above copyright
155e9cd1aeSAssar Westerlund  *    notice, this list of conditions and the following disclaimer in the
165e9cd1aeSAssar Westerlund  *    documentation and/or other materials provided with the distribution.
175e9cd1aeSAssar Westerlund  *
185e9cd1aeSAssar Westerlund  * 3. Neither the name of PADL Software  nor the names of its contributors
195e9cd1aeSAssar Westerlund  *    may be used to endorse or promote products derived from this software
205e9cd1aeSAssar Westerlund  *    without specific prior written permission.
215e9cd1aeSAssar Westerlund  *
225e9cd1aeSAssar Westerlund  * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
235e9cd1aeSAssar Westerlund  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
245e9cd1aeSAssar Westerlund  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
255e9cd1aeSAssar Westerlund  * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
265e9cd1aeSAssar Westerlund  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
275e9cd1aeSAssar Westerlund  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
285e9cd1aeSAssar Westerlund  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
295e9cd1aeSAssar Westerlund  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
305e9cd1aeSAssar Westerlund  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
315e9cd1aeSAssar Westerlund  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
325e9cd1aeSAssar Westerlund  * SUCH DAMAGE.
335e9cd1aeSAssar Westerlund  */
345e9cd1aeSAssar Westerlund 
355e9cd1aeSAssar Westerlund #include "hdb_locl.h"
365e9cd1aeSAssar Westerlund 
375e9cd1aeSAssar Westerlund #ifdef OPENLDAP
385e9cd1aeSAssar Westerlund 
395e9cd1aeSAssar Westerlund #include <lber.h>
40adb0ddaeSAssar Westerlund #include <ldap.h>
415e9cd1aeSAssar Westerlund #include <sys/un.h>
42c19800e8SDoug Rabson #include <hex.h>
435e9cd1aeSAssar Westerlund 
44c19800e8SDoug Rabson static krb5_error_code LDAP__connect(krb5_context context, HDB *);
45c19800e8SDoug Rabson static krb5_error_code LDAP_close(krb5_context context, HDB *);
465e9cd1aeSAssar Westerlund 
47*a0d7d68aSCy Schubert static krb5_error_code hdb_ldap_create(krb5_context context, HDB **, const char *);
48*a0d7d68aSCy Schubert static krb5_error_code hdb_ldapi_create(krb5_context context, HDB **, const char *);
49*a0d7d68aSCy Schubert 
505e9cd1aeSAssar Westerlund static krb5_error_code
515e9cd1aeSAssar Westerlund LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
52ae771770SStanislav Sedov 		   int flags, hdb_entry_ex * ent);
535e9cd1aeSAssar Westerlund 
54c19800e8SDoug Rabson static const char *default_structural_object = "account";
55c19800e8SDoug Rabson static char *structural_object;
56c19800e8SDoug Rabson static krb5_boolean samba_forwardable;
57c19800e8SDoug Rabson 
58c19800e8SDoug Rabson struct hdbldapdb {
59c19800e8SDoug Rabson     LDAP *h_lp;
60c19800e8SDoug Rabson     int   h_msgid;
61c19800e8SDoug Rabson     char *h_base;
62c19800e8SDoug Rabson     char *h_url;
63c19800e8SDoug Rabson     char *h_createbase;
64c19800e8SDoug Rabson };
65c19800e8SDoug Rabson 
66c19800e8SDoug Rabson #define HDB2LDAP(db) (((struct hdbldapdb *)(db)->hdb_db)->h_lp)
67c19800e8SDoug Rabson #define HDB2MSGID(db) (((struct hdbldapdb *)(db)->hdb_db)->h_msgid)
68c19800e8SDoug Rabson #define HDBSETMSGID(db,msgid) \
69c19800e8SDoug Rabson 	do { ((struct hdbldapdb *)(db)->hdb_db)->h_msgid = msgid; } while(0)
70c19800e8SDoug Rabson #define HDB2BASE(dn) (((struct hdbldapdb *)(db)->hdb_db)->h_base)
71c19800e8SDoug Rabson #define HDB2URL(dn) (((struct hdbldapdb *)(db)->hdb_db)->h_url)
72c19800e8SDoug Rabson #define HDB2CREATE(db) (((struct hdbldapdb *)(db)->hdb_db)->h_createbase)
73c19800e8SDoug Rabson 
74c19800e8SDoug Rabson /*
75c19800e8SDoug Rabson  *
76c19800e8SDoug Rabson  */
77c19800e8SDoug Rabson 
78c19800e8SDoug Rabson static char * krb5kdcentry_attrs[] = {
79c19800e8SDoug Rabson     "cn",
80c19800e8SDoug Rabson     "createTimestamp",
81c19800e8SDoug Rabson     "creatorsName",
82c19800e8SDoug Rabson     "krb5EncryptionType",
83c19800e8SDoug Rabson     "krb5KDCFlags",
84c19800e8SDoug Rabson     "krb5Key",
85c19800e8SDoug Rabson     "krb5KeyVersionNumber",
86c19800e8SDoug Rabson     "krb5MaxLife",
87c19800e8SDoug Rabson     "krb5MaxRenew",
88c19800e8SDoug Rabson     "krb5PasswordEnd",
89c19800e8SDoug Rabson     "krb5PrincipalName",
90c19800e8SDoug Rabson     "krb5PrincipalRealm",
91c19800e8SDoug Rabson     "krb5ValidEnd",
92c19800e8SDoug Rabson     "krb5ValidStart",
93c19800e8SDoug Rabson     "modifiersName",
94c19800e8SDoug Rabson     "modifyTimestamp",
95c19800e8SDoug Rabson     "objectClass",
96c19800e8SDoug Rabson     "sambaAcctFlags",
97c19800e8SDoug Rabson     "sambaKickoffTime",
98c19800e8SDoug Rabson     "sambaNTPassword",
99c19800e8SDoug Rabson     "sambaPwdLastSet",
100c19800e8SDoug Rabson     "sambaPwdMustChange",
101c19800e8SDoug Rabson     "uid",
1025e9cd1aeSAssar Westerlund     NULL
1035e9cd1aeSAssar Westerlund };
1045e9cd1aeSAssar Westerlund 
105c19800e8SDoug Rabson static char *krb5principal_attrs[] = {
106c19800e8SDoug Rabson     "cn",
107c19800e8SDoug Rabson     "createTimestamp",
108c19800e8SDoug Rabson     "creatorsName",
109c19800e8SDoug Rabson     "krb5PrincipalName",
110c19800e8SDoug Rabson     "krb5PrincipalRealm",
111c19800e8SDoug Rabson     "modifiersName",
112c19800e8SDoug Rabson     "modifyTimestamp",
113c19800e8SDoug Rabson     "objectClass",
114c19800e8SDoug Rabson     "uid",
1155e9cd1aeSAssar Westerlund     NULL
1165e9cd1aeSAssar Westerlund };
1175e9cd1aeSAssar Westerlund 
118c19800e8SDoug Rabson static int
119c19800e8SDoug Rabson LDAP_no_size_limit(krb5_context context, LDAP *lp)
120c19800e8SDoug Rabson {
121c19800e8SDoug Rabson     int ret, limit = LDAP_NO_LIMIT;
122c19800e8SDoug Rabson 
123c19800e8SDoug Rabson     ret = ldap_set_option(lp, LDAP_OPT_SIZELIMIT, (const void *)&limit);
124c19800e8SDoug Rabson     if (ret != LDAP_SUCCESS) {
125ae771770SStanislav Sedov 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
126ae771770SStanislav Sedov 			       "ldap_set_option: %s",
127c19800e8SDoug Rabson 			       ldap_err2string(ret));
128c19800e8SDoug Rabson 	return HDB_ERR_BADVERSION;
129c19800e8SDoug Rabson     }
130c19800e8SDoug Rabson     return 0;
131c19800e8SDoug Rabson }
132c19800e8SDoug Rabson 
133c19800e8SDoug Rabson static int
134c19800e8SDoug Rabson check_ldap(krb5_context context, HDB *db, int ret)
135c19800e8SDoug Rabson {
136c19800e8SDoug Rabson     switch (ret) {
137c19800e8SDoug Rabson     case LDAP_SUCCESS:
138c19800e8SDoug Rabson 	return 0;
139c19800e8SDoug Rabson     case LDAP_SERVER_DOWN:
140c19800e8SDoug Rabson 	LDAP_close(context, db);
141c19800e8SDoug Rabson 	return 1;
142c19800e8SDoug Rabson     default:
143c19800e8SDoug Rabson 	return 1;
144c19800e8SDoug Rabson     }
145c19800e8SDoug Rabson }
146c19800e8SDoug Rabson 
1475e9cd1aeSAssar Westerlund static krb5_error_code
1481c43270aSJacques Vidrine LDAP__setmod(LDAPMod *** modlist, int modop, const char *attribute,
1491c43270aSJacques Vidrine 	     int *pIndex)
1505e9cd1aeSAssar Westerlund {
1511c43270aSJacques Vidrine     int cMods;
1525e9cd1aeSAssar Westerlund 
1531c43270aSJacques Vidrine     if (*modlist == NULL) {
1541c43270aSJacques Vidrine 	*modlist = (LDAPMod **)ber_memcalloc(1, sizeof(LDAPMod *));
155c19800e8SDoug Rabson 	if (*modlist == NULL)
1565e9cd1aeSAssar Westerlund 	    return ENOMEM;
1575e9cd1aeSAssar Westerlund     }
1585e9cd1aeSAssar Westerlund 
1591c43270aSJacques Vidrine     for (cMods = 0; (*modlist)[cMods] != NULL; cMods++) {
1601c43270aSJacques Vidrine 	if ((*modlist)[cMods]->mod_op == modop &&
1611c43270aSJacques Vidrine 	    strcasecmp((*modlist)[cMods]->mod_type, attribute) == 0) {
1625e9cd1aeSAssar Westerlund 	    break;
1635e9cd1aeSAssar Westerlund 	}
1645e9cd1aeSAssar Westerlund     }
1655e9cd1aeSAssar Westerlund 
1661c43270aSJacques Vidrine     *pIndex = cMods;
1671c43270aSJacques Vidrine 
1681c43270aSJacques Vidrine     if ((*modlist)[cMods] == NULL) {
1691c43270aSJacques Vidrine 	LDAPMod *mod;
1701c43270aSJacques Vidrine 
1711c43270aSJacques Vidrine 	*modlist = (LDAPMod **)ber_memrealloc(*modlist,
1721c43270aSJacques Vidrine 					      (cMods + 2) * sizeof(LDAPMod *));
173c19800e8SDoug Rabson 	if (*modlist == NULL)
1745e9cd1aeSAssar Westerlund 	    return ENOMEM;
175c19800e8SDoug Rabson 
1761c43270aSJacques Vidrine 	(*modlist)[cMods] = (LDAPMod *)ber_memalloc(sizeof(LDAPMod));
177c19800e8SDoug Rabson 	if ((*modlist)[cMods] == NULL)
1785e9cd1aeSAssar Westerlund 	    return ENOMEM;
1791c43270aSJacques Vidrine 
1801c43270aSJacques Vidrine 	mod = (*modlist)[cMods];
1811c43270aSJacques Vidrine 	mod->mod_op = modop;
1821c43270aSJacques Vidrine 	mod->mod_type = ber_strdup(attribute);
1831c43270aSJacques Vidrine 	if (mod->mod_type == NULL) {
1841c43270aSJacques Vidrine 	    ber_memfree(mod);
1851c43270aSJacques Vidrine 	    (*modlist)[cMods] = NULL;
1865e9cd1aeSAssar Westerlund 	    return ENOMEM;
1875e9cd1aeSAssar Westerlund 	}
1881c43270aSJacques Vidrine 
1891c43270aSJacques Vidrine 	if (modop & LDAP_MOD_BVALUES) {
1901c43270aSJacques Vidrine 	    mod->mod_bvalues = NULL;
1911c43270aSJacques Vidrine 	} else {
1921c43270aSJacques Vidrine 	    mod->mod_values = NULL;
1931c43270aSJacques Vidrine 	}
1941c43270aSJacques Vidrine 
1951c43270aSJacques Vidrine 	(*modlist)[cMods + 1] = NULL;
1961c43270aSJacques Vidrine     }
1971c43270aSJacques Vidrine 
1981c43270aSJacques Vidrine     return 0;
1991c43270aSJacques Vidrine }
2001c43270aSJacques Vidrine 
2011c43270aSJacques Vidrine static krb5_error_code
2021c43270aSJacques Vidrine LDAP_addmod_len(LDAPMod *** modlist, int modop, const char *attribute,
2031c43270aSJacques Vidrine 		unsigned char *value, size_t len)
2041c43270aSJacques Vidrine {
2051c43270aSJacques Vidrine     krb5_error_code ret;
206c19800e8SDoug Rabson     int cMods, i = 0;
2071c43270aSJacques Vidrine 
2081c43270aSJacques Vidrine     ret = LDAP__setmod(modlist, modop | LDAP_MOD_BVALUES, attribute, &cMods);
209c19800e8SDoug Rabson     if (ret)
2101c43270aSJacques Vidrine 	return ret;
2115e9cd1aeSAssar Westerlund 
2125e9cd1aeSAssar Westerlund     if (value != NULL) {
213c19800e8SDoug Rabson 	struct berval **bv;
2141c43270aSJacques Vidrine 
215c19800e8SDoug Rabson 	bv = (*modlist)[cMods]->mod_bvalues;
216c19800e8SDoug Rabson 	if (bv != NULL) {
217c19800e8SDoug Rabson 	    for (i = 0; bv[i] != NULL; i++)
2181c43270aSJacques Vidrine 		;
219c19800e8SDoug Rabson 	    bv = ber_memrealloc(bv, (i + 2) * sizeof(*bv));
220c19800e8SDoug Rabson 	} else
221c19800e8SDoug Rabson 	    bv = ber_memalloc(2 * sizeof(*bv));
222c19800e8SDoug Rabson 	if (bv == NULL)
2235e9cd1aeSAssar Westerlund 	    return ENOMEM;
224c19800e8SDoug Rabson 
225c19800e8SDoug Rabson 	(*modlist)[cMods]->mod_bvalues = bv;
226c19800e8SDoug Rabson 
227ae771770SStanislav Sedov 	bv[i] = ber_memalloc(sizeof(**bv));;
228c19800e8SDoug Rabson 	if (bv[i] == NULL)
2295e9cd1aeSAssar Westerlund 	    return ENOMEM;
2301c43270aSJacques Vidrine 
231c19800e8SDoug Rabson 	bv[i]->bv_val = (void *)value;
232c19800e8SDoug Rabson 	bv[i]->bv_len = len;
2331c43270aSJacques Vidrine 
234c19800e8SDoug Rabson 	bv[i + 1] = NULL;
2355e9cd1aeSAssar Westerlund     }
2361c43270aSJacques Vidrine 
2375e9cd1aeSAssar Westerlund     return 0;
2385e9cd1aeSAssar Westerlund }
2395e9cd1aeSAssar Westerlund 
2405e9cd1aeSAssar Westerlund static krb5_error_code
2415e9cd1aeSAssar Westerlund LDAP_addmod(LDAPMod *** modlist, int modop, const char *attribute,
2425e9cd1aeSAssar Westerlund 	    const char *value)
2435e9cd1aeSAssar Westerlund {
244c19800e8SDoug Rabson     int cMods, i = 0;
2451c43270aSJacques Vidrine     krb5_error_code ret;
2465e9cd1aeSAssar Westerlund 
2471c43270aSJacques Vidrine     ret = LDAP__setmod(modlist, modop, attribute, &cMods);
248c19800e8SDoug Rabson     if (ret)
2491c43270aSJacques Vidrine 	return ret;
2505e9cd1aeSAssar Westerlund 
2515e9cd1aeSAssar Westerlund     if (value != NULL) {
252c19800e8SDoug Rabson 	char **bv;
2531c43270aSJacques Vidrine 
254c19800e8SDoug Rabson 	bv = (*modlist)[cMods]->mod_values;
255c19800e8SDoug Rabson 	if (bv != NULL) {
256c19800e8SDoug Rabson 	    for (i = 0; bv[i] != NULL; i++)
2571c43270aSJacques Vidrine 		;
258c19800e8SDoug Rabson 	    bv = ber_memrealloc(bv, (i + 2) * sizeof(*bv));
259c19800e8SDoug Rabson 	} else
260c19800e8SDoug Rabson 	    bv = ber_memalloc(2 * sizeof(*bv));
261c19800e8SDoug Rabson 	if (bv == NULL)
2625e9cd1aeSAssar Westerlund 	    return ENOMEM;
263c19800e8SDoug Rabson 
264c19800e8SDoug Rabson 	(*modlist)[cMods]->mod_values = bv;
265c19800e8SDoug Rabson 
266c19800e8SDoug Rabson 	bv[i] = ber_strdup(value);
267c19800e8SDoug Rabson 	if (bv[i] == NULL)
2685e9cd1aeSAssar Westerlund 	    return ENOMEM;
269c19800e8SDoug Rabson 
270c19800e8SDoug Rabson 	bv[i + 1] = NULL;
2715e9cd1aeSAssar Westerlund     }
2721c43270aSJacques Vidrine 
2735e9cd1aeSAssar Westerlund     return 0;
2745e9cd1aeSAssar Westerlund }
2755e9cd1aeSAssar Westerlund 
2765e9cd1aeSAssar Westerlund static krb5_error_code
2775e9cd1aeSAssar Westerlund LDAP_addmod_generalized_time(LDAPMod *** mods, int modop,
2785e9cd1aeSAssar Westerlund 			     const char *attribute, KerberosTime * time)
2795e9cd1aeSAssar Westerlund {
2805e9cd1aeSAssar Westerlund     char buf[22];
2815e9cd1aeSAssar Westerlund     struct tm *tm;
2825e9cd1aeSAssar Westerlund 
2835e9cd1aeSAssar Westerlund     /* XXX not threadsafe */
2845e9cd1aeSAssar Westerlund     tm = gmtime(time);
2855e9cd1aeSAssar Westerlund     strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", tm);
2865e9cd1aeSAssar Westerlund 
2875e9cd1aeSAssar Westerlund     return LDAP_addmod(mods, modop, attribute, buf);
2885e9cd1aeSAssar Westerlund }
2895e9cd1aeSAssar Westerlund 
2905e9cd1aeSAssar Westerlund static krb5_error_code
291c19800e8SDoug Rabson LDAP_addmod_integer(krb5_context context,
292c19800e8SDoug Rabson 		    LDAPMod *** mods, int modop,
293c19800e8SDoug Rabson 		    const char *attribute, unsigned long l)
294c19800e8SDoug Rabson {
295c19800e8SDoug Rabson     krb5_error_code ret;
296c19800e8SDoug Rabson     char *buf;
297c19800e8SDoug Rabson 
298c19800e8SDoug Rabson     ret = asprintf(&buf, "%ld", l);
299c19800e8SDoug Rabson     if (ret < 0) {
300ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
301ae771770SStanislav Sedov 			       "asprintf: out of memory:");
302ae771770SStanislav Sedov 	return ENOMEM;
303c19800e8SDoug Rabson     }
304c19800e8SDoug Rabson     ret = LDAP_addmod(mods, modop, attribute, buf);
305c19800e8SDoug Rabson     free (buf);
306c19800e8SDoug Rabson     return ret;
307c19800e8SDoug Rabson }
308c19800e8SDoug Rabson 
309c19800e8SDoug Rabson static krb5_error_code
3105e9cd1aeSAssar Westerlund LDAP_get_string_value(HDB * db, LDAPMessage * entry,
3115e9cd1aeSAssar Westerlund 		      const char *attribute, char **ptr)
3125e9cd1aeSAssar Westerlund {
313ae771770SStanislav Sedov     struct berval **vals;
3145e9cd1aeSAssar Westerlund 
315ae771770SStanislav Sedov     vals = ldap_get_values_len(HDB2LDAP(db), entry, attribute);
316ae771770SStanislav Sedov     if (vals == NULL || vals[0] == NULL) {
317c19800e8SDoug Rabson 	*ptr = NULL;
3185e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
3195e9cd1aeSAssar Westerlund     }
320c19800e8SDoug Rabson 
321ae771770SStanislav Sedov     *ptr = malloc(vals[0]->bv_len + 1);
322ae771770SStanislav Sedov     if (*ptr == NULL) {
323ae771770SStanislav Sedov 	ldap_value_free_len(vals);
324ae771770SStanislav Sedov 	return ENOMEM;
325ae771770SStanislav Sedov     }
3265e9cd1aeSAssar Westerlund 
327ae771770SStanislav Sedov     memcpy(*ptr, vals[0]->bv_val, vals[0]->bv_len);
328ae771770SStanislav Sedov     (*ptr)[vals[0]->bv_len] = 0;
3295e9cd1aeSAssar Westerlund 
330ae771770SStanislav Sedov     ldap_value_free_len(vals);
331ae771770SStanislav Sedov 
332ae771770SStanislav Sedov     return 0;
3335e9cd1aeSAssar Westerlund }
3345e9cd1aeSAssar Westerlund 
3355e9cd1aeSAssar Westerlund static krb5_error_code
3365e9cd1aeSAssar Westerlund LDAP_get_integer_value(HDB * db, LDAPMessage * entry,
3375e9cd1aeSAssar Westerlund 		       const char *attribute, int *ptr)
3385e9cd1aeSAssar Westerlund {
339ae771770SStanislav Sedov     krb5_error_code ret;
340ae771770SStanislav Sedov     char *val;
3415e9cd1aeSAssar Westerlund 
342ae771770SStanislav Sedov     ret = LDAP_get_string_value(db, entry, attribute, &val);
343ae771770SStanislav Sedov     if (ret)
344ae771770SStanislav Sedov 	return ret;
345ae771770SStanislav Sedov     *ptr = atoi(val);
346ae771770SStanislav Sedov     free(val);
3475e9cd1aeSAssar Westerlund     return 0;
3485e9cd1aeSAssar Westerlund }
3495e9cd1aeSAssar Westerlund 
3505e9cd1aeSAssar Westerlund static krb5_error_code
3515e9cd1aeSAssar Westerlund LDAP_get_generalized_time_value(HDB * db, LDAPMessage * entry,
3525e9cd1aeSAssar Westerlund 				const char *attribute, KerberosTime * kt)
3535e9cd1aeSAssar Westerlund {
3545e9cd1aeSAssar Westerlund     char *tmp, *gentime;
3555e9cd1aeSAssar Westerlund     struct tm tm;
3565e9cd1aeSAssar Westerlund     int ret;
3575e9cd1aeSAssar Westerlund 
3585e9cd1aeSAssar Westerlund     *kt = 0;
3595e9cd1aeSAssar Westerlund 
3605e9cd1aeSAssar Westerlund     ret = LDAP_get_string_value(db, entry, attribute, &gentime);
361c19800e8SDoug Rabson     if (ret)
3625e9cd1aeSAssar Westerlund 	return ret;
3635e9cd1aeSAssar Westerlund 
3645e9cd1aeSAssar Westerlund     tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm);
3655e9cd1aeSAssar Westerlund     if (tmp == NULL) {
3665e9cd1aeSAssar Westerlund 	free(gentime);
3675e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
3685e9cd1aeSAssar Westerlund     }
3695e9cd1aeSAssar Westerlund 
3705e9cd1aeSAssar Westerlund     free(gentime);
3715e9cd1aeSAssar Westerlund 
3725e9cd1aeSAssar Westerlund     *kt = timegm(&tm);
3735e9cd1aeSAssar Westerlund 
3745e9cd1aeSAssar Westerlund     return 0;
3755e9cd1aeSAssar Westerlund }
3765e9cd1aeSAssar Westerlund 
377ae771770SStanislav Sedov static int
378ae771770SStanislav Sedov bervalstrcmp(struct berval *v, const char *str)
379ae771770SStanislav Sedov {
380ae771770SStanislav Sedov     size_t len = strlen(str);
381ae771770SStanislav Sedov     return (v->bv_len == len) && strncasecmp(str, (char *)v->bv_val, len) == 0;
382ae771770SStanislav Sedov }
383ae771770SStanislav Sedov 
384ae771770SStanislav Sedov 
3855e9cd1aeSAssar Westerlund static krb5_error_code
386c19800e8SDoug Rabson LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
3875e9cd1aeSAssar Westerlund 		LDAPMessage * msg, LDAPMod *** pmods)
3885e9cd1aeSAssar Westerlund {
3895e9cd1aeSAssar Westerlund     krb5_error_code ret;
3905e9cd1aeSAssar Westerlund     krb5_boolean is_new_entry;
3915e9cd1aeSAssar Westerlund     char *tmp = NULL;
3925e9cd1aeSAssar Westerlund     LDAPMod **mods = NULL;
393c19800e8SDoug Rabson     hdb_entry_ex orig;
3945e9cd1aeSAssar Westerlund     unsigned long oflags, nflags;
395c19800e8SDoug Rabson     int i;
396c19800e8SDoug Rabson 
397c19800e8SDoug Rabson     krb5_boolean is_samba_account = FALSE;
398c19800e8SDoug Rabson     krb5_boolean is_account = FALSE;
399c19800e8SDoug Rabson     krb5_boolean is_heimdal_entry = FALSE;
400c19800e8SDoug Rabson     krb5_boolean is_heimdal_principal = FALSE;
401c19800e8SDoug Rabson 
402ae771770SStanislav Sedov     struct berval **vals;
403c19800e8SDoug Rabson 
404c19800e8SDoug Rabson     *pmods = NULL;
4055e9cd1aeSAssar Westerlund 
4065e9cd1aeSAssar Westerlund     if (msg != NULL) {
407c19800e8SDoug Rabson 
408ae771770SStanislav Sedov 	ret = LDAP_message2entry(context, db, msg, 0, &orig);
409c19800e8SDoug Rabson 	if (ret)
410c19800e8SDoug Rabson 	    goto out;
411c19800e8SDoug Rabson 
412c19800e8SDoug Rabson 	is_new_entry = FALSE;
413c19800e8SDoug Rabson 
414ae771770SStanislav Sedov 	vals = ldap_get_values_len(HDB2LDAP(db), msg, "objectClass");
415ae771770SStanislav Sedov 	if (vals) {
416ae771770SStanislav Sedov 	    int num_objectclasses = ldap_count_values_len(vals);
417c19800e8SDoug Rabson 	    for (i=0; i < num_objectclasses; i++) {
418ae771770SStanislav Sedov 		if (bervalstrcmp(vals[i], "sambaSamAccount"))
419c19800e8SDoug Rabson 		    is_samba_account = TRUE;
420ae771770SStanislav Sedov 		else if (bervalstrcmp(vals[i], structural_object))
421c19800e8SDoug Rabson 		    is_account = TRUE;
422ae771770SStanislav Sedov 		else if (bervalstrcmp(vals[i], "krb5Principal"))
423c19800e8SDoug Rabson 		    is_heimdal_principal = TRUE;
424ae771770SStanislav Sedov 		else if (bervalstrcmp(vals[i], "krb5KDCEntry"))
425c19800e8SDoug Rabson 		    is_heimdal_entry = TRUE;
426c19800e8SDoug Rabson 	    }
427ae771770SStanislav Sedov 	    ldap_value_free_len(vals);
428c19800e8SDoug Rabson 	}
429c19800e8SDoug Rabson 
430c19800e8SDoug Rabson 	/*
431c19800e8SDoug Rabson 	 * If this is just a "account" entry and no other objectclass
432c19800e8SDoug Rabson 	 * is hanging on this entry, it's really a new entry.
433c19800e8SDoug Rabson 	 */
434c19800e8SDoug Rabson 	if (is_samba_account == FALSE && is_heimdal_principal == FALSE &&
435c19800e8SDoug Rabson 	    is_heimdal_entry == FALSE) {
436c19800e8SDoug Rabson 	    if (is_account == TRUE) {
437c19800e8SDoug Rabson 		is_new_entry = TRUE;
438c19800e8SDoug Rabson 	    } else {
439c19800e8SDoug Rabson 		ret = HDB_ERR_NOENTRY;
4405e9cd1aeSAssar Westerlund 		goto out;
4415e9cd1aeSAssar Westerlund 	    }
442c19800e8SDoug Rabson 	}
443c19800e8SDoug Rabson     } else
444c19800e8SDoug Rabson 	is_new_entry = TRUE;
445c19800e8SDoug Rabson 
446c19800e8SDoug Rabson     if (is_new_entry) {
447c19800e8SDoug Rabson 
4485e9cd1aeSAssar Westerlund 	/* to make it perfectly obvious we're depending on
4495e9cd1aeSAssar Westerlund 	 * orig being intiialized to zero */
4505e9cd1aeSAssar Westerlund 	memset(&orig, 0, sizeof(orig));
451c19800e8SDoug Rabson 
452c19800e8SDoug Rabson 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "top");
453c19800e8SDoug Rabson 	if (ret)
454c19800e8SDoug Rabson 	    goto out;
455c19800e8SDoug Rabson 
456c19800e8SDoug Rabson 	/* account is the structural object class */
457c19800e8SDoug Rabson 	if (is_account == FALSE) {
458c19800e8SDoug Rabson 	    ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass",
459c19800e8SDoug Rabson 			      structural_object);
460c19800e8SDoug Rabson 	    is_account = TRUE;
461c19800e8SDoug Rabson 	    if (ret)
462c19800e8SDoug Rabson 		goto out;
4635e9cd1aeSAssar Westerlund 	}
4645e9cd1aeSAssar Westerlund 
465c19800e8SDoug Rabson 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5Principal");
466c19800e8SDoug Rabson 	is_heimdal_principal = TRUE;
467c19800e8SDoug Rabson 	if (ret)
4685e9cd1aeSAssar Westerlund 	    goto out;
469c19800e8SDoug Rabson 
470c19800e8SDoug Rabson 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5KDCEntry");
471c19800e8SDoug Rabson 	is_heimdal_entry = TRUE;
472c19800e8SDoug Rabson 	if (ret)
4735e9cd1aeSAssar Westerlund 	    goto out;
4745e9cd1aeSAssar Westerlund     }
4755e9cd1aeSAssar Westerlund 
4765e9cd1aeSAssar Westerlund     if (is_new_entry ||
477c19800e8SDoug Rabson 	krb5_principal_compare(context, ent->entry.principal, orig.entry.principal)
478c19800e8SDoug Rabson 	== FALSE)
479c19800e8SDoug Rabson     {
480c19800e8SDoug Rabson 	if (is_heimdal_principal || is_heimdal_entry) {
481c19800e8SDoug Rabson 
482c19800e8SDoug Rabson 	    ret = krb5_unparse_name(context, ent->entry.principal, &tmp);
483c19800e8SDoug Rabson 	    if (ret)
4845e9cd1aeSAssar Westerlund 		goto out;
485c19800e8SDoug Rabson 
486c19800e8SDoug Rabson 	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE,
487c19800e8SDoug Rabson 			      "krb5PrincipalName", tmp);
488c19800e8SDoug Rabson 	    if (ret) {
4895e9cd1aeSAssar Westerlund 		free(tmp);
4905e9cd1aeSAssar Westerlund 		goto out;
4915e9cd1aeSAssar Westerlund 	    }
4925e9cd1aeSAssar Westerlund 	    free(tmp);
4935e9cd1aeSAssar Westerlund 	}
4945e9cd1aeSAssar Westerlund 
495c19800e8SDoug Rabson 	if (is_account || is_samba_account) {
496c19800e8SDoug Rabson 	    ret = krb5_unparse_name_short(context, ent->entry.principal, &tmp);
497c19800e8SDoug Rabson 	    if (ret)
498c19800e8SDoug Rabson 		goto out;
499c19800e8SDoug Rabson 	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "uid", tmp);
500c19800e8SDoug Rabson 	    if (ret) {
501c19800e8SDoug Rabson 		free(tmp);
5025e9cd1aeSAssar Westerlund 		goto out;
5035e9cd1aeSAssar Westerlund 	    }
5045e9cd1aeSAssar Westerlund 	    free(tmp);
5055e9cd1aeSAssar Westerlund 	}
5065e9cd1aeSAssar Westerlund     }
5075e9cd1aeSAssar Westerlund 
508c19800e8SDoug Rabson     if (is_heimdal_entry && (ent->entry.kvno != orig.entry.kvno || is_new_entry)) {
509c19800e8SDoug Rabson 	ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
510c19800e8SDoug Rabson 			    "krb5KeyVersionNumber",
511c19800e8SDoug Rabson 			    ent->entry.kvno);
512c19800e8SDoug Rabson 	if (ret)
513c19800e8SDoug Rabson 	    goto out;
514c19800e8SDoug Rabson     }
515c19800e8SDoug Rabson 
516c19800e8SDoug Rabson     if (is_heimdal_entry && ent->entry.valid_start) {
517c19800e8SDoug Rabson 	if (orig.entry.valid_end == NULL
518c19800e8SDoug Rabson 	    || (*(ent->entry.valid_start) != *(orig.entry.valid_start))) {
519c19800e8SDoug Rabson 	    ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
5205e9cd1aeSAssar Westerlund 					       "krb5ValidStart",
521c19800e8SDoug Rabson 					       ent->entry.valid_start);
522c19800e8SDoug Rabson 	    if (ret)
5235e9cd1aeSAssar Westerlund 		goto out;
5245e9cd1aeSAssar Westerlund 	}
5255e9cd1aeSAssar Westerlund     }
5265e9cd1aeSAssar Westerlund 
527c19800e8SDoug Rabson     if (ent->entry.valid_end) {
528c19800e8SDoug Rabson  	if (orig.entry.valid_end == NULL || (*(ent->entry.valid_end) != *(orig.entry.valid_end))) {
529c19800e8SDoug Rabson 	    if (is_heimdal_entry) {
530c19800e8SDoug Rabson 		ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
5315e9cd1aeSAssar Westerlund 						   "krb5ValidEnd",
532c19800e8SDoug Rabson 						   ent->entry.valid_end);
533c19800e8SDoug Rabson 		if (ret)
534c19800e8SDoug Rabson 		    goto out;
535c19800e8SDoug Rabson             }
536c19800e8SDoug Rabson 	    if (is_samba_account) {
537c19800e8SDoug Rabson 		ret = LDAP_addmod_integer(context, &mods,  LDAP_MOD_REPLACE,
538c19800e8SDoug Rabson 					  "sambaKickoffTime",
539c19800e8SDoug Rabson 					  *(ent->entry.valid_end));
540c19800e8SDoug Rabson 		if (ret)
5415e9cd1aeSAssar Westerlund 		    goto out;
5425e9cd1aeSAssar Westerlund 	    }
5435e9cd1aeSAssar Westerlund    	}
5445e9cd1aeSAssar Westerlund     }
5455e9cd1aeSAssar Westerlund 
546c19800e8SDoug Rabson     if (ent->entry.pw_end) {
547c19800e8SDoug Rabson 	if (orig.entry.pw_end == NULL || (*(ent->entry.pw_end) != *(orig.entry.pw_end))) {
548c19800e8SDoug Rabson 	    if (is_heimdal_entry) {
549c19800e8SDoug Rabson 		ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
5505e9cd1aeSAssar Westerlund 						   "krb5PasswordEnd",
551c19800e8SDoug Rabson 						   ent->entry.pw_end);
552c19800e8SDoug Rabson 		if (ret)
553c19800e8SDoug Rabson 		    goto out;
554c19800e8SDoug Rabson 	    }
555c19800e8SDoug Rabson 
556c19800e8SDoug Rabson 	    if (is_samba_account) {
557c19800e8SDoug Rabson 		ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
558c19800e8SDoug Rabson 					  "sambaPwdMustChange",
559c19800e8SDoug Rabson 					  *(ent->entry.pw_end));
560c19800e8SDoug Rabson 		if (ret)
5615e9cd1aeSAssar Westerlund 		    goto out;
5625e9cd1aeSAssar Westerlund 	    }
5635e9cd1aeSAssar Westerlund 	}
5645e9cd1aeSAssar Westerlund     }
5655e9cd1aeSAssar Westerlund 
5665e9cd1aeSAssar Westerlund 
567c19800e8SDoug Rabson #if 0 /* we we have last_pw_change */
568c19800e8SDoug Rabson     if (is_samba_account && ent->entry.last_pw_change) {
569c19800e8SDoug Rabson 	if (orig.entry.last_pw_change == NULL || (*(ent->entry.last_pw_change) != *(orig.entry.last_pw_change))) {
570c19800e8SDoug Rabson 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
571c19800e8SDoug Rabson 				      "sambaPwdLastSet",
572c19800e8SDoug Rabson 				      *(ent->entry.last_pw_change));
573c19800e8SDoug Rabson 	    if (ret)
5745e9cd1aeSAssar Westerlund 		goto out;
5755e9cd1aeSAssar Westerlund 	}
5765e9cd1aeSAssar Westerlund     }
577c19800e8SDoug Rabson #endif
5785e9cd1aeSAssar Westerlund 
579c19800e8SDoug Rabson     if (is_heimdal_entry && ent->entry.max_life) {
580c19800e8SDoug Rabson 	if (orig.entry.max_life == NULL
581c19800e8SDoug Rabson 	    || (*(ent->entry.max_life) != *(orig.entry.max_life))) {
5825e9cd1aeSAssar Westerlund 
583c19800e8SDoug Rabson 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
584c19800e8SDoug Rabson 				      "krb5MaxLife",
585c19800e8SDoug Rabson 				      *(ent->entry.max_life));
586c19800e8SDoug Rabson 	    if (ret)
5875e9cd1aeSAssar Westerlund 		goto out;
5885e9cd1aeSAssar Westerlund 	}
5895e9cd1aeSAssar Westerlund     }
5905e9cd1aeSAssar Westerlund 
591c19800e8SDoug Rabson     if (is_heimdal_entry && ent->entry.max_renew) {
592c19800e8SDoug Rabson 	if (orig.entry.max_renew == NULL
593c19800e8SDoug Rabson 	    || (*(ent->entry.max_renew) != *(orig.entry.max_renew))) {
594c19800e8SDoug Rabson 
595c19800e8SDoug Rabson 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
596c19800e8SDoug Rabson 				      "krb5MaxRenew",
597c19800e8SDoug Rabson 				      *(ent->entry.max_renew));
598c19800e8SDoug Rabson 	    if (ret)
599c19800e8SDoug Rabson 		goto out;
600c19800e8SDoug Rabson 	}
601c19800e8SDoug Rabson     }
602c19800e8SDoug Rabson 
603c19800e8SDoug Rabson     oflags = HDBFlags2int(orig.entry.flags);
604c19800e8SDoug Rabson     nflags = HDBFlags2int(ent->entry.flags);
605c19800e8SDoug Rabson 
606c19800e8SDoug Rabson     if (is_heimdal_entry && oflags != nflags) {
607c19800e8SDoug Rabson 
608c19800e8SDoug Rabson 	ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
609c19800e8SDoug Rabson 				  "krb5KDCFlags",
610c19800e8SDoug Rabson 				  nflags);
611c19800e8SDoug Rabson 	if (ret)
612c19800e8SDoug Rabson 	    goto out;
613c19800e8SDoug Rabson     }
614c19800e8SDoug Rabson 
615c19800e8SDoug Rabson     /* Remove keys if they exists, and then replace keys. */
616c19800e8SDoug Rabson     if (!is_new_entry && orig.entry.keys.len > 0) {
617ae771770SStanislav Sedov 	vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key");
618ae771770SStanislav Sedov 	if (vals) {
619ae771770SStanislav Sedov 	    ldap_value_free_len(vals);
620c19800e8SDoug Rabson 
6215e9cd1aeSAssar Westerlund 	    ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5Key", NULL);
622c19800e8SDoug Rabson 	    if (ret)
6235e9cd1aeSAssar Westerlund 		goto out;
6245e9cd1aeSAssar Westerlund 	}
6255e9cd1aeSAssar Westerlund     }
6265e9cd1aeSAssar Westerlund 
627c19800e8SDoug Rabson     for (i = 0; i < ent->entry.keys.len; i++) {
628c19800e8SDoug Rabson 
629c19800e8SDoug Rabson 	if (is_samba_account
630c19800e8SDoug Rabson 	    && ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
631c19800e8SDoug Rabson 	    char *ntHexPassword;
632c19800e8SDoug Rabson 	    char *nt;
633ae771770SStanislav Sedov 	    time_t now = time(NULL);
634c19800e8SDoug Rabson 
635c19800e8SDoug Rabson 	    /* the key might have been 'sealed', but samba passwords
636c19800e8SDoug Rabson 	       are clear in the directory */
637c19800e8SDoug Rabson 	    ret = hdb_unseal_key(context, db, &ent->entry.keys.val[i]);
638c19800e8SDoug Rabson 	    if (ret)
639c19800e8SDoug Rabson 		goto out;
640c19800e8SDoug Rabson 
641c19800e8SDoug Rabson 	    nt = ent->entry.keys.val[i].key.keyvalue.data;
642c19800e8SDoug Rabson 	    /* store in ntPassword, not krb5key */
643c19800e8SDoug Rabson 	    ret = hex_encode(nt, 16, &ntHexPassword);
644c19800e8SDoug Rabson 	    if (ret < 0) {
645c19800e8SDoug Rabson 		ret = ENOMEM;
646ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, "hdb-ldap: failed to "
647ae771770SStanislav Sedov 				      "hex encode key");
648c19800e8SDoug Rabson 		goto out;
649c19800e8SDoug Rabson 	    }
650c19800e8SDoug Rabson 	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "sambaNTPassword",
651c19800e8SDoug Rabson 			      ntHexPassword);
652c19800e8SDoug Rabson 	    free(ntHexPassword);
653c19800e8SDoug Rabson 	    if (ret)
654c19800e8SDoug Rabson 		goto out;
655ae771770SStanislav Sedov 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
656ae771770SStanislav Sedov 				      "sambaPwdLastSet", now);
657ae771770SStanislav Sedov 	    if (ret)
658ae771770SStanislav Sedov 		goto out;
659c19800e8SDoug Rabson 
660c19800e8SDoug Rabson 	    /* have to kill the LM passwod if it exists */
661ae771770SStanislav Sedov 	    vals = ldap_get_values_len(HDB2LDAP(db), msg, "sambaLMPassword");
662ae771770SStanislav Sedov 	    if (vals) {
663ae771770SStanislav Sedov 		ldap_value_free_len(vals);
664c19800e8SDoug Rabson 		ret = LDAP_addmod(&mods, LDAP_MOD_DELETE,
665c19800e8SDoug Rabson 				  "sambaLMPassword", NULL);
666c19800e8SDoug Rabson 		if (ret)
667c19800e8SDoug Rabson 		    goto out;
668c19800e8SDoug Rabson 	    }
669c19800e8SDoug Rabson 
670c19800e8SDoug Rabson 	} else if (is_heimdal_entry) {
6715e9cd1aeSAssar Westerlund 	    unsigned char *buf;
672c19800e8SDoug Rabson 	    size_t len, buf_size;
6735e9cd1aeSAssar Westerlund 
674c19800e8SDoug Rabson 	    ASN1_MALLOC_ENCODE(Key, buf, buf_size, &ent->entry.keys.val[i], &len, ret);
675c19800e8SDoug Rabson 	    if (ret)
6765e9cd1aeSAssar Westerlund 		goto out;
677c19800e8SDoug Rabson 	    if(buf_size != len)
678c19800e8SDoug Rabson 		krb5_abortx(context, "internal error in ASN.1 encoder");
6795e9cd1aeSAssar Westerlund 
6805e9cd1aeSAssar Westerlund 	    /* addmod_len _owns_ the key, doesn't need to copy it */
6815e9cd1aeSAssar Westerlund 	    ret = LDAP_addmod_len(&mods, LDAP_MOD_ADD, "krb5Key", buf, len);
682c19800e8SDoug Rabson 	    if (ret)
6835e9cd1aeSAssar Westerlund 		goto out;
6845e9cd1aeSAssar Westerlund 	}
6855e9cd1aeSAssar Westerlund     }
6865e9cd1aeSAssar Westerlund 
687c19800e8SDoug Rabson     if (ent->entry.etypes) {
688c19800e8SDoug Rabson 	int add_krb5EncryptionType = 0;
689c19800e8SDoug Rabson 
690c19800e8SDoug Rabson 	/*
691c19800e8SDoug Rabson 	 * Only add/modify krb5EncryptionType if it's a new heimdal
692c19800e8SDoug Rabson 	 * entry or krb5EncryptionType already exists on the entry.
693c19800e8SDoug Rabson 	 */
694c19800e8SDoug Rabson 
695c19800e8SDoug Rabson 	if (!is_new_entry) {
696ae771770SStanislav Sedov 	    vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType");
697ae771770SStanislav Sedov 	    if (vals) {
698ae771770SStanislav Sedov 		ldap_value_free_len(vals);
699c19800e8SDoug Rabson 		ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5EncryptionType",
7005e9cd1aeSAssar Westerlund 				  NULL);
701c19800e8SDoug Rabson 		if (ret)
702c19800e8SDoug Rabson 		    goto out;
703c19800e8SDoug Rabson 		add_krb5EncryptionType = 1;
7045e9cd1aeSAssar Westerlund 	    }
705c19800e8SDoug Rabson 	} else if (is_heimdal_entry)
706c19800e8SDoug Rabson 	    add_krb5EncryptionType = 1;
707c19800e8SDoug Rabson 
708c19800e8SDoug Rabson 	if (add_krb5EncryptionType) {
709c19800e8SDoug Rabson 	    for (i = 0; i < ent->entry.etypes->len; i++) {
710c19800e8SDoug Rabson 		if (is_samba_account &&
711c19800e8SDoug Rabson 		    ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5)
712c19800e8SDoug Rabson 		{
713c19800e8SDoug Rabson 		    ;
714c19800e8SDoug Rabson 		} else if (is_heimdal_entry) {
715c19800e8SDoug Rabson 		    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_ADD,
716c19800e8SDoug Rabson 					      "krb5EncryptionType",
717c19800e8SDoug Rabson 					      ent->entry.etypes->val[i]);
718c19800e8SDoug Rabson 		    if (ret)
7195e9cd1aeSAssar Westerlund 			goto out;
7205e9cd1aeSAssar Westerlund 		}
7215e9cd1aeSAssar Westerlund 	    }
7225e9cd1aeSAssar Westerlund 	}
7235e9cd1aeSAssar Westerlund     }
7245e9cd1aeSAssar Westerlund 
7255e9cd1aeSAssar Westerlund     /* for clarity */
7265e9cd1aeSAssar Westerlund     ret = 0;
7275e9cd1aeSAssar Westerlund 
7285e9cd1aeSAssar Westerlund  out:
7295e9cd1aeSAssar Westerlund 
730c19800e8SDoug Rabson     if (ret == 0)
7315e9cd1aeSAssar Westerlund 	*pmods = mods;
732c19800e8SDoug Rabson     else if (mods != NULL) {
7335e9cd1aeSAssar Westerlund 	ldap_mods_free(mods, 1);
7345e9cd1aeSAssar Westerlund 	*pmods = NULL;
7355e9cd1aeSAssar Westerlund     }
7365e9cd1aeSAssar Westerlund 
737c19800e8SDoug Rabson     if (msg)
7385e9cd1aeSAssar Westerlund 	hdb_free_entry(context, &orig);
7395e9cd1aeSAssar Westerlund 
7405e9cd1aeSAssar Westerlund     return ret;
7415e9cd1aeSAssar Westerlund }
7425e9cd1aeSAssar Westerlund 
7435e9cd1aeSAssar Westerlund static krb5_error_code
7445e9cd1aeSAssar Westerlund LDAP_dn2principal(krb5_context context, HDB * db, const char *dn,
7455e9cd1aeSAssar Westerlund 		  krb5_principal * principal)
7465e9cd1aeSAssar Westerlund {
7475e9cd1aeSAssar Westerlund     krb5_error_code ret;
748c19800e8SDoug Rabson     int rc;
749c19800e8SDoug Rabson     const char *filter = "(objectClass=krb5Principal)";
7505e9cd1aeSAssar Westerlund     LDAPMessage *res = NULL, *e;
751ae771770SStanislav Sedov     char *p;
7525e9cd1aeSAssar Westerlund 
753c19800e8SDoug Rabson     ret = LDAP_no_size_limit(context, HDB2LDAP(db));
754c19800e8SDoug Rabson     if (ret)
7554137ff4cSJacques Vidrine 	goto out;
7564137ff4cSJacques Vidrine 
757ae771770SStanislav Sedov     rc = ldap_search_ext_s(HDB2LDAP(db), dn, LDAP_SCOPE_SUBTREE,
758ae771770SStanislav Sedov 			   filter, krb5principal_attrs, 0,
759ae771770SStanislav Sedov 			   NULL, NULL, NULL,
7605e9cd1aeSAssar Westerlund 			   0, &res);
761c19800e8SDoug Rabson     if (check_ldap(context, db, rc)) {
7625e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
763ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "ldap_search_ext_s: "
764ae771770SStanislav Sedov 			       "filter: %s error: %s",
765ae771770SStanislav Sedov 			       filter, ldap_err2string(rc));
7665e9cd1aeSAssar Westerlund 	goto out;
7675e9cd1aeSAssar Westerlund     }
7685e9cd1aeSAssar Westerlund 
769c19800e8SDoug Rabson     e = ldap_first_entry(HDB2LDAP(db), res);
7705e9cd1aeSAssar Westerlund     if (e == NULL) {
7715e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
7725e9cd1aeSAssar Westerlund 	goto out;
7735e9cd1aeSAssar Westerlund     }
7745e9cd1aeSAssar Westerlund 
775ae771770SStanislav Sedov     ret = LDAP_get_string_value(db, e, "krb5PrincipalName", &p);
776ae771770SStanislav Sedov     if (ret) {
7775e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
7785e9cd1aeSAssar Westerlund 	goto out;
7795e9cd1aeSAssar Westerlund     }
7805e9cd1aeSAssar Westerlund 
781ae771770SStanislav Sedov     ret = krb5_parse_name(context, p, principal);
782ae771770SStanislav Sedov     free(p);
7835e9cd1aeSAssar Westerlund 
7845e9cd1aeSAssar Westerlund   out:
785c19800e8SDoug Rabson     if (res)
7865e9cd1aeSAssar Westerlund 	ldap_msgfree(res);
787c19800e8SDoug Rabson 
7885e9cd1aeSAssar Westerlund     return ret;
7895e9cd1aeSAssar Westerlund }
7905e9cd1aeSAssar Westerlund 
791ae771770SStanislav Sedov static int
792ae771770SStanislav Sedov need_quote(unsigned char c)
793ae771770SStanislav Sedov {
794ae771770SStanislav Sedov     return (c & 0x80) ||
795ae771770SStanislav Sedov 	(c < 32) ||
796ae771770SStanislav Sedov 	(c == '(') ||
797ae771770SStanislav Sedov 	(c == ')') ||
798ae771770SStanislav Sedov 	(c == '*') ||
799ae771770SStanislav Sedov 	(c == '\\') ||
800ae771770SStanislav Sedov 	(c == 0x7f);
801ae771770SStanislav Sedov }
802ae771770SStanislav Sedov 
803*a0d7d68aSCy Schubert static const char hexchar[] = "0123456789ABCDEF";
804ae771770SStanislav Sedov 
805ae771770SStanislav Sedov static krb5_error_code
806*a0d7d68aSCy Schubert escape_value(krb5_context context, const char *unquoted, char **quoted)
807ae771770SStanislav Sedov {
808ae771770SStanislav Sedov     size_t i, len;
809ae771770SStanislav Sedov 
810ae771770SStanislav Sedov     for (i = 0, len = 0; unquoted[i] != '\0'; i++, len++) {
811ae771770SStanislav Sedov 	if (need_quote((unsigned char)unquoted[i]))
812ae771770SStanislav Sedov 	    len += 2;
813ae771770SStanislav Sedov     }
814ae771770SStanislav Sedov 
815ae771770SStanislav Sedov     *quoted = malloc(len + 1);
816ae771770SStanislav Sedov     if (*quoted == NULL) {
817ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
818ae771770SStanislav Sedov 	return ENOMEM;
819ae771770SStanislav Sedov     }
820ae771770SStanislav Sedov 
821ae771770SStanislav Sedov     for (i = 0; unquoted[0] ; unquoted++) {
822*a0d7d68aSCy Schubert 	if (need_quote((unsigned char)unquoted[0])) {
823ae771770SStanislav Sedov 	    (*quoted)[i++] = '\\';
824ae771770SStanislav Sedov 	    (*quoted)[i++] = hexchar[(unquoted[0] >> 4) & 0xf];
825ae771770SStanislav Sedov 	    (*quoted)[i++] = hexchar[(unquoted[0]     ) & 0xf];
826ae771770SStanislav Sedov 	} else
827ae771770SStanislav Sedov 	    (*quoted)[i++] = (char)unquoted[0];
828ae771770SStanislav Sedov     }
829ae771770SStanislav Sedov     (*quoted)[i] = '\0';
830ae771770SStanislav Sedov     return 0;
831ae771770SStanislav Sedov }
832ae771770SStanislav Sedov 
833ae771770SStanislav Sedov 
8345e9cd1aeSAssar Westerlund static krb5_error_code
835c19800e8SDoug Rabson LDAP__lookup_princ(krb5_context context,
836c19800e8SDoug Rabson 		   HDB *db,
837c19800e8SDoug Rabson 		   const char *princname,
838c19800e8SDoug Rabson 		   const char *userid,
8395e9cd1aeSAssar Westerlund 		   LDAPMessage **msg)
8405e9cd1aeSAssar Westerlund {
8415e9cd1aeSAssar Westerlund     krb5_error_code ret;
842c19800e8SDoug Rabson     int rc;
843ae771770SStanislav Sedov     char *quote, *filter = NULL;
8445e9cd1aeSAssar Westerlund 
845c19800e8SDoug Rabson     ret = LDAP__connect(context, db);
846c19800e8SDoug Rabson     if (ret)
847c19800e8SDoug Rabson 	return ret;
8485e9cd1aeSAssar Westerlund 
849ae771770SStanislav Sedov     /*
850ae771770SStanislav Sedov      * Quote searches that contain filter language, this quote
851ae771770SStanislav Sedov      * searches for *@REALM, which takes very long time.
852ae771770SStanislav Sedov      */
853ae771770SStanislav Sedov 
854ae771770SStanislav Sedov     ret = escape_value(context, princname, &quote);
855ae771770SStanislav Sedov     if (ret)
856ae771770SStanislav Sedov 	goto out;
857ae771770SStanislav Sedov 
858c19800e8SDoug Rabson     rc = asprintf(&filter,
859c19800e8SDoug Rabson 		  "(&(objectClass=krb5Principal)(krb5PrincipalName=%s))",
860ae771770SStanislav Sedov 		  quote);
861ae771770SStanislav Sedov     free(quote);
862ae771770SStanislav Sedov 
8635e9cd1aeSAssar Westerlund     if (rc < 0) {
8645e9cd1aeSAssar Westerlund 	ret = ENOMEM;
865ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "malloc: out of memory");
8665e9cd1aeSAssar Westerlund 	goto out;
8675e9cd1aeSAssar Westerlund     }
8685e9cd1aeSAssar Westerlund 
869c19800e8SDoug Rabson     ret = LDAP_no_size_limit(context, HDB2LDAP(db));
870c19800e8SDoug Rabson     if (ret)
871c19800e8SDoug Rabson 	goto out;
872c19800e8SDoug Rabson 
873ae771770SStanislav Sedov     rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db),
874ae771770SStanislav Sedov 			   LDAP_SCOPE_SUBTREE, filter,
875ae771770SStanislav Sedov 			   krb5kdcentry_attrs, 0,
876ae771770SStanislav Sedov 			   NULL, NULL, NULL,
877ae771770SStanislav Sedov 			   0, msg);
878c19800e8SDoug Rabson     if (check_ldap(context, db, rc)) {
879c19800e8SDoug Rabson 	ret = HDB_ERR_NOENTRY;
880ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "ldap_search_ext_s: "
881ae771770SStanislav Sedov 			      "filter: %s - error: %s",
882ae771770SStanislav Sedov 			      filter, ldap_err2string(rc));
8834137ff4cSJacques Vidrine 	goto out;
8844137ff4cSJacques Vidrine     }
8855e9cd1aeSAssar Westerlund 
886c19800e8SDoug Rabson     if (userid && ldap_count_entries(HDB2LDAP(db), *msg) == 0) {
887c19800e8SDoug Rabson 	free(filter);
888c19800e8SDoug Rabson 	filter = NULL;
889c19800e8SDoug Rabson 	ldap_msgfree(*msg);
890c19800e8SDoug Rabson 	*msg = NULL;
891c19800e8SDoug Rabson 
892ae771770SStanislav Sedov 	ret = escape_value(context, userid, &quote);
893ae771770SStanislav Sedov 	if (ret)
894ae771770SStanislav Sedov 	    goto out;
895ae771770SStanislav Sedov 
896c19800e8SDoug Rabson 	rc = asprintf(&filter,
897c19800e8SDoug Rabson 	    "(&(|(objectClass=sambaSamAccount)(objectClass=%s))(uid=%s))",
898ae771770SStanislav Sedov 		      structural_object, quote);
899ae771770SStanislav Sedov 	free(quote);
900c19800e8SDoug Rabson 	if (rc < 0) {
901c19800e8SDoug Rabson 	    ret = ENOMEM;
902ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "asprintf: out of memory");
903c19800e8SDoug Rabson 	    goto out;
904c19800e8SDoug Rabson 	}
905c19800e8SDoug Rabson 
906c19800e8SDoug Rabson 	ret = LDAP_no_size_limit(context, HDB2LDAP(db));
907c19800e8SDoug Rabson 	if (ret)
908c19800e8SDoug Rabson 	    goto out;
909c19800e8SDoug Rabson 
910ae771770SStanislav Sedov 	rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE,
911ae771770SStanislav Sedov 			       filter, krb5kdcentry_attrs, 0,
912ae771770SStanislav Sedov 			       NULL, NULL, NULL,
913ae771770SStanislav Sedov 			       0, msg);
914c19800e8SDoug Rabson 	if (check_ldap(context, db, rc)) {
9155e9cd1aeSAssar Westerlund 	    ret = HDB_ERR_NOENTRY;
916ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
917ae771770SStanislav Sedov 				   "ldap_search_ext_s: filter: %s error: %s",
918ae771770SStanislav Sedov 				   filter, ldap_err2string(rc));
9195e9cd1aeSAssar Westerlund 	    goto out;
9205e9cd1aeSAssar Westerlund 	}
921c19800e8SDoug Rabson     }
9225e9cd1aeSAssar Westerlund 
9235e9cd1aeSAssar Westerlund     ret = 0;
9245e9cd1aeSAssar Westerlund 
9255e9cd1aeSAssar Westerlund   out:
926c19800e8SDoug Rabson     if (filter)
9275e9cd1aeSAssar Westerlund 	free(filter);
928c19800e8SDoug Rabson 
9295e9cd1aeSAssar Westerlund     return ret;
9305e9cd1aeSAssar Westerlund }
9315e9cd1aeSAssar Westerlund 
9325e9cd1aeSAssar Westerlund static krb5_error_code
9335e9cd1aeSAssar Westerlund LDAP_principal2message(krb5_context context, HDB * db,
934c19800e8SDoug Rabson 		       krb5_const_principal princ, LDAPMessage ** msg)
9355e9cd1aeSAssar Westerlund {
936c19800e8SDoug Rabson     char *name, *name_short = NULL;
9375e9cd1aeSAssar Westerlund     krb5_error_code ret;
938c19800e8SDoug Rabson     krb5_realm *r, *r0;
9395e9cd1aeSAssar Westerlund 
940c19800e8SDoug Rabson     *msg = NULL;
941c19800e8SDoug Rabson 
942c19800e8SDoug Rabson     ret = krb5_unparse_name(context, princ, &name);
943c19800e8SDoug Rabson     if (ret)
944c19800e8SDoug Rabson 	return ret;
945c19800e8SDoug Rabson 
946c19800e8SDoug Rabson     ret = krb5_get_default_realms(context, &r0);
947c19800e8SDoug Rabson     if(ret) {
948c19800e8SDoug Rabson 	free(name);
9495e9cd1aeSAssar Westerlund 	return ret;
9505e9cd1aeSAssar Westerlund     }
951c19800e8SDoug Rabson     for (r = r0; *r != NULL; r++) {
952c19800e8SDoug Rabson 	if(strcmp(krb5_principal_get_realm(context, princ), *r) == 0) {
953c19800e8SDoug Rabson 	    ret = krb5_unparse_name_short(context, princ, &name_short);
954c19800e8SDoug Rabson 	    if (ret) {
955c19800e8SDoug Rabson 		krb5_free_host_realm(context, r0);
956c19800e8SDoug Rabson 		free(name);
957c19800e8SDoug Rabson 		return ret;
958c19800e8SDoug Rabson 	    }
959c19800e8SDoug Rabson 	    break;
960c19800e8SDoug Rabson 	}
961c19800e8SDoug Rabson     }
962c19800e8SDoug Rabson     krb5_free_host_realm(context, r0);
9635e9cd1aeSAssar Westerlund 
964c19800e8SDoug Rabson     ret = LDAP__lookup_princ(context, db, name, name_short, msg);
965c19800e8SDoug Rabson     free(name);
966c19800e8SDoug Rabson     free(name_short);
9675e9cd1aeSAssar Westerlund 
9685e9cd1aeSAssar Westerlund     return ret;
9695e9cd1aeSAssar Westerlund }
9705e9cd1aeSAssar Westerlund 
9715e9cd1aeSAssar Westerlund /*
9725e9cd1aeSAssar Westerlund  * Construct an hdb_entry from a directory entry.
9735e9cd1aeSAssar Westerlund  */
9745e9cd1aeSAssar Westerlund static krb5_error_code
9755e9cd1aeSAssar Westerlund LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
976ae771770SStanislav Sedov 		   int flags, hdb_entry_ex * ent)
9775e9cd1aeSAssar Westerlund {
978c19800e8SDoug Rabson     char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL;
979c19800e8SDoug Rabson     char *samba_acct_flags = NULL;
9805e9cd1aeSAssar Westerlund     struct berval **keys;
981ae771770SStanislav Sedov     struct berval **vals;
982ae771770SStanislav Sedov     int tmp, tmp_time, i, ret, have_arcfour = 0;
9835e9cd1aeSAssar Westerlund 
9845e9cd1aeSAssar Westerlund     memset(ent, 0, sizeof(*ent));
985c19800e8SDoug Rabson     ent->entry.flags = int2HDBFlags(0);
9865e9cd1aeSAssar Westerlund 
987c19800e8SDoug Rabson     ret = LDAP_get_string_value(db, msg, "krb5PrincipalName", &unparsed_name);
988c19800e8SDoug Rabson     if (ret == 0) {
989c19800e8SDoug Rabson 	ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal);
990c19800e8SDoug Rabson 	if (ret)
9915e9cd1aeSAssar Westerlund 	    goto out;
992c19800e8SDoug Rabson     } else {
993c19800e8SDoug Rabson 	ret = LDAP_get_string_value(db, msg, "uid",
994c19800e8SDoug Rabson 				    &unparsed_name);
995c19800e8SDoug Rabson 	if (ret == 0) {
996c19800e8SDoug Rabson 	    ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal);
997c19800e8SDoug Rabson 	    if (ret)
998c19800e8SDoug Rabson 		goto out;
999c19800e8SDoug Rabson 	} else {
1000ae771770SStanislav Sedov 	    krb5_set_error_message(context, HDB_ERR_NOENTRY,
1001ae771770SStanislav Sedov 				   "hdb-ldap: ldap entry missing"
1002c19800e8SDoug Rabson 				  "principal name");
1003c19800e8SDoug Rabson 	    return HDB_ERR_NOENTRY;
1004c19800e8SDoug Rabson 	}
10055e9cd1aeSAssar Westerlund     }
10065e9cd1aeSAssar Westerlund 
1007c19800e8SDoug Rabson     {
1008c19800e8SDoug Rabson 	int integer;
1009c19800e8SDoug Rabson 	ret = LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber",
1010c19800e8SDoug Rabson 				     &integer);
1011c19800e8SDoug Rabson 	if (ret)
1012c19800e8SDoug Rabson 	    ent->entry.kvno = 0;
1013c19800e8SDoug Rabson 	else
1014c19800e8SDoug Rabson 	    ent->entry.kvno = integer;
10155e9cd1aeSAssar Westerlund     }
10165e9cd1aeSAssar Westerlund 
1017c19800e8SDoug Rabson     keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key");
10185e9cd1aeSAssar Westerlund     if (keys != NULL) {
10195e9cd1aeSAssar Westerlund 	int i;
10205e9cd1aeSAssar Westerlund 	size_t l;
10215e9cd1aeSAssar Westerlund 
1022c19800e8SDoug Rabson 	ent->entry.keys.len = ldap_count_values_len(keys);
1023c19800e8SDoug Rabson 	ent->entry.keys.val = (Key *) calloc(ent->entry.keys.len, sizeof(Key));
1024c19800e8SDoug Rabson 	if (ent->entry.keys.val == NULL) {
10254137ff4cSJacques Vidrine 	    ret = ENOMEM;
1026ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "calloc: out of memory");
10274137ff4cSJacques Vidrine 	    goto out;
10284137ff4cSJacques Vidrine 	}
1029c19800e8SDoug Rabson 	for (i = 0; i < ent->entry.keys.len; i++) {
10305e9cd1aeSAssar Westerlund 	    decode_Key((unsigned char *) keys[i]->bv_val,
1031c19800e8SDoug Rabson 		       (size_t) keys[i]->bv_len, &ent->entry.keys.val[i], &l);
10325e9cd1aeSAssar Westerlund 	}
10335e9cd1aeSAssar Westerlund 	ber_bvecfree(keys);
10345e9cd1aeSAssar Westerlund     } else {
10355e9cd1aeSAssar Westerlund #if 1
10365e9cd1aeSAssar Westerlund 	/*
10375e9cd1aeSAssar Westerlund 	 * This violates the ASN1 but it allows a principal to
10385e9cd1aeSAssar Westerlund 	 * be related to a general directory entry without creating
10395e9cd1aeSAssar Westerlund 	 * the keys. Hopefully it's OK.
10405e9cd1aeSAssar Westerlund 	 */
1041c19800e8SDoug Rabson 	ent->entry.keys.len = 0;
1042c19800e8SDoug Rabson 	ent->entry.keys.val = NULL;
10435e9cd1aeSAssar Westerlund #else
10445e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
10455e9cd1aeSAssar Westerlund 	goto out;
10465e9cd1aeSAssar Westerlund #endif
10475e9cd1aeSAssar Westerlund     }
10485e9cd1aeSAssar Westerlund 
1049ae771770SStanislav Sedov     vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType");
1050ae771770SStanislav Sedov     if (vals != NULL) {
1051c19800e8SDoug Rabson 	int i;
1052c19800e8SDoug Rabson 
1053c19800e8SDoug Rabson 	ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes)));
1054c19800e8SDoug Rabson 	if (ent->entry.etypes == NULL) {
1055c19800e8SDoug Rabson 	    ret = ENOMEM;
1056ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,"malloc: out of memory");
1057c19800e8SDoug Rabson 	    goto out;
1058c19800e8SDoug Rabson 	}
1059ae771770SStanislav Sedov 	ent->entry.etypes->len = ldap_count_values_len(vals);
1060c19800e8SDoug Rabson 	ent->entry.etypes->val = calloc(ent->entry.etypes->len, sizeof(int));
1061c19800e8SDoug Rabson 	if (ent->entry.etypes->val == NULL) {
1062c19800e8SDoug Rabson 	    ret = ENOMEM;
1063ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1064ae771770SStanislav Sedov 	    ent->entry.etypes->len = 0;
1065c19800e8SDoug Rabson 	    goto out;
1066c19800e8SDoug Rabson 	}
1067c19800e8SDoug Rabson 	for (i = 0; i < ent->entry.etypes->len; i++) {
1068ae771770SStanislav Sedov 	    char *buf;
1069ae771770SStanislav Sedov 
1070ae771770SStanislav Sedov 	    buf = malloc(vals[i]->bv_len + 1);
1071ae771770SStanislav Sedov 	    if (buf == NULL) {
1072ae771770SStanislav Sedov 		ret = ENOMEM;
1073ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, "malloc: out of memory");
1074ae771770SStanislav Sedov 		goto out;
1075c19800e8SDoug Rabson 	    }
1076ae771770SStanislav Sedov 	    memcpy(buf, vals[i]->bv_val, vals[i]->bv_len);
1077ae771770SStanislav Sedov 	    buf[vals[i]->bv_len] = '\0';
1078ae771770SStanislav Sedov 	    ent->entry.etypes->val[i] = atoi(buf);
1079ae771770SStanislav Sedov 	    free(buf);
1080ae771770SStanislav Sedov 	}
1081ae771770SStanislav Sedov 	ldap_value_free_len(vals);
10825e9cd1aeSAssar Westerlund     }
10835e9cd1aeSAssar Westerlund 
1084c19800e8SDoug Rabson     for (i = 0; i < ent->entry.keys.len; i++) {
1085c19800e8SDoug Rabson 	if (ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
1086c19800e8SDoug Rabson 	    have_arcfour = 1;
1087c19800e8SDoug Rabson 	    break;
1088c19800e8SDoug Rabson 	}
1089c19800e8SDoug Rabson     }
1090c19800e8SDoug Rabson 
1091c19800e8SDoug Rabson     /* manually construct the NT (type 23) key */
1092c19800e8SDoug Rabson     ret = LDAP_get_string_value(db, msg, "sambaNTPassword", &ntPasswordIN);
1093c19800e8SDoug Rabson     if (ret == 0 && have_arcfour == 0) {
1094c19800e8SDoug Rabson 	unsigned *etypes;
1095c19800e8SDoug Rabson 	Key *keys;
1096c19800e8SDoug Rabson 	int i;
1097c19800e8SDoug Rabson 
1098c19800e8SDoug Rabson 	keys = realloc(ent->entry.keys.val,
1099c19800e8SDoug Rabson 		       (ent->entry.keys.len + 1) * sizeof(ent->entry.keys.val[0]));
1100c19800e8SDoug Rabson 	if (keys == NULL) {
1101c19800e8SDoug Rabson 	    free(ntPasswordIN);
1102c19800e8SDoug Rabson 	    ret = ENOMEM;
1103ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1104c19800e8SDoug Rabson 	    goto out;
1105c19800e8SDoug Rabson 	}
1106c19800e8SDoug Rabson 	ent->entry.keys.val = keys;
1107c19800e8SDoug Rabson 	memset(&ent->entry.keys.val[ent->entry.keys.len], 0, sizeof(Key));
1108c19800e8SDoug Rabson 	ent->entry.keys.val[ent->entry.keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5;
1109c19800e8SDoug Rabson 	ret = krb5_data_alloc (&ent->entry.keys.val[ent->entry.keys.len].key.keyvalue, 16);
1110c19800e8SDoug Rabson 	if (ret) {
1111ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1112c19800e8SDoug Rabson 	    free(ntPasswordIN);
1113c19800e8SDoug Rabson 	    ret = ENOMEM;
1114c19800e8SDoug Rabson 	    goto out;
1115c19800e8SDoug Rabson 	}
1116c19800e8SDoug Rabson 	ret = hex_decode(ntPasswordIN,
1117c19800e8SDoug Rabson 			 ent->entry.keys.val[ent->entry.keys.len].key.keyvalue.data, 16);
1118c19800e8SDoug Rabson 	ent->entry.keys.len++;
1119c19800e8SDoug Rabson 
1120c19800e8SDoug Rabson 	if (ent->entry.etypes == NULL) {
1121c19800e8SDoug Rabson 	    ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes)));
1122c19800e8SDoug Rabson 	    if (ent->entry.etypes == NULL) {
1123c19800e8SDoug Rabson 		ret = ENOMEM;
1124ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, "malloc: out of memory");
1125c19800e8SDoug Rabson 		goto out;
1126c19800e8SDoug Rabson 	    }
1127c19800e8SDoug Rabson 	    ent->entry.etypes->val = NULL;
1128c19800e8SDoug Rabson 	    ent->entry.etypes->len = 0;
1129c19800e8SDoug Rabson 	}
1130c19800e8SDoug Rabson 
1131c19800e8SDoug Rabson 	for (i = 0; i < ent->entry.etypes->len; i++)
1132c19800e8SDoug Rabson 	    if (ent->entry.etypes->val[i] == ETYPE_ARCFOUR_HMAC_MD5)
1133c19800e8SDoug Rabson 		break;
1134c19800e8SDoug Rabson 	/* If there is no ARCFOUR enctype, add one */
1135c19800e8SDoug Rabson 	if (i == ent->entry.etypes->len) {
1136c19800e8SDoug Rabson 	    etypes = realloc(ent->entry.etypes->val,
1137c19800e8SDoug Rabson 			     (ent->entry.etypes->len + 1) *
1138c19800e8SDoug Rabson 			     sizeof(ent->entry.etypes->val[0]));
1139c19800e8SDoug Rabson 	    if (etypes == NULL) {
1140c19800e8SDoug Rabson 		ret = ENOMEM;
1141ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, "malloc: out of memory");
1142c19800e8SDoug Rabson 		goto out;
1143c19800e8SDoug Rabson 	    }
1144c19800e8SDoug Rabson 	    ent->entry.etypes->val = etypes;
1145c19800e8SDoug Rabson 	    ent->entry.etypes->val[ent->entry.etypes->len] =
1146c19800e8SDoug Rabson 		ETYPE_ARCFOUR_HMAC_MD5;
1147c19800e8SDoug Rabson 	    ent->entry.etypes->len++;
1148c19800e8SDoug Rabson 	}
1149c19800e8SDoug Rabson     }
1150c19800e8SDoug Rabson 
1151c19800e8SDoug Rabson     ret = LDAP_get_generalized_time_value(db, msg, "createTimestamp",
1152c19800e8SDoug Rabson 					  &ent->entry.created_by.time);
1153c19800e8SDoug Rabson     if (ret)
1154c19800e8SDoug Rabson 	ent->entry.created_by.time = time(NULL);
1155c19800e8SDoug Rabson 
1156c19800e8SDoug Rabson     ent->entry.created_by.principal = NULL;
11575e9cd1aeSAssar Westerlund 
1158ae771770SStanislav Sedov     if (flags & HDB_F_ADMIN_DATA) {
11595e9cd1aeSAssar Westerlund 	ret = LDAP_get_string_value(db, msg, "creatorsName", &dn);
11605e9cd1aeSAssar Westerlund 	if (ret == 0) {
1161ae771770SStanislav Sedov 	    LDAP_dn2principal(context, db, dn, &ent->entry.created_by.principal);
11625e9cd1aeSAssar Westerlund 	    free(dn);
11635e9cd1aeSAssar Westerlund 	}
11645e9cd1aeSAssar Westerlund 
1165ae771770SStanislav Sedov 	ent->entry.modified_by = calloc(1, sizeof(*ent->entry.modified_by));
1166c19800e8SDoug Rabson 	if (ent->entry.modified_by == NULL) {
11675e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
1168ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
11695e9cd1aeSAssar Westerlund 	    goto out;
11705e9cd1aeSAssar Westerlund 	}
1171ae771770SStanislav Sedov 
1172c19800e8SDoug Rabson 	ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp",
1173c19800e8SDoug Rabson 					      &ent->entry.modified_by->time);
11745e9cd1aeSAssar Westerlund 	if (ret == 0) {
11755e9cd1aeSAssar Westerlund 	    ret = LDAP_get_string_value(db, msg, "modifiersName", &dn);
1176ae771770SStanislav Sedov 	    if (ret == 0) {
1177ae771770SStanislav Sedov 		LDAP_dn2principal(context, db, dn, &ent->entry.modified_by->principal);
11785e9cd1aeSAssar Westerlund 		free(dn);
11795e9cd1aeSAssar Westerlund 	    } else {
1180c19800e8SDoug Rabson 		free(ent->entry.modified_by);
1181c19800e8SDoug Rabson 		ent->entry.modified_by = NULL;
11825e9cd1aeSAssar Westerlund 	    }
1183ae771770SStanislav Sedov 	}
1184ae771770SStanislav Sedov     }
11855e9cd1aeSAssar Westerlund 
1186c19800e8SDoug Rabson     ent->entry.valid_start = malloc(sizeof(*ent->entry.valid_start));
1187c19800e8SDoug Rabson     if (ent->entry.valid_start == NULL) {
11885e9cd1aeSAssar Westerlund 	ret = ENOMEM;
1189ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "malloc: out of memory");
11905e9cd1aeSAssar Westerlund 	goto out;
11915e9cd1aeSAssar Westerlund     }
1192c19800e8SDoug Rabson     ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart",
1193c19800e8SDoug Rabson 					  ent->entry.valid_start);
1194c19800e8SDoug Rabson     if (ret) {
11955e9cd1aeSAssar Westerlund 	/* OPTIONAL */
1196c19800e8SDoug Rabson 	free(ent->entry.valid_start);
1197c19800e8SDoug Rabson 	ent->entry.valid_start = NULL;
11985e9cd1aeSAssar Westerlund     }
11995e9cd1aeSAssar Westerlund 
1200c19800e8SDoug Rabson     ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end));
1201c19800e8SDoug Rabson     if (ent->entry.valid_end == NULL) {
12024137ff4cSJacques Vidrine 	ret = ENOMEM;
1203ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "malloc: out of memory");
12045e9cd1aeSAssar Westerlund 	goto out;
12055e9cd1aeSAssar Westerlund     }
1206c19800e8SDoug Rabson     ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd",
1207c19800e8SDoug Rabson 					  ent->entry.valid_end);
1208c19800e8SDoug Rabson     if (ret) {
12095e9cd1aeSAssar Westerlund 	/* OPTIONAL */
1210c19800e8SDoug Rabson 	free(ent->entry.valid_end);
1211c19800e8SDoug Rabson 	ent->entry.valid_end = NULL;
12125e9cd1aeSAssar Westerlund     }
12135e9cd1aeSAssar Westerlund 
1214c19800e8SDoug Rabson     ret = LDAP_get_integer_value(db, msg, "sambaKickoffTime", &tmp_time);
1215c19800e8SDoug Rabson     if (ret == 0) {
1216c19800e8SDoug Rabson  	if (ent->entry.valid_end == NULL) {
1217c19800e8SDoug Rabson  	    ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end));
1218c19800e8SDoug Rabson  	    if (ent->entry.valid_end == NULL) {
12194137ff4cSJacques Vidrine  		ret = ENOMEM;
1220ae771770SStanislav Sedov  		krb5_set_error_message(context, ret, "malloc: out of memory");
12215e9cd1aeSAssar Westerlund  		goto out;
12225e9cd1aeSAssar Westerlund  	    }
1223c19800e8SDoug Rabson  	}
1224c19800e8SDoug Rabson  	*ent->entry.valid_end = tmp_time;
1225c19800e8SDoug Rabson     }
1226c19800e8SDoug Rabson 
1227c19800e8SDoug Rabson     ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
1228c19800e8SDoug Rabson     if (ent->entry.pw_end == NULL) {
1229c19800e8SDoug Rabson 	ret = ENOMEM;
1230ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "malloc: out of memory");
1231c19800e8SDoug Rabson 	goto out;
1232c19800e8SDoug Rabson     }
1233c19800e8SDoug Rabson     ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd",
1234c19800e8SDoug Rabson 					  ent->entry.pw_end);
1235c19800e8SDoug Rabson     if (ret) {
12365e9cd1aeSAssar Westerlund 	/* OPTIONAL */
1237c19800e8SDoug Rabson 	free(ent->entry.pw_end);
1238c19800e8SDoug Rabson 	ent->entry.pw_end = NULL;
12395e9cd1aeSAssar Westerlund     }
12405e9cd1aeSAssar Westerlund 
1241ae771770SStanislav Sedov     ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time);
1242ae771770SStanislav Sedov     if (ret == 0) {
1243ae771770SStanislav Sedov 	time_t delta;
1244ae771770SStanislav Sedov 
1245ae771770SStanislav Sedov 	if (ent->entry.pw_end == NULL) {
1246ae771770SStanislav Sedov             ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
1247ae771770SStanislav Sedov             if (ent->entry.pw_end == NULL) {
1248ae771770SStanislav Sedov                 ret = ENOMEM;
1249ae771770SStanislav Sedov                 krb5_set_error_message(context, ret, "malloc: out of memory");
1250ae771770SStanislav Sedov                 goto out;
1251ae771770SStanislav Sedov             }
1252ae771770SStanislav Sedov         }
1253ae771770SStanislav Sedov 
1254ae771770SStanislav Sedov 	delta = krb5_config_get_time_default(context, NULL,
1255ae771770SStanislav Sedov 					     365 * 24 * 60 * 60,
1256ae771770SStanislav Sedov 					     "kadmin",
1257ae771770SStanislav Sedov 					     "password_lifetime",
1258ae771770SStanislav Sedov 					     NULL);
1259ae771770SStanislav Sedov         *ent->entry.pw_end = tmp_time + delta;
1260ae771770SStanislav Sedov     }
1261ae771770SStanislav Sedov 
1262c19800e8SDoug Rabson     ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time);
1263c19800e8SDoug Rabson     if (ret == 0) {
1264c19800e8SDoug Rabson 	if (ent->entry.pw_end == NULL) {
1265c19800e8SDoug Rabson 	    ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
1266c19800e8SDoug Rabson 	    if (ent->entry.pw_end == NULL) {
12675e9cd1aeSAssar Westerlund 		ret = ENOMEM;
1268ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, "malloc: out of memory");
12695e9cd1aeSAssar Westerlund 		goto out;
12705e9cd1aeSAssar Westerlund 	    }
1271c19800e8SDoug Rabson 	}
1272c19800e8SDoug Rabson 	*ent->entry.pw_end = tmp_time;
12735e9cd1aeSAssar Westerlund     }
12745e9cd1aeSAssar Westerlund 
1275c19800e8SDoug Rabson     /* OPTIONAL */
1276c19800e8SDoug Rabson     ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time);
1277c19800e8SDoug Rabson     if (ret == 0)
1278c19800e8SDoug Rabson 	hdb_entry_set_pw_change_time(context, &ent->entry, tmp_time);
1279c19800e8SDoug Rabson 
1280c19800e8SDoug Rabson     {
1281c19800e8SDoug Rabson 	int max_life;
1282c19800e8SDoug Rabson 
1283c19800e8SDoug Rabson 	ent->entry.max_life = malloc(sizeof(*ent->entry.max_life));
1284c19800e8SDoug Rabson 	if (ent->entry.max_life == NULL) {
12855e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
1286ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
12875e9cd1aeSAssar Westerlund 	    goto out;
12885e9cd1aeSAssar Westerlund 	}
1289c19800e8SDoug Rabson 	ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", &max_life);
1290c19800e8SDoug Rabson 	if (ret) {
1291c19800e8SDoug Rabson 	    free(ent->entry.max_life);
1292c19800e8SDoug Rabson 	    ent->entry.max_life = NULL;
1293c19800e8SDoug Rabson 	} else
1294c19800e8SDoug Rabson 	    *ent->entry.max_life = max_life;
12955e9cd1aeSAssar Westerlund     }
12965e9cd1aeSAssar Westerlund 
1297c19800e8SDoug Rabson     {
1298c19800e8SDoug Rabson 	int max_renew;
1299c19800e8SDoug Rabson 
1300c19800e8SDoug Rabson 	ent->entry.max_renew = malloc(sizeof(*ent->entry.max_renew));
1301c19800e8SDoug Rabson 	if (ent->entry.max_renew == NULL) {
1302c19800e8SDoug Rabson 	    ret = ENOMEM;
1303ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1304c19800e8SDoug Rabson 	    goto out;
1305c19800e8SDoug Rabson 	}
1306c19800e8SDoug Rabson 	ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", &max_renew);
1307c19800e8SDoug Rabson 	if (ret) {
1308c19800e8SDoug Rabson 	    free(ent->entry.max_renew);
1309c19800e8SDoug Rabson 	    ent->entry.max_renew = NULL;
1310c19800e8SDoug Rabson 	} else
1311c19800e8SDoug Rabson 	    *ent->entry.max_renew = max_renew;
1312c19800e8SDoug Rabson     }
1313c19800e8SDoug Rabson 
1314ae771770SStanislav Sedov     ret = LDAP_get_integer_value(db, msg, "krb5KDCFlags", &tmp);
1315ae771770SStanislav Sedov     if (ret)
13165e9cd1aeSAssar Westerlund 	tmp = 0;
13175e9cd1aeSAssar Westerlund 
1318c19800e8SDoug Rabson     ent->entry.flags = int2HDBFlags(tmp);
1319c19800e8SDoug Rabson 
1320c19800e8SDoug Rabson     /* Try and find Samba flags to put into the mix */
1321c19800e8SDoug Rabson     ret = LDAP_get_string_value(db, msg, "sambaAcctFlags", &samba_acct_flags);
1322c19800e8SDoug Rabson     if (ret == 0) {
1323c19800e8SDoug Rabson 	/* parse the [UXW...] string:
1324c19800e8SDoug Rabson 
1325c19800e8SDoug Rabson 	   'N'    No password
1326c19800e8SDoug Rabson 	   'D'    Disabled
1327c19800e8SDoug Rabson 	   'H'    Homedir required
1328c19800e8SDoug Rabson 	   'T'    Temp account.
1329c19800e8SDoug Rabson 	   'U'    User account (normal)
1330c19800e8SDoug Rabson 	   'M'    MNS logon user account - what is this ?
1331c19800e8SDoug Rabson 	   'W'    Workstation account
1332c19800e8SDoug Rabson 	   'S'    Server account
1333c19800e8SDoug Rabson 	   'L'    Locked account
1334c19800e8SDoug Rabson 	   'X'    No Xpiry on password
1335c19800e8SDoug Rabson 	   'I'    Interdomain trust account
1336c19800e8SDoug Rabson 
1337c19800e8SDoug Rabson 	*/
1338c19800e8SDoug Rabson 
13395e9cd1aeSAssar Westerlund 	int i;
1340c19800e8SDoug Rabson 	int flags_len = strlen(samba_acct_flags);
13415e9cd1aeSAssar Westerlund 
1342c19800e8SDoug Rabson 	if (flags_len < 2)
1343c19800e8SDoug Rabson 	    goto out2;
1344c19800e8SDoug Rabson 
1345c19800e8SDoug Rabson 	if (samba_acct_flags[0] != '['
1346c19800e8SDoug Rabson 	    || samba_acct_flags[flags_len - 1] != ']')
1347c19800e8SDoug Rabson 	    goto out2;
1348c19800e8SDoug Rabson 
1349c19800e8SDoug Rabson 	/* Allow forwarding */
1350c19800e8SDoug Rabson 	if (samba_forwardable)
1351c19800e8SDoug Rabson 	    ent->entry.flags.forwardable = TRUE;
1352c19800e8SDoug Rabson 
1353c19800e8SDoug Rabson 	for (i=0; i < flags_len; i++) {
1354c19800e8SDoug Rabson 	    switch (samba_acct_flags[i]) {
1355c19800e8SDoug Rabson 	    case ' ':
1356c19800e8SDoug Rabson 	    case '[':
1357c19800e8SDoug Rabson 	    case ']':
1358c19800e8SDoug Rabson 		break;
1359c19800e8SDoug Rabson 	    case 'N':
1360c19800e8SDoug Rabson 		/* how to handle no password in kerberos? */
1361c19800e8SDoug Rabson 		break;
1362c19800e8SDoug Rabson 	    case 'D':
1363c19800e8SDoug Rabson 		ent->entry.flags.invalid = TRUE;
1364c19800e8SDoug Rabson 		break;
1365c19800e8SDoug Rabson 	    case 'H':
1366c19800e8SDoug Rabson 		break;
1367c19800e8SDoug Rabson 	    case 'T':
1368c19800e8SDoug Rabson 		/* temp duplicate */
1369c19800e8SDoug Rabson 		ent->entry.flags.invalid = TRUE;
1370c19800e8SDoug Rabson 		break;
1371c19800e8SDoug Rabson 	    case 'U':
1372c19800e8SDoug Rabson 		ent->entry.flags.client = TRUE;
1373c19800e8SDoug Rabson 		break;
1374c19800e8SDoug Rabson 	    case 'M':
1375c19800e8SDoug Rabson 		break;
1376c19800e8SDoug Rabson 	    case 'W':
1377c19800e8SDoug Rabson 	    case 'S':
1378c19800e8SDoug Rabson 		ent->entry.flags.server = TRUE;
1379c19800e8SDoug Rabson 		ent->entry.flags.client = TRUE;
1380c19800e8SDoug Rabson 		break;
1381c19800e8SDoug Rabson 	    case 'L':
1382c19800e8SDoug Rabson 		ent->entry.flags.invalid = TRUE;
1383c19800e8SDoug Rabson 		break;
1384c19800e8SDoug Rabson 	    case 'X':
1385c19800e8SDoug Rabson 		if (ent->entry.pw_end) {
1386c19800e8SDoug Rabson 		    free(ent->entry.pw_end);
1387c19800e8SDoug Rabson 		    ent->entry.pw_end = NULL;
13885e9cd1aeSAssar Westerlund 		}
1389c19800e8SDoug Rabson 		break;
1390c19800e8SDoug Rabson 	    case 'I':
1391c19800e8SDoug Rabson 		ent->entry.flags.server = TRUE;
1392c19800e8SDoug Rabson 		ent->entry.flags.client = TRUE;
1393c19800e8SDoug Rabson 		break;
13945e9cd1aeSAssar Westerlund 	    }
1395c19800e8SDoug Rabson 	}
1396c19800e8SDoug Rabson     out2:
1397c19800e8SDoug Rabson 	free(samba_acct_flags);
13985e9cd1aeSAssar Westerlund     }
13995e9cd1aeSAssar Westerlund 
14005e9cd1aeSAssar Westerlund     ret = 0;
14015e9cd1aeSAssar Westerlund 
14025e9cd1aeSAssar Westerlund out:
1403c19800e8SDoug Rabson     if (unparsed_name)
14045e9cd1aeSAssar Westerlund 	free(unparsed_name);
14055e9cd1aeSAssar Westerlund 
1406c19800e8SDoug Rabson     if (ret)
14075e9cd1aeSAssar Westerlund 	hdb_free_entry(context, ent);
14085e9cd1aeSAssar Westerlund 
14095e9cd1aeSAssar Westerlund     return ret;
14105e9cd1aeSAssar Westerlund }
14115e9cd1aeSAssar Westerlund 
1412c19800e8SDoug Rabson static krb5_error_code
1413c19800e8SDoug Rabson LDAP_close(krb5_context context, HDB * db)
14145e9cd1aeSAssar Westerlund {
1415c19800e8SDoug Rabson     if (HDB2LDAP(db)) {
1416c19800e8SDoug Rabson 	ldap_unbind_ext(HDB2LDAP(db), NULL, NULL);
1417c19800e8SDoug Rabson 	((struct hdbldapdb *)db->hdb_db)->h_lp = NULL;
1418c19800e8SDoug Rabson     }
14194137ff4cSJacques Vidrine 
14205e9cd1aeSAssar Westerlund     return 0;
14215e9cd1aeSAssar Westerlund }
14225e9cd1aeSAssar Westerlund 
14235e9cd1aeSAssar Westerlund static krb5_error_code
14245e9cd1aeSAssar Westerlund LDAP_lock(krb5_context context, HDB * db, int operation)
14255e9cd1aeSAssar Westerlund {
14265e9cd1aeSAssar Westerlund     return 0;
14275e9cd1aeSAssar Westerlund }
14285e9cd1aeSAssar Westerlund 
1429c19800e8SDoug Rabson static krb5_error_code
1430c19800e8SDoug Rabson LDAP_unlock(krb5_context context, HDB * db)
14315e9cd1aeSAssar Westerlund {
14325e9cd1aeSAssar Westerlund     return 0;
14335e9cd1aeSAssar Westerlund }
14345e9cd1aeSAssar Westerlund 
14355e9cd1aeSAssar Westerlund static krb5_error_code
1436c19800e8SDoug Rabson LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry)
14375e9cd1aeSAssar Westerlund {
14385e9cd1aeSAssar Westerlund     int msgid, rc, parserc;
14395e9cd1aeSAssar Westerlund     krb5_error_code ret;
14405e9cd1aeSAssar Westerlund     LDAPMessage *e;
14415e9cd1aeSAssar Westerlund 
1442c19800e8SDoug Rabson     msgid = HDB2MSGID(db);
1443c19800e8SDoug Rabson     if (msgid < 0)
14445e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
14455e9cd1aeSAssar Westerlund 
14465e9cd1aeSAssar Westerlund     do {
1447c19800e8SDoug Rabson 	rc = ldap_result(HDB2LDAP(db), msgid, LDAP_MSG_ONE, NULL, &e);
14485e9cd1aeSAssar Westerlund 	switch (rc) {
1449c19800e8SDoug Rabson 	case LDAP_RES_SEARCH_REFERENCE:
1450c19800e8SDoug Rabson 	    ldap_msgfree(e);
1451c19800e8SDoug Rabson 	    ret = 0;
1452c19800e8SDoug Rabson 	    break;
14535e9cd1aeSAssar Westerlund 	case LDAP_RES_SEARCH_ENTRY:
14545e9cd1aeSAssar Westerlund 	    /* We have an entry. Parse it. */
1455ae771770SStanislav Sedov 	    ret = LDAP_message2entry(context, db, e, flags, entry);
14565e9cd1aeSAssar Westerlund 	    ldap_msgfree(e);
14575e9cd1aeSAssar Westerlund 	    break;
14585e9cd1aeSAssar Westerlund 	case LDAP_RES_SEARCH_RESULT:
14595e9cd1aeSAssar Westerlund 	    /* We're probably at the end of the results. If not, abandon. */
14605e9cd1aeSAssar Westerlund 	    parserc =
1461c19800e8SDoug Rabson 		ldap_parse_result(HDB2LDAP(db), e, NULL, NULL, NULL,
14625e9cd1aeSAssar Westerlund 				  NULL, NULL, 1);
1463ae771770SStanislav Sedov 	    ret = HDB_ERR_NOENTRY;
14645e9cd1aeSAssar Westerlund 	    if (parserc != LDAP_SUCCESS
14655e9cd1aeSAssar Westerlund 		&& parserc != LDAP_MORE_RESULTS_TO_RETURN) {
1466ae771770SStanislav Sedov 	        krb5_set_error_message(context, ret, "ldap_parse_result: %s",
1467c19800e8SDoug Rabson 				       ldap_err2string(parserc));
1468ae771770SStanislav Sedov 		ldap_abandon_ext(HDB2LDAP(db), msgid, NULL, NULL);
14695e9cd1aeSAssar Westerlund 	    }
1470c19800e8SDoug Rabson 	    HDBSETMSGID(db, -1);
14715e9cd1aeSAssar Westerlund 	    break;
1472c19800e8SDoug Rabson 	case LDAP_SERVER_DOWN:
1473c19800e8SDoug Rabson 	    ldap_msgfree(e);
1474c19800e8SDoug Rabson 	    LDAP_close(context, db);
1475c19800e8SDoug Rabson 	    HDBSETMSGID(db, -1);
1476c19800e8SDoug Rabson 	    ret = ENETDOWN;
1477c19800e8SDoug Rabson 	    break;
14785e9cd1aeSAssar Westerlund 	default:
14795e9cd1aeSAssar Westerlund 	    /* Some unspecified error (timeout?). Abandon. */
14805e9cd1aeSAssar Westerlund 	    ldap_msgfree(e);
1481ae771770SStanislav Sedov 	    ldap_abandon_ext(HDB2LDAP(db), msgid, NULL, NULL);
14825e9cd1aeSAssar Westerlund 	    ret = HDB_ERR_NOENTRY;
1483c19800e8SDoug Rabson 	    HDBSETMSGID(db, -1);
14845e9cd1aeSAssar Westerlund 	    break;
14855e9cd1aeSAssar Westerlund 	}
14865e9cd1aeSAssar Westerlund     } while (rc == LDAP_RES_SEARCH_REFERENCE);
14875e9cd1aeSAssar Westerlund 
14885e9cd1aeSAssar Westerlund     if (ret == 0) {
1489c19800e8SDoug Rabson 	if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
1490c19800e8SDoug Rabson 	    ret = hdb_unseal_keys(context, db, &entry->entry);
14915e9cd1aeSAssar Westerlund 	    if (ret)
14925e9cd1aeSAssar Westerlund 		hdb_free_entry(context, entry);
14935e9cd1aeSAssar Westerlund 	}
14945e9cd1aeSAssar Westerlund     }
14955e9cd1aeSAssar Westerlund 
14965e9cd1aeSAssar Westerlund     return ret;
14975e9cd1aeSAssar Westerlund }
14985e9cd1aeSAssar Westerlund 
14995e9cd1aeSAssar Westerlund static krb5_error_code
15005e9cd1aeSAssar Westerlund LDAP_firstkey(krb5_context context, HDB *db, unsigned flags,
1501c19800e8SDoug Rabson 	      hdb_entry_ex *entry)
15025e9cd1aeSAssar Westerlund {
1503c19800e8SDoug Rabson     krb5_error_code ret;
1504c19800e8SDoug Rabson     int msgid;
15055e9cd1aeSAssar Westerlund 
1506c19800e8SDoug Rabson     ret = LDAP__connect(context, db);
1507c19800e8SDoug Rabson     if (ret)
1508c19800e8SDoug Rabson 	return ret;
15095e9cd1aeSAssar Westerlund 
1510c19800e8SDoug Rabson     ret = LDAP_no_size_limit(context, HDB2LDAP(db));
1511c19800e8SDoug Rabson     if (ret)
1512c19800e8SDoug Rabson 	return ret;
15135e9cd1aeSAssar Westerlund 
1514ae771770SStanislav Sedov     ret = ldap_search_ext(HDB2LDAP(db), HDB2BASE(db),
1515c19800e8SDoug Rabson 			LDAP_SCOPE_SUBTREE,
1516c19800e8SDoug Rabson 			"(|(objectClass=krb5Principal)(objectClass=sambaSamAccount))",
1517ae771770SStanislav Sedov 			krb5kdcentry_attrs, 0,
1518ae771770SStanislav Sedov 			NULL, NULL, NULL, 0, &msgid);
1519c19800e8SDoug Rabson     if (msgid < 0)
15205e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
15215e9cd1aeSAssar Westerlund 
1522c19800e8SDoug Rabson     HDBSETMSGID(db, msgid);
15235e9cd1aeSAssar Westerlund 
15245e9cd1aeSAssar Westerlund     return LDAP_seq(context, db, flags, entry);
15255e9cd1aeSAssar Westerlund }
15265e9cd1aeSAssar Westerlund 
15275e9cd1aeSAssar Westerlund static krb5_error_code
15285e9cd1aeSAssar Westerlund LDAP_nextkey(krb5_context context, HDB * db, unsigned flags,
1529c19800e8SDoug Rabson 	     hdb_entry_ex * entry)
15305e9cd1aeSAssar Westerlund {
15315e9cd1aeSAssar Westerlund     return LDAP_seq(context, db, flags, entry);
15325e9cd1aeSAssar Westerlund }
15335e9cd1aeSAssar Westerlund 
15345e9cd1aeSAssar Westerlund static krb5_error_code
1535c19800e8SDoug Rabson LDAP__connect(krb5_context context, HDB * db)
15365e9cd1aeSAssar Westerlund {
15374137ff4cSJacques Vidrine     int rc, version = LDAP_VERSION3;
15381c43270aSJacques Vidrine     /*
15391c43270aSJacques Vidrine      * Empty credentials to do a SASL bind with LDAP. Note that empty
15401c43270aSJacques Vidrine      * different from NULL credentials. If you provide NULL
15411c43270aSJacques Vidrine      * credentials instead of empty credentials you will get a SASL
15421c43270aSJacques Vidrine      * bind in progress message.
15431c43270aSJacques Vidrine      */
15441c43270aSJacques Vidrine     struct berval bv = { 0, "" };
15455e9cd1aeSAssar Westerlund 
1546c19800e8SDoug Rabson     if (HDB2LDAP(db)) {
15475e9cd1aeSAssar Westerlund 	/* connection has been opened. ping server. */
15485e9cd1aeSAssar Westerlund 	struct sockaddr_un addr;
1549c19800e8SDoug Rabson 	socklen_t len = sizeof(addr);
15505e9cd1aeSAssar Westerlund 	int sd;
15515e9cd1aeSAssar Westerlund 
1552c19800e8SDoug Rabson 	if (ldap_get_option(HDB2LDAP(db), LDAP_OPT_DESC, &sd) == 0 &&
15535e9cd1aeSAssar Westerlund 	    getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
15545e9cd1aeSAssar Westerlund 	    /* the other end has died. reopen. */
15555e9cd1aeSAssar Westerlund 	    LDAP_close(context, db);
15565e9cd1aeSAssar Westerlund 	}
15575e9cd1aeSAssar Westerlund     }
15585e9cd1aeSAssar Westerlund 
1559c19800e8SDoug Rabson     if (HDB2LDAP(db) != NULL) /* server is UP */
15605e9cd1aeSAssar Westerlund 	return 0;
15615e9cd1aeSAssar Westerlund 
1562c19800e8SDoug Rabson     rc = ldap_initialize(&((struct hdbldapdb *)db->hdb_db)->h_lp, HDB2URL(db));
15635e9cd1aeSAssar Westerlund     if (rc != LDAP_SUCCESS) {
1564ae771770SStanislav Sedov 	krb5_set_error_message(context, HDB_ERR_NOENTRY, "ldap_initialize: %s",
1565c19800e8SDoug Rabson 			       ldap_err2string(rc));
15665e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
15675e9cd1aeSAssar Westerlund     }
15685e9cd1aeSAssar Westerlund 
1569c19800e8SDoug Rabson     rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_PROTOCOL_VERSION,
1570c19800e8SDoug Rabson 			 (const void *)&version);
15715e9cd1aeSAssar Westerlund     if (rc != LDAP_SUCCESS) {
1572ae771770SStanislav Sedov 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
1573ae771770SStanislav Sedov 			       "ldap_set_option: %s", ldap_err2string(rc));
1574c19800e8SDoug Rabson 	LDAP_close(context, db);
15754137ff4cSJacques Vidrine 	return HDB_ERR_BADVERSION;
15765e9cd1aeSAssar Westerlund     }
15775e9cd1aeSAssar Westerlund 
1578c19800e8SDoug Rabson     rc = ldap_sasl_bind_s(HDB2LDAP(db), NULL, "EXTERNAL", &bv,
1579c19800e8SDoug Rabson 			  NULL, NULL, NULL);
15801c43270aSJacques Vidrine     if (rc != LDAP_SUCCESS) {
1581ae771770SStanislav Sedov 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
1582ae771770SStanislav Sedov 			      "ldap_sasl_bind_s: %s", ldap_err2string(rc));
1583c19800e8SDoug Rabson 	LDAP_close(context, db);
15841c43270aSJacques Vidrine 	return HDB_ERR_BADVERSION;
15851c43270aSJacques Vidrine     }
15861c43270aSJacques Vidrine 
15874137ff4cSJacques Vidrine     return 0;
15885e9cd1aeSAssar Westerlund }
15895e9cd1aeSAssar Westerlund 
15905e9cd1aeSAssar Westerlund static krb5_error_code
15915e9cd1aeSAssar Westerlund LDAP_open(krb5_context context, HDB * db, int flags, mode_t mode)
15925e9cd1aeSAssar Westerlund {
15935e9cd1aeSAssar Westerlund     /* Not the right place for this. */
15945e9cd1aeSAssar Westerlund #ifdef HAVE_SIGACTION
15955e9cd1aeSAssar Westerlund     struct sigaction sa;
15965e9cd1aeSAssar Westerlund 
15975e9cd1aeSAssar Westerlund     sa.sa_flags = 0;
15985e9cd1aeSAssar Westerlund     sa.sa_handler = SIG_IGN;
15995e9cd1aeSAssar Westerlund     sigemptyset(&sa.sa_mask);
16005e9cd1aeSAssar Westerlund 
16015e9cd1aeSAssar Westerlund     sigaction(SIGPIPE, &sa, NULL);
16025e9cd1aeSAssar Westerlund #else
16035e9cd1aeSAssar Westerlund     signal(SIGPIPE, SIG_IGN);
16044137ff4cSJacques Vidrine #endif /* HAVE_SIGACTION */
16055e9cd1aeSAssar Westerlund 
16064137ff4cSJacques Vidrine     return LDAP__connect(context, db);
16075e9cd1aeSAssar Westerlund }
16085e9cd1aeSAssar Westerlund 
16095e9cd1aeSAssar Westerlund static krb5_error_code
1610ae771770SStanislav Sedov LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
1611ae771770SStanislav Sedov 		unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry)
16125e9cd1aeSAssar Westerlund {
16135e9cd1aeSAssar Westerlund     LDAPMessage *msg, *e;
16145e9cd1aeSAssar Westerlund     krb5_error_code ret;
16155e9cd1aeSAssar Westerlund 
1616c19800e8SDoug Rabson     ret = LDAP_principal2message(context, db, principal, &msg);
1617c19800e8SDoug Rabson     if (ret)
16185e9cd1aeSAssar Westerlund 	return ret;
16195e9cd1aeSAssar Westerlund 
1620c19800e8SDoug Rabson     e = ldap_first_entry(HDB2LDAP(db), msg);
16215e9cd1aeSAssar Westerlund     if (e == NULL) {
16225e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
16235e9cd1aeSAssar Westerlund 	goto out;
16245e9cd1aeSAssar Westerlund     }
16255e9cd1aeSAssar Westerlund 
1626ae771770SStanislav Sedov     ret = LDAP_message2entry(context, db, e, flags, entry);
16275e9cd1aeSAssar Westerlund     if (ret == 0) {
1628c19800e8SDoug Rabson 	if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
1629c19800e8SDoug Rabson 	    ret = hdb_unseal_keys(context, db, &entry->entry);
16305e9cd1aeSAssar Westerlund 	    if (ret)
16315e9cd1aeSAssar Westerlund 		hdb_free_entry(context, entry);
16325e9cd1aeSAssar Westerlund 	}
16335e9cd1aeSAssar Westerlund     }
16345e9cd1aeSAssar Westerlund 
16355e9cd1aeSAssar Westerlund   out:
16365e9cd1aeSAssar Westerlund     ldap_msgfree(msg);
16375e9cd1aeSAssar Westerlund 
16385e9cd1aeSAssar Westerlund     return ret;
16395e9cd1aeSAssar Westerlund }
16405e9cd1aeSAssar Westerlund 
16415e9cd1aeSAssar Westerlund static krb5_error_code
1642ae771770SStanislav Sedov LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal,
1643ae771770SStanislav Sedov 	   unsigned flags, hdb_entry_ex * entry)
1644ae771770SStanislav Sedov {
1645ae771770SStanislav Sedov     return LDAP_fetch_kvno(context, db, principal,
1646ae771770SStanislav Sedov 			   flags & (~HDB_F_KVNO_SPECIFIED), 0, entry);
1647ae771770SStanislav Sedov }
1648ae771770SStanislav Sedov 
1649ae771770SStanislav Sedov static krb5_error_code
16505e9cd1aeSAssar Westerlund LDAP_store(krb5_context context, HDB * db, unsigned flags,
1651c19800e8SDoug Rabson 	   hdb_entry_ex * entry)
16525e9cd1aeSAssar Westerlund {
16535e9cd1aeSAssar Westerlund     LDAPMod **mods = NULL;
16545e9cd1aeSAssar Westerlund     krb5_error_code ret;
16554137ff4cSJacques Vidrine     const char *errfn;
16564137ff4cSJacques Vidrine     int rc;
16575e9cd1aeSAssar Westerlund     LDAPMessage *msg = NULL, *e = NULL;
16585e9cd1aeSAssar Westerlund     char *dn = NULL, *name = NULL;
16595e9cd1aeSAssar Westerlund 
1660c19800e8SDoug Rabson     ret = LDAP_principal2message(context, db, entry->entry.principal, &msg);
1661c19800e8SDoug Rabson     if (ret == 0)
1662c19800e8SDoug Rabson 	e = ldap_first_entry(HDB2LDAP(db), msg);
1663c19800e8SDoug Rabson 
1664c19800e8SDoug Rabson     ret = krb5_unparse_name(context, entry->entry.principal, &name);
1665c19800e8SDoug Rabson     if (ret) {
1666c19800e8SDoug Rabson 	free(name);
1667c19800e8SDoug Rabson 	return ret;
16685e9cd1aeSAssar Westerlund     }
16695e9cd1aeSAssar Westerlund 
1670c19800e8SDoug Rabson     ret = hdb_seal_keys(context, db, &entry->entry);
1671c19800e8SDoug Rabson     if (ret)
16725e9cd1aeSAssar Westerlund 	goto out;
16735e9cd1aeSAssar Westerlund 
16745e9cd1aeSAssar Westerlund     /* turn new entry into LDAPMod array */
16755e9cd1aeSAssar Westerlund     ret = LDAP_entry2mods(context, db, entry, e, &mods);
1676c19800e8SDoug Rabson     if (ret)
16775e9cd1aeSAssar Westerlund 	goto out;
16785e9cd1aeSAssar Westerlund 
16795e9cd1aeSAssar Westerlund     if (e == NULL) {
1680c19800e8SDoug Rabson 	ret = asprintf(&dn, "krb5PrincipalName=%s,%s", name, HDB2CREATE(db));
16815e9cd1aeSAssar Westerlund 	if (ret < 0) {
16825e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
1683ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "asprintf: out of memory");
16845e9cd1aeSAssar Westerlund 	    goto out;
16855e9cd1aeSAssar Westerlund 	}
16865e9cd1aeSAssar Westerlund     } else if (flags & HDB_F_REPLACE) {
16875e9cd1aeSAssar Westerlund 	/* Entry exists, and we're allowed to replace it. */
1688c19800e8SDoug Rabson 	dn = ldap_get_dn(HDB2LDAP(db), e);
16895e9cd1aeSAssar Westerlund     } else {
16905e9cd1aeSAssar Westerlund 	/* Entry exists, but we're not allowed to replace it. Bail. */
16915e9cd1aeSAssar Westerlund 	ret = HDB_ERR_EXISTS;
16925e9cd1aeSAssar Westerlund 	goto out;
16935e9cd1aeSAssar Westerlund     }
16945e9cd1aeSAssar Westerlund 
16955e9cd1aeSAssar Westerlund     /* write entry into directory */
16965e9cd1aeSAssar Westerlund     if (e == NULL) {
16975e9cd1aeSAssar Westerlund 	/* didn't exist before */
1698ae771770SStanislav Sedov 	rc = ldap_add_ext_s(HDB2LDAP(db), dn, mods, NULL, NULL );
1699ae771770SStanislav Sedov 	errfn = "ldap_add_ext_s";
17005e9cd1aeSAssar Westerlund     } else {
17015e9cd1aeSAssar Westerlund 	/* already existed, send deltas only */
1702ae771770SStanislav Sedov 	rc = ldap_modify_ext_s(HDB2LDAP(db), dn, mods, NULL, NULL );
1703ae771770SStanislav Sedov 	errfn = "ldap_modify_ext_s";
17045e9cd1aeSAssar Westerlund     }
17055e9cd1aeSAssar Westerlund 
1706c19800e8SDoug Rabson     if (check_ldap(context, db, rc)) {
1707c19800e8SDoug Rabson 	char *ld_error = NULL;
1708c19800e8SDoug Rabson 	ldap_get_option(HDB2LDAP(db), LDAP_OPT_ERROR_STRING,
1709c19800e8SDoug Rabson 			&ld_error);
17105e9cd1aeSAssar Westerlund 	ret = HDB_ERR_CANT_LOCK_DB;
1711ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "%s: %s (DN=%s) %s: %s",
1712ae771770SStanislav Sedov 			      errfn, name, dn, ldap_err2string(rc), ld_error);
1713c19800e8SDoug Rabson     } else
1714c19800e8SDoug Rabson 	ret = 0;
17155e9cd1aeSAssar Westerlund 
17165e9cd1aeSAssar Westerlund   out:
17175e9cd1aeSAssar Westerlund     /* free stuff */
1718c19800e8SDoug Rabson     if (dn)
17195e9cd1aeSAssar Westerlund 	free(dn);
1720c19800e8SDoug Rabson     if (msg)
17215e9cd1aeSAssar Westerlund 	ldap_msgfree(msg);
1722c19800e8SDoug Rabson     if (mods)
17235e9cd1aeSAssar Westerlund 	ldap_mods_free(mods, 1);
1724c19800e8SDoug Rabson     if (name)
17255e9cd1aeSAssar Westerlund 	free(name);
17265e9cd1aeSAssar Westerlund 
17275e9cd1aeSAssar Westerlund     return ret;
17285e9cd1aeSAssar Westerlund }
17295e9cd1aeSAssar Westerlund 
17305e9cd1aeSAssar Westerlund static krb5_error_code
1731c19800e8SDoug Rabson LDAP_remove(krb5_context context, HDB *db, krb5_const_principal principal)
17325e9cd1aeSAssar Westerlund {
17335e9cd1aeSAssar Westerlund     krb5_error_code ret;
17345e9cd1aeSAssar Westerlund     LDAPMessage *msg, *e;
17355e9cd1aeSAssar Westerlund     char *dn = NULL;
17364137ff4cSJacques Vidrine     int rc, limit = LDAP_NO_LIMIT;
17375e9cd1aeSAssar Westerlund 
1738c19800e8SDoug Rabson     ret = LDAP_principal2message(context, db, principal, &msg);
1739c19800e8SDoug Rabson     if (ret)
17405e9cd1aeSAssar Westerlund 	goto out;
17415e9cd1aeSAssar Westerlund 
1742c19800e8SDoug Rabson     e = ldap_first_entry(HDB2LDAP(db), msg);
17435e9cd1aeSAssar Westerlund     if (e == NULL) {
17445e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
17455e9cd1aeSAssar Westerlund 	goto out;
17465e9cd1aeSAssar Westerlund     }
17475e9cd1aeSAssar Westerlund 
1748c19800e8SDoug Rabson     dn = ldap_get_dn(HDB2LDAP(db), e);
17495e9cd1aeSAssar Westerlund     if (dn == NULL) {
17505e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
17515e9cd1aeSAssar Westerlund 	goto out;
17525e9cd1aeSAssar Westerlund     }
17535e9cd1aeSAssar Westerlund 
1754c19800e8SDoug Rabson     rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_SIZELIMIT, (const void *)&limit);
17554137ff4cSJacques Vidrine     if (rc != LDAP_SUCCESS) {
17564137ff4cSJacques Vidrine 	ret = HDB_ERR_BADVERSION;
1757ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "ldap_set_option: %s",
1758ae771770SStanislav Sedov 			      ldap_err2string(rc));
17594137ff4cSJacques Vidrine 	goto out;
17604137ff4cSJacques Vidrine     }
17615e9cd1aeSAssar Westerlund 
1762ae771770SStanislav Sedov     rc = ldap_delete_ext_s(HDB2LDAP(db), dn, NULL, NULL );
1763c19800e8SDoug Rabson     if (check_ldap(context, db, rc)) {
17645e9cd1aeSAssar Westerlund 	ret = HDB_ERR_CANT_LOCK_DB;
1765ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "ldap_delete_ext_s: %s",
1766ae771770SStanislav Sedov 			       ldap_err2string(rc));
1767c19800e8SDoug Rabson     } else
1768c19800e8SDoug Rabson 	ret = 0;
17695e9cd1aeSAssar Westerlund 
17705e9cd1aeSAssar Westerlund   out:
1771c19800e8SDoug Rabson     if (dn != NULL)
17725e9cd1aeSAssar Westerlund 	free(dn);
1773c19800e8SDoug Rabson     if (msg != NULL)
17745e9cd1aeSAssar Westerlund 	ldap_msgfree(msg);
17755e9cd1aeSAssar Westerlund 
17765e9cd1aeSAssar Westerlund     return ret;
17775e9cd1aeSAssar Westerlund }
17785e9cd1aeSAssar Westerlund 
17795e9cd1aeSAssar Westerlund static krb5_error_code
1780c19800e8SDoug Rabson LDAP_destroy(krb5_context context, HDB * db)
17815e9cd1aeSAssar Westerlund {
17825e9cd1aeSAssar Westerlund     krb5_error_code ret;
17835e9cd1aeSAssar Westerlund 
1784c19800e8SDoug Rabson     LDAP_close(context, db);
1785c19800e8SDoug Rabson 
17865e9cd1aeSAssar Westerlund     ret = hdb_clear_master_key(context, db);
1787c19800e8SDoug Rabson     if (HDB2BASE(db))
1788c19800e8SDoug Rabson 	free(HDB2BASE(db));
1789c19800e8SDoug Rabson     if (HDB2CREATE(db))
1790c19800e8SDoug Rabson 	free(HDB2CREATE(db));
1791c19800e8SDoug Rabson     if (HDB2URL(db))
1792c19800e8SDoug Rabson 	free(HDB2URL(db));
1793c19800e8SDoug Rabson     if (db->hdb_name)
1794c19800e8SDoug Rabson 	free(db->hdb_name);
1795c19800e8SDoug Rabson     free(db->hdb_db);
17965e9cd1aeSAssar Westerlund     free(db);
17975e9cd1aeSAssar Westerlund 
17985e9cd1aeSAssar Westerlund     return ret;
17995e9cd1aeSAssar Westerlund }
18005e9cd1aeSAssar Westerlund 
1801ae771770SStanislav Sedov static krb5_error_code
1802c19800e8SDoug Rabson hdb_ldap_common(krb5_context context,
1803c19800e8SDoug Rabson 		HDB ** db,
1804c19800e8SDoug Rabson 		const char *search_base,
1805c19800e8SDoug Rabson 		const char *url)
18065e9cd1aeSAssar Westerlund {
1807c19800e8SDoug Rabson     struct hdbldapdb *h;
1808c19800e8SDoug Rabson     const char *create_base = NULL;
1809c19800e8SDoug Rabson 
1810c19800e8SDoug Rabson     if (search_base == NULL && search_base[0] == '\0') {
1811ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "ldap search base not configured");
1812c19800e8SDoug Rabson 	return ENOMEM; /* XXX */
1813c19800e8SDoug Rabson     }
1814c19800e8SDoug Rabson 
1815c19800e8SDoug Rabson     if (structural_object == NULL) {
1816c19800e8SDoug Rabson 	const char *p;
1817c19800e8SDoug Rabson 
1818c19800e8SDoug Rabson 	p = krb5_config_get_string(context, NULL, "kdc",
1819c19800e8SDoug Rabson 				   "hdb-ldap-structural-object", NULL);
1820c19800e8SDoug Rabson 	if (p == NULL)
1821c19800e8SDoug Rabson 	    p = default_structural_object;
1822c19800e8SDoug Rabson 	structural_object = strdup(p);
1823c19800e8SDoug Rabson 	if (structural_object == NULL) {
1824ae771770SStanislav Sedov 	    krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1825c19800e8SDoug Rabson 	    return ENOMEM;
1826c19800e8SDoug Rabson 	}
1827c19800e8SDoug Rabson     }
1828c19800e8SDoug Rabson 
1829c19800e8SDoug Rabson     samba_forwardable =
1830c19800e8SDoug Rabson 	krb5_config_get_bool_default(context, NULL, TRUE,
1831c19800e8SDoug Rabson 				     "kdc", "hdb-samba-forwardable", NULL);
1832c19800e8SDoug Rabson 
1833c19800e8SDoug Rabson     *db = calloc(1, sizeof(**db));
18344137ff4cSJacques Vidrine     if (*db == NULL) {
1835ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
18365e9cd1aeSAssar Westerlund 	return ENOMEM;
18374137ff4cSJacques Vidrine     }
1838c19800e8SDoug Rabson     memset(*db, 0, sizeof(**db));
18395e9cd1aeSAssar Westerlund 
1840c19800e8SDoug Rabson     h = calloc(1, sizeof(*h));
1841c19800e8SDoug Rabson     if (h == NULL) {
18424137ff4cSJacques Vidrine 	free(*db);
18434137ff4cSJacques Vidrine 	*db = NULL;
1844ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
18454137ff4cSJacques Vidrine 	return ENOMEM;
18464137ff4cSJacques Vidrine     }
1847c19800e8SDoug Rabson     (*db)->hdb_db = h;
1848c19800e8SDoug Rabson 
1849c19800e8SDoug Rabson     /* XXX */
1850c19800e8SDoug Rabson     if (asprintf(&(*db)->hdb_name, "ldap:%s", search_base) == -1) {
1851c19800e8SDoug Rabson 	LDAP_destroy(context, *db);
1852c19800e8SDoug Rabson 	*db = NULL;
1853ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "strdup: out of memory");
1854c19800e8SDoug Rabson 	return ENOMEM;
18554137ff4cSJacques Vidrine     }
18564137ff4cSJacques Vidrine 
1857c19800e8SDoug Rabson     h->h_url = strdup(url);
1858c19800e8SDoug Rabson     h->h_base = strdup(search_base);
1859c19800e8SDoug Rabson     if (h->h_url == NULL || h->h_base == NULL) {
1860c19800e8SDoug Rabson 	LDAP_destroy(context, *db);
1861c19800e8SDoug Rabson 	*db = NULL;
1862ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "strdup: out of memory");
1863c19800e8SDoug Rabson 	return ENOMEM;
1864c19800e8SDoug Rabson     }
1865c19800e8SDoug Rabson 
1866c19800e8SDoug Rabson     create_base = krb5_config_get_string(context, NULL, "kdc",
1867c19800e8SDoug Rabson 					 "hdb-ldap-create-base", NULL);
1868c19800e8SDoug Rabson     if (create_base == NULL)
1869c19800e8SDoug Rabson 	create_base = h->h_base;
1870c19800e8SDoug Rabson 
1871c19800e8SDoug Rabson     h->h_createbase = strdup(create_base);
1872c19800e8SDoug Rabson     if (h->h_createbase == NULL) {
1873c19800e8SDoug Rabson 	LDAP_destroy(context, *db);
1874c19800e8SDoug Rabson 	*db = NULL;
1875ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "strdup: out of memory");
1876c19800e8SDoug Rabson 	return ENOMEM;
1877c19800e8SDoug Rabson     }
1878c19800e8SDoug Rabson 
1879c19800e8SDoug Rabson     (*db)->hdb_master_key_set = 0;
1880c19800e8SDoug Rabson     (*db)->hdb_openp = 0;
1881ae771770SStanislav Sedov     (*db)->hdb_capability_flags = 0;
1882c19800e8SDoug Rabson     (*db)->hdb_open = LDAP_open;
1883c19800e8SDoug Rabson     (*db)->hdb_close = LDAP_close;
1884ae771770SStanislav Sedov     (*db)->hdb_fetch_kvno = LDAP_fetch_kvno;
1885c19800e8SDoug Rabson     (*db)->hdb_store = LDAP_store;
1886c19800e8SDoug Rabson     (*db)->hdb_remove = LDAP_remove;
1887c19800e8SDoug Rabson     (*db)->hdb_firstkey = LDAP_firstkey;
1888c19800e8SDoug Rabson     (*db)->hdb_nextkey = LDAP_nextkey;
1889c19800e8SDoug Rabson     (*db)->hdb_lock = LDAP_lock;
1890c19800e8SDoug Rabson     (*db)->hdb_unlock = LDAP_unlock;
1891c19800e8SDoug Rabson     (*db)->hdb_rename = NULL;
1892c19800e8SDoug Rabson     (*db)->hdb__get = NULL;
1893c19800e8SDoug Rabson     (*db)->hdb__put = NULL;
1894c19800e8SDoug Rabson     (*db)->hdb__del = NULL;
1895c19800e8SDoug Rabson     (*db)->hdb_destroy = LDAP_destroy;
18965e9cd1aeSAssar Westerlund 
18975e9cd1aeSAssar Westerlund     return 0;
18985e9cd1aeSAssar Westerlund }
18995e9cd1aeSAssar Westerlund 
1900c19800e8SDoug Rabson krb5_error_code
1901c19800e8SDoug Rabson hdb_ldap_create(krb5_context context, HDB ** db, const char *arg)
1902c19800e8SDoug Rabson {
1903c19800e8SDoug Rabson     return hdb_ldap_common(context, db, arg, "ldapi:///");
1904c19800e8SDoug Rabson }
1905c19800e8SDoug Rabson 
1906c19800e8SDoug Rabson krb5_error_code
1907c19800e8SDoug Rabson hdb_ldapi_create(krb5_context context, HDB ** db, const char *arg)
1908c19800e8SDoug Rabson {
1909c19800e8SDoug Rabson     krb5_error_code ret;
1910c19800e8SDoug Rabson     char *search_base, *p;
1911c19800e8SDoug Rabson 
1912c19800e8SDoug Rabson     asprintf(&p, "ldapi:%s", arg);
1913c19800e8SDoug Rabson     if (p == NULL) {
1914c19800e8SDoug Rabson 	*db = NULL;
1915ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "out of memory");
1916c19800e8SDoug Rabson 	return ENOMEM;
1917c19800e8SDoug Rabson     }
1918c19800e8SDoug Rabson     search_base = strchr(p + strlen("ldapi://"), ':');
1919c19800e8SDoug Rabson     if (search_base == NULL) {
1920c19800e8SDoug Rabson 	*db = NULL;
1921ae771770SStanislav Sedov 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
1922ae771770SStanislav Sedov 			       "search base missing");
1923c19800e8SDoug Rabson 	return HDB_ERR_BADVERSION;
1924c19800e8SDoug Rabson     }
1925c19800e8SDoug Rabson     *search_base = '\0';
1926c19800e8SDoug Rabson     search_base++;
1927c19800e8SDoug Rabson 
1928c19800e8SDoug Rabson     ret = hdb_ldap_common(context, db, search_base, p);
1929c19800e8SDoug Rabson     free(p);
1930c19800e8SDoug Rabson     return ret;
1931c19800e8SDoug Rabson }
1932c19800e8SDoug Rabson 
1933c19800e8SDoug Rabson #ifdef OPENLDAP_MODULE
1934c19800e8SDoug Rabson 
1935c19800e8SDoug Rabson struct hdb_so_method hdb_ldap_interface = {
1936c19800e8SDoug Rabson     HDB_INTERFACE_VERSION,
1937c19800e8SDoug Rabson     "ldap",
1938c19800e8SDoug Rabson     hdb_ldap_create
1939c19800e8SDoug Rabson };
1940c19800e8SDoug Rabson 
1941c19800e8SDoug Rabson struct hdb_so_method hdb_ldapi_interface = {
1942c19800e8SDoug Rabson     HDB_INTERFACE_VERSION,
1943c19800e8SDoug Rabson     "ldapi",
1944c19800e8SDoug Rabson     hdb_ldapi_create
1945c19800e8SDoug Rabson };
1946c19800e8SDoug Rabson 
1947c19800e8SDoug Rabson #endif
1948c19800e8SDoug Rabson 
19495e9cd1aeSAssar Westerlund #endif				/* OPENLDAP */
1950