xref: /freebsd/crypto/heimdal/lib/hdb/hdb-ldap.c (revision ae77177087c655fc883075af4f425b37e032cd05)
15e9cd1aeSAssar Westerlund /*
2c19800e8SDoug Rabson  * Copyright (c) 1999-2001, 2003, PADL Software Pty Ltd.
3c19800e8SDoug Rabson  * Copyright (c) 2004, Andrew Bartlett.
4*ae771770SStanislav 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 
475e9cd1aeSAssar Westerlund static krb5_error_code
485e9cd1aeSAssar Westerlund LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
49*ae771770SStanislav Sedov 		   int flags, hdb_entry_ex * ent);
505e9cd1aeSAssar Westerlund 
51c19800e8SDoug Rabson static const char *default_structural_object = "account";
52c19800e8SDoug Rabson static char *structural_object;
53c19800e8SDoug Rabson static krb5_boolean samba_forwardable;
54c19800e8SDoug Rabson 
55c19800e8SDoug Rabson struct hdbldapdb {
56c19800e8SDoug Rabson     LDAP *h_lp;
57c19800e8SDoug Rabson     int   h_msgid;
58c19800e8SDoug Rabson     char *h_base;
59c19800e8SDoug Rabson     char *h_url;
60c19800e8SDoug Rabson     char *h_createbase;
61c19800e8SDoug Rabson };
62c19800e8SDoug Rabson 
63c19800e8SDoug Rabson #define HDB2LDAP(db) (((struct hdbldapdb *)(db)->hdb_db)->h_lp)
64c19800e8SDoug Rabson #define HDB2MSGID(db) (((struct hdbldapdb *)(db)->hdb_db)->h_msgid)
65c19800e8SDoug Rabson #define HDBSETMSGID(db,msgid) \
66c19800e8SDoug Rabson 	do { ((struct hdbldapdb *)(db)->hdb_db)->h_msgid = msgid; } while(0)
67c19800e8SDoug Rabson #define HDB2BASE(dn) (((struct hdbldapdb *)(db)->hdb_db)->h_base)
68c19800e8SDoug Rabson #define HDB2URL(dn) (((struct hdbldapdb *)(db)->hdb_db)->h_url)
69c19800e8SDoug Rabson #define HDB2CREATE(db) (((struct hdbldapdb *)(db)->hdb_db)->h_createbase)
70c19800e8SDoug Rabson 
71c19800e8SDoug Rabson /*
72c19800e8SDoug Rabson  *
73c19800e8SDoug Rabson  */
74c19800e8SDoug Rabson 
75c19800e8SDoug Rabson static char * krb5kdcentry_attrs[] = {
76c19800e8SDoug Rabson     "cn",
77c19800e8SDoug Rabson     "createTimestamp",
78c19800e8SDoug Rabson     "creatorsName",
79c19800e8SDoug Rabson     "krb5EncryptionType",
80c19800e8SDoug Rabson     "krb5KDCFlags",
81c19800e8SDoug Rabson     "krb5Key",
82c19800e8SDoug Rabson     "krb5KeyVersionNumber",
83c19800e8SDoug Rabson     "krb5MaxLife",
84c19800e8SDoug Rabson     "krb5MaxRenew",
85c19800e8SDoug Rabson     "krb5PasswordEnd",
86c19800e8SDoug Rabson     "krb5PrincipalName",
87c19800e8SDoug Rabson     "krb5PrincipalRealm",
88c19800e8SDoug Rabson     "krb5ValidEnd",
89c19800e8SDoug Rabson     "krb5ValidStart",
90c19800e8SDoug Rabson     "modifiersName",
91c19800e8SDoug Rabson     "modifyTimestamp",
92c19800e8SDoug Rabson     "objectClass",
93c19800e8SDoug Rabson     "sambaAcctFlags",
94c19800e8SDoug Rabson     "sambaKickoffTime",
95c19800e8SDoug Rabson     "sambaNTPassword",
96c19800e8SDoug Rabson     "sambaPwdLastSet",
97c19800e8SDoug Rabson     "sambaPwdMustChange",
98c19800e8SDoug Rabson     "uid",
995e9cd1aeSAssar Westerlund     NULL
1005e9cd1aeSAssar Westerlund };
1015e9cd1aeSAssar Westerlund 
102c19800e8SDoug Rabson static char *krb5principal_attrs[] = {
103c19800e8SDoug Rabson     "cn",
104c19800e8SDoug Rabson     "createTimestamp",
105c19800e8SDoug Rabson     "creatorsName",
106c19800e8SDoug Rabson     "krb5PrincipalName",
107c19800e8SDoug Rabson     "krb5PrincipalRealm",
108c19800e8SDoug Rabson     "modifiersName",
109c19800e8SDoug Rabson     "modifyTimestamp",
110c19800e8SDoug Rabson     "objectClass",
111c19800e8SDoug Rabson     "uid",
1125e9cd1aeSAssar Westerlund     NULL
1135e9cd1aeSAssar Westerlund };
1145e9cd1aeSAssar Westerlund 
115c19800e8SDoug Rabson static int
116c19800e8SDoug Rabson LDAP_no_size_limit(krb5_context context, LDAP *lp)
117c19800e8SDoug Rabson {
118c19800e8SDoug Rabson     int ret, limit = LDAP_NO_LIMIT;
119c19800e8SDoug Rabson 
120c19800e8SDoug Rabson     ret = ldap_set_option(lp, LDAP_OPT_SIZELIMIT, (const void *)&limit);
121c19800e8SDoug Rabson     if (ret != LDAP_SUCCESS) {
122*ae771770SStanislav Sedov 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
123*ae771770SStanislav Sedov 			       "ldap_set_option: %s",
124c19800e8SDoug Rabson 			       ldap_err2string(ret));
125c19800e8SDoug Rabson 	return HDB_ERR_BADVERSION;
126c19800e8SDoug Rabson     }
127c19800e8SDoug Rabson     return 0;
128c19800e8SDoug Rabson }
129c19800e8SDoug Rabson 
130c19800e8SDoug Rabson static int
131c19800e8SDoug Rabson check_ldap(krb5_context context, HDB *db, int ret)
132c19800e8SDoug Rabson {
133c19800e8SDoug Rabson     switch (ret) {
134c19800e8SDoug Rabson     case LDAP_SUCCESS:
135c19800e8SDoug Rabson 	return 0;
136c19800e8SDoug Rabson     case LDAP_SERVER_DOWN:
137c19800e8SDoug Rabson 	LDAP_close(context, db);
138c19800e8SDoug Rabson 	return 1;
139c19800e8SDoug Rabson     default:
140c19800e8SDoug Rabson 	return 1;
141c19800e8SDoug Rabson     }
142c19800e8SDoug Rabson }
143c19800e8SDoug Rabson 
1445e9cd1aeSAssar Westerlund static krb5_error_code
1451c43270aSJacques Vidrine LDAP__setmod(LDAPMod *** modlist, int modop, const char *attribute,
1461c43270aSJacques Vidrine 	     int *pIndex)
1475e9cd1aeSAssar Westerlund {
1481c43270aSJacques Vidrine     int cMods;
1495e9cd1aeSAssar Westerlund 
1501c43270aSJacques Vidrine     if (*modlist == NULL) {
1511c43270aSJacques Vidrine 	*modlist = (LDAPMod **)ber_memcalloc(1, sizeof(LDAPMod *));
152c19800e8SDoug Rabson 	if (*modlist == NULL)
1535e9cd1aeSAssar Westerlund 	    return ENOMEM;
1545e9cd1aeSAssar Westerlund     }
1555e9cd1aeSAssar Westerlund 
1561c43270aSJacques Vidrine     for (cMods = 0; (*modlist)[cMods] != NULL; cMods++) {
1571c43270aSJacques Vidrine 	if ((*modlist)[cMods]->mod_op == modop &&
1581c43270aSJacques Vidrine 	    strcasecmp((*modlist)[cMods]->mod_type, attribute) == 0) {
1595e9cd1aeSAssar Westerlund 	    break;
1605e9cd1aeSAssar Westerlund 	}
1615e9cd1aeSAssar Westerlund     }
1625e9cd1aeSAssar Westerlund 
1631c43270aSJacques Vidrine     *pIndex = cMods;
1641c43270aSJacques Vidrine 
1651c43270aSJacques Vidrine     if ((*modlist)[cMods] == NULL) {
1661c43270aSJacques Vidrine 	LDAPMod *mod;
1671c43270aSJacques Vidrine 
1681c43270aSJacques Vidrine 	*modlist = (LDAPMod **)ber_memrealloc(*modlist,
1691c43270aSJacques Vidrine 					      (cMods + 2) * sizeof(LDAPMod *));
170c19800e8SDoug Rabson 	if (*modlist == NULL)
1715e9cd1aeSAssar Westerlund 	    return ENOMEM;
172c19800e8SDoug Rabson 
1731c43270aSJacques Vidrine 	(*modlist)[cMods] = (LDAPMod *)ber_memalloc(sizeof(LDAPMod));
174c19800e8SDoug Rabson 	if ((*modlist)[cMods] == NULL)
1755e9cd1aeSAssar Westerlund 	    return ENOMEM;
1761c43270aSJacques Vidrine 
1771c43270aSJacques Vidrine 	mod = (*modlist)[cMods];
1781c43270aSJacques Vidrine 	mod->mod_op = modop;
1791c43270aSJacques Vidrine 	mod->mod_type = ber_strdup(attribute);
1801c43270aSJacques Vidrine 	if (mod->mod_type == NULL) {
1811c43270aSJacques Vidrine 	    ber_memfree(mod);
1821c43270aSJacques Vidrine 	    (*modlist)[cMods] = NULL;
1835e9cd1aeSAssar Westerlund 	    return ENOMEM;
1845e9cd1aeSAssar Westerlund 	}
1851c43270aSJacques Vidrine 
1861c43270aSJacques Vidrine 	if (modop & LDAP_MOD_BVALUES) {
1871c43270aSJacques Vidrine 	    mod->mod_bvalues = NULL;
1881c43270aSJacques Vidrine 	} else {
1891c43270aSJacques Vidrine 	    mod->mod_values = NULL;
1901c43270aSJacques Vidrine 	}
1911c43270aSJacques Vidrine 
1921c43270aSJacques Vidrine 	(*modlist)[cMods + 1] = NULL;
1931c43270aSJacques Vidrine     }
1941c43270aSJacques Vidrine 
1951c43270aSJacques Vidrine     return 0;
1961c43270aSJacques Vidrine }
1971c43270aSJacques Vidrine 
1981c43270aSJacques Vidrine static krb5_error_code
1991c43270aSJacques Vidrine LDAP_addmod_len(LDAPMod *** modlist, int modop, const char *attribute,
2001c43270aSJacques Vidrine 		unsigned char *value, size_t len)
2011c43270aSJacques Vidrine {
2021c43270aSJacques Vidrine     krb5_error_code ret;
203c19800e8SDoug Rabson     int cMods, i = 0;
2041c43270aSJacques Vidrine 
2051c43270aSJacques Vidrine     ret = LDAP__setmod(modlist, modop | LDAP_MOD_BVALUES, attribute, &cMods);
206c19800e8SDoug Rabson     if (ret)
2071c43270aSJacques Vidrine 	return ret;
2085e9cd1aeSAssar Westerlund 
2095e9cd1aeSAssar Westerlund     if (value != NULL) {
210c19800e8SDoug Rabson 	struct berval **bv;
2111c43270aSJacques Vidrine 
212c19800e8SDoug Rabson 	bv = (*modlist)[cMods]->mod_bvalues;
213c19800e8SDoug Rabson 	if (bv != NULL) {
214c19800e8SDoug Rabson 	    for (i = 0; bv[i] != NULL; i++)
2151c43270aSJacques Vidrine 		;
216c19800e8SDoug Rabson 	    bv = ber_memrealloc(bv, (i + 2) * sizeof(*bv));
217c19800e8SDoug Rabson 	} else
218c19800e8SDoug Rabson 	    bv = ber_memalloc(2 * sizeof(*bv));
219c19800e8SDoug Rabson 	if (bv == NULL)
2205e9cd1aeSAssar Westerlund 	    return ENOMEM;
221c19800e8SDoug Rabson 
222c19800e8SDoug Rabson 	(*modlist)[cMods]->mod_bvalues = bv;
223c19800e8SDoug Rabson 
224*ae771770SStanislav Sedov 	bv[i] = ber_memalloc(sizeof(**bv));;
225c19800e8SDoug Rabson 	if (bv[i] == NULL)
2265e9cd1aeSAssar Westerlund 	    return ENOMEM;
2271c43270aSJacques Vidrine 
228c19800e8SDoug Rabson 	bv[i]->bv_val = (void *)value;
229c19800e8SDoug Rabson 	bv[i]->bv_len = len;
2301c43270aSJacques Vidrine 
231c19800e8SDoug Rabson 	bv[i + 1] = NULL;
2325e9cd1aeSAssar Westerlund     }
2331c43270aSJacques Vidrine 
2345e9cd1aeSAssar Westerlund     return 0;
2355e9cd1aeSAssar Westerlund }
2365e9cd1aeSAssar Westerlund 
2375e9cd1aeSAssar Westerlund static krb5_error_code
2385e9cd1aeSAssar Westerlund LDAP_addmod(LDAPMod *** modlist, int modop, const char *attribute,
2395e9cd1aeSAssar Westerlund 	    const char *value)
2405e9cd1aeSAssar Westerlund {
241c19800e8SDoug Rabson     int cMods, i = 0;
2421c43270aSJacques Vidrine     krb5_error_code ret;
2435e9cd1aeSAssar Westerlund 
2441c43270aSJacques Vidrine     ret = LDAP__setmod(modlist, modop, attribute, &cMods);
245c19800e8SDoug Rabson     if (ret)
2461c43270aSJacques Vidrine 	return ret;
2475e9cd1aeSAssar Westerlund 
2485e9cd1aeSAssar Westerlund     if (value != NULL) {
249c19800e8SDoug Rabson 	char **bv;
2501c43270aSJacques Vidrine 
251c19800e8SDoug Rabson 	bv = (*modlist)[cMods]->mod_values;
252c19800e8SDoug Rabson 	if (bv != NULL) {
253c19800e8SDoug Rabson 	    for (i = 0; bv[i] != NULL; i++)
2541c43270aSJacques Vidrine 		;
255c19800e8SDoug Rabson 	    bv = ber_memrealloc(bv, (i + 2) * sizeof(*bv));
256c19800e8SDoug Rabson 	} else
257c19800e8SDoug Rabson 	    bv = ber_memalloc(2 * sizeof(*bv));
258c19800e8SDoug Rabson 	if (bv == NULL)
2595e9cd1aeSAssar Westerlund 	    return ENOMEM;
260c19800e8SDoug Rabson 
261c19800e8SDoug Rabson 	(*modlist)[cMods]->mod_values = bv;
262c19800e8SDoug Rabson 
263c19800e8SDoug Rabson 	bv[i] = ber_strdup(value);
264c19800e8SDoug Rabson 	if (bv[i] == NULL)
2655e9cd1aeSAssar Westerlund 	    return ENOMEM;
266c19800e8SDoug Rabson 
267c19800e8SDoug Rabson 	bv[i + 1] = NULL;
2685e9cd1aeSAssar Westerlund     }
2691c43270aSJacques Vidrine 
2705e9cd1aeSAssar Westerlund     return 0;
2715e9cd1aeSAssar Westerlund }
2725e9cd1aeSAssar Westerlund 
2735e9cd1aeSAssar Westerlund static krb5_error_code
2745e9cd1aeSAssar Westerlund LDAP_addmod_generalized_time(LDAPMod *** mods, int modop,
2755e9cd1aeSAssar Westerlund 			     const char *attribute, KerberosTime * time)
2765e9cd1aeSAssar Westerlund {
2775e9cd1aeSAssar Westerlund     char buf[22];
2785e9cd1aeSAssar Westerlund     struct tm *tm;
2795e9cd1aeSAssar Westerlund 
2805e9cd1aeSAssar Westerlund     /* XXX not threadsafe */
2815e9cd1aeSAssar Westerlund     tm = gmtime(time);
2825e9cd1aeSAssar Westerlund     strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", tm);
2835e9cd1aeSAssar Westerlund 
2845e9cd1aeSAssar Westerlund     return LDAP_addmod(mods, modop, attribute, buf);
2855e9cd1aeSAssar Westerlund }
2865e9cd1aeSAssar Westerlund 
2875e9cd1aeSAssar Westerlund static krb5_error_code
288c19800e8SDoug Rabson LDAP_addmod_integer(krb5_context context,
289c19800e8SDoug Rabson 		    LDAPMod *** mods, int modop,
290c19800e8SDoug Rabson 		    const char *attribute, unsigned long l)
291c19800e8SDoug Rabson {
292c19800e8SDoug Rabson     krb5_error_code ret;
293c19800e8SDoug Rabson     char *buf;
294c19800e8SDoug Rabson 
295c19800e8SDoug Rabson     ret = asprintf(&buf, "%ld", l);
296c19800e8SDoug Rabson     if (ret < 0) {
297*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
298*ae771770SStanislav Sedov 			       "asprintf: out of memory:");
299*ae771770SStanislav Sedov 	return ENOMEM;
300c19800e8SDoug Rabson     }
301c19800e8SDoug Rabson     ret = LDAP_addmod(mods, modop, attribute, buf);
302c19800e8SDoug Rabson     free (buf);
303c19800e8SDoug Rabson     return ret;
304c19800e8SDoug Rabson }
305c19800e8SDoug Rabson 
306c19800e8SDoug Rabson static krb5_error_code
3075e9cd1aeSAssar Westerlund LDAP_get_string_value(HDB * db, LDAPMessage * entry,
3085e9cd1aeSAssar Westerlund 		      const char *attribute, char **ptr)
3095e9cd1aeSAssar Westerlund {
310*ae771770SStanislav Sedov     struct berval **vals;
3115e9cd1aeSAssar Westerlund 
312*ae771770SStanislav Sedov     vals = ldap_get_values_len(HDB2LDAP(db), entry, attribute);
313*ae771770SStanislav Sedov     if (vals == NULL || vals[0] == NULL) {
314c19800e8SDoug Rabson 	*ptr = NULL;
3155e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
3165e9cd1aeSAssar Westerlund     }
317c19800e8SDoug Rabson 
318*ae771770SStanislav Sedov     *ptr = malloc(vals[0]->bv_len + 1);
319*ae771770SStanislav Sedov     if (*ptr == NULL) {
320*ae771770SStanislav Sedov 	ldap_value_free_len(vals);
321*ae771770SStanislav Sedov 	return ENOMEM;
322*ae771770SStanislav Sedov     }
3235e9cd1aeSAssar Westerlund 
324*ae771770SStanislav Sedov     memcpy(*ptr, vals[0]->bv_val, vals[0]->bv_len);
325*ae771770SStanislav Sedov     (*ptr)[vals[0]->bv_len] = 0;
3265e9cd1aeSAssar Westerlund 
327*ae771770SStanislav Sedov     ldap_value_free_len(vals);
328*ae771770SStanislav Sedov 
329*ae771770SStanislav Sedov     return 0;
3305e9cd1aeSAssar Westerlund }
3315e9cd1aeSAssar Westerlund 
3325e9cd1aeSAssar Westerlund static krb5_error_code
3335e9cd1aeSAssar Westerlund LDAP_get_integer_value(HDB * db, LDAPMessage * entry,
3345e9cd1aeSAssar Westerlund 		       const char *attribute, int *ptr)
3355e9cd1aeSAssar Westerlund {
336*ae771770SStanislav Sedov     krb5_error_code ret;
337*ae771770SStanislav Sedov     char *val;
3385e9cd1aeSAssar Westerlund 
339*ae771770SStanislav Sedov     ret = LDAP_get_string_value(db, entry, attribute, &val);
340*ae771770SStanislav Sedov     if (ret)
341*ae771770SStanislav Sedov 	return ret;
342*ae771770SStanislav Sedov     *ptr = atoi(val);
343*ae771770SStanislav Sedov     free(val);
3445e9cd1aeSAssar Westerlund     return 0;
3455e9cd1aeSAssar Westerlund }
3465e9cd1aeSAssar Westerlund 
3475e9cd1aeSAssar Westerlund static krb5_error_code
3485e9cd1aeSAssar Westerlund LDAP_get_generalized_time_value(HDB * db, LDAPMessage * entry,
3495e9cd1aeSAssar Westerlund 				const char *attribute, KerberosTime * kt)
3505e9cd1aeSAssar Westerlund {
3515e9cd1aeSAssar Westerlund     char *tmp, *gentime;
3525e9cd1aeSAssar Westerlund     struct tm tm;
3535e9cd1aeSAssar Westerlund     int ret;
3545e9cd1aeSAssar Westerlund 
3555e9cd1aeSAssar Westerlund     *kt = 0;
3565e9cd1aeSAssar Westerlund 
3575e9cd1aeSAssar Westerlund     ret = LDAP_get_string_value(db, entry, attribute, &gentime);
358c19800e8SDoug Rabson     if (ret)
3595e9cd1aeSAssar Westerlund 	return ret;
3605e9cd1aeSAssar Westerlund 
3615e9cd1aeSAssar Westerlund     tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm);
3625e9cd1aeSAssar Westerlund     if (tmp == NULL) {
3635e9cd1aeSAssar Westerlund 	free(gentime);
3645e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
3655e9cd1aeSAssar Westerlund     }
3665e9cd1aeSAssar Westerlund 
3675e9cd1aeSAssar Westerlund     free(gentime);
3685e9cd1aeSAssar Westerlund 
3695e9cd1aeSAssar Westerlund     *kt = timegm(&tm);
3705e9cd1aeSAssar Westerlund 
3715e9cd1aeSAssar Westerlund     return 0;
3725e9cd1aeSAssar Westerlund }
3735e9cd1aeSAssar Westerlund 
374*ae771770SStanislav Sedov static int
375*ae771770SStanislav Sedov bervalstrcmp(struct berval *v, const char *str)
376*ae771770SStanislav Sedov {
377*ae771770SStanislav Sedov     size_t len = strlen(str);
378*ae771770SStanislav Sedov     return (v->bv_len == len) && strncasecmp(str, (char *)v->bv_val, len) == 0;
379*ae771770SStanislav Sedov }
380*ae771770SStanislav Sedov 
381*ae771770SStanislav Sedov 
3825e9cd1aeSAssar Westerlund static krb5_error_code
383c19800e8SDoug Rabson LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
3845e9cd1aeSAssar Westerlund 		LDAPMessage * msg, LDAPMod *** pmods)
3855e9cd1aeSAssar Westerlund {
3865e9cd1aeSAssar Westerlund     krb5_error_code ret;
3875e9cd1aeSAssar Westerlund     krb5_boolean is_new_entry;
3885e9cd1aeSAssar Westerlund     char *tmp = NULL;
3895e9cd1aeSAssar Westerlund     LDAPMod **mods = NULL;
390c19800e8SDoug Rabson     hdb_entry_ex orig;
3915e9cd1aeSAssar Westerlund     unsigned long oflags, nflags;
392c19800e8SDoug Rabson     int i;
393c19800e8SDoug Rabson 
394c19800e8SDoug Rabson     krb5_boolean is_samba_account = FALSE;
395c19800e8SDoug Rabson     krb5_boolean is_account = FALSE;
396c19800e8SDoug Rabson     krb5_boolean is_heimdal_entry = FALSE;
397c19800e8SDoug Rabson     krb5_boolean is_heimdal_principal = FALSE;
398c19800e8SDoug Rabson 
399*ae771770SStanislav Sedov     struct berval **vals;
400c19800e8SDoug Rabson 
401c19800e8SDoug Rabson     *pmods = NULL;
4025e9cd1aeSAssar Westerlund 
4035e9cd1aeSAssar Westerlund     if (msg != NULL) {
404c19800e8SDoug Rabson 
405*ae771770SStanislav Sedov 	ret = LDAP_message2entry(context, db, msg, 0, &orig);
406c19800e8SDoug Rabson 	if (ret)
407c19800e8SDoug Rabson 	    goto out;
408c19800e8SDoug Rabson 
409c19800e8SDoug Rabson 	is_new_entry = FALSE;
410c19800e8SDoug Rabson 
411*ae771770SStanislav Sedov 	vals = ldap_get_values_len(HDB2LDAP(db), msg, "objectClass");
412*ae771770SStanislav Sedov 	if (vals) {
413*ae771770SStanislav Sedov 	    int num_objectclasses = ldap_count_values_len(vals);
414c19800e8SDoug Rabson 	    for (i=0; i < num_objectclasses; i++) {
415*ae771770SStanislav Sedov 		if (bervalstrcmp(vals[i], "sambaSamAccount"))
416c19800e8SDoug Rabson 		    is_samba_account = TRUE;
417*ae771770SStanislav Sedov 		else if (bervalstrcmp(vals[i], structural_object))
418c19800e8SDoug Rabson 		    is_account = TRUE;
419*ae771770SStanislav Sedov 		else if (bervalstrcmp(vals[i], "krb5Principal"))
420c19800e8SDoug Rabson 		    is_heimdal_principal = TRUE;
421*ae771770SStanislav Sedov 		else if (bervalstrcmp(vals[i], "krb5KDCEntry"))
422c19800e8SDoug Rabson 		    is_heimdal_entry = TRUE;
423c19800e8SDoug Rabson 	    }
424*ae771770SStanislav Sedov 	    ldap_value_free_len(vals);
425c19800e8SDoug Rabson 	}
426c19800e8SDoug Rabson 
427c19800e8SDoug Rabson 	/*
428c19800e8SDoug Rabson 	 * If this is just a "account" entry and no other objectclass
429c19800e8SDoug Rabson 	 * is hanging on this entry, it's really a new entry.
430c19800e8SDoug Rabson 	 */
431c19800e8SDoug Rabson 	if (is_samba_account == FALSE && is_heimdal_principal == FALSE &&
432c19800e8SDoug Rabson 	    is_heimdal_entry == FALSE) {
433c19800e8SDoug Rabson 	    if (is_account == TRUE) {
434c19800e8SDoug Rabson 		is_new_entry = TRUE;
435c19800e8SDoug Rabson 	    } else {
436c19800e8SDoug Rabson 		ret = HDB_ERR_NOENTRY;
4375e9cd1aeSAssar Westerlund 		goto out;
4385e9cd1aeSAssar Westerlund 	    }
439c19800e8SDoug Rabson 	}
440c19800e8SDoug Rabson     } else
441c19800e8SDoug Rabson 	is_new_entry = TRUE;
442c19800e8SDoug Rabson 
443c19800e8SDoug Rabson     if (is_new_entry) {
444c19800e8SDoug Rabson 
4455e9cd1aeSAssar Westerlund 	/* to make it perfectly obvious we're depending on
4465e9cd1aeSAssar Westerlund 	 * orig being intiialized to zero */
4475e9cd1aeSAssar Westerlund 	memset(&orig, 0, sizeof(orig));
448c19800e8SDoug Rabson 
449c19800e8SDoug Rabson 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "top");
450c19800e8SDoug Rabson 	if (ret)
451c19800e8SDoug Rabson 	    goto out;
452c19800e8SDoug Rabson 
453c19800e8SDoug Rabson 	/* account is the structural object class */
454c19800e8SDoug Rabson 	if (is_account == FALSE) {
455c19800e8SDoug Rabson 	    ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass",
456c19800e8SDoug Rabson 			      structural_object);
457c19800e8SDoug Rabson 	    is_account = TRUE;
458c19800e8SDoug Rabson 	    if (ret)
459c19800e8SDoug Rabson 		goto out;
4605e9cd1aeSAssar Westerlund 	}
4615e9cd1aeSAssar Westerlund 
462c19800e8SDoug Rabson 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5Principal");
463c19800e8SDoug Rabson 	is_heimdal_principal = TRUE;
464c19800e8SDoug Rabson 	if (ret)
4655e9cd1aeSAssar Westerlund 	    goto out;
466c19800e8SDoug Rabson 
467c19800e8SDoug Rabson 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5KDCEntry");
468c19800e8SDoug Rabson 	is_heimdal_entry = TRUE;
469c19800e8SDoug Rabson 	if (ret)
4705e9cd1aeSAssar Westerlund 	    goto out;
4715e9cd1aeSAssar Westerlund     }
4725e9cd1aeSAssar Westerlund 
4735e9cd1aeSAssar Westerlund     if (is_new_entry ||
474c19800e8SDoug Rabson 	krb5_principal_compare(context, ent->entry.principal, orig.entry.principal)
475c19800e8SDoug Rabson 	== FALSE)
476c19800e8SDoug Rabson     {
477c19800e8SDoug Rabson 	if (is_heimdal_principal || is_heimdal_entry) {
478c19800e8SDoug Rabson 
479c19800e8SDoug Rabson 	    ret = krb5_unparse_name(context, ent->entry.principal, &tmp);
480c19800e8SDoug Rabson 	    if (ret)
4815e9cd1aeSAssar Westerlund 		goto out;
482c19800e8SDoug Rabson 
483c19800e8SDoug Rabson 	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE,
484c19800e8SDoug Rabson 			      "krb5PrincipalName", tmp);
485c19800e8SDoug Rabson 	    if (ret) {
4865e9cd1aeSAssar Westerlund 		free(tmp);
4875e9cd1aeSAssar Westerlund 		goto out;
4885e9cd1aeSAssar Westerlund 	    }
4895e9cd1aeSAssar Westerlund 	    free(tmp);
4905e9cd1aeSAssar Westerlund 	}
4915e9cd1aeSAssar Westerlund 
492c19800e8SDoug Rabson 	if (is_account || is_samba_account) {
493c19800e8SDoug Rabson 	    ret = krb5_unparse_name_short(context, ent->entry.principal, &tmp);
494c19800e8SDoug Rabson 	    if (ret)
495c19800e8SDoug Rabson 		goto out;
496c19800e8SDoug Rabson 	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "uid", tmp);
497c19800e8SDoug Rabson 	    if (ret) {
498c19800e8SDoug Rabson 		free(tmp);
4995e9cd1aeSAssar Westerlund 		goto out;
5005e9cd1aeSAssar Westerlund 	    }
5015e9cd1aeSAssar Westerlund 	    free(tmp);
5025e9cd1aeSAssar Westerlund 	}
5035e9cd1aeSAssar Westerlund     }
5045e9cd1aeSAssar Westerlund 
505c19800e8SDoug Rabson     if (is_heimdal_entry && (ent->entry.kvno != orig.entry.kvno || is_new_entry)) {
506c19800e8SDoug Rabson 	ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
507c19800e8SDoug Rabson 			    "krb5KeyVersionNumber",
508c19800e8SDoug Rabson 			    ent->entry.kvno);
509c19800e8SDoug Rabson 	if (ret)
510c19800e8SDoug Rabson 	    goto out;
511c19800e8SDoug Rabson     }
512c19800e8SDoug Rabson 
513c19800e8SDoug Rabson     if (is_heimdal_entry && ent->entry.valid_start) {
514c19800e8SDoug Rabson 	if (orig.entry.valid_end == NULL
515c19800e8SDoug Rabson 	    || (*(ent->entry.valid_start) != *(orig.entry.valid_start))) {
516c19800e8SDoug Rabson 	    ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
5175e9cd1aeSAssar Westerlund 					       "krb5ValidStart",
518c19800e8SDoug Rabson 					       ent->entry.valid_start);
519c19800e8SDoug Rabson 	    if (ret)
5205e9cd1aeSAssar Westerlund 		goto out;
5215e9cd1aeSAssar Westerlund 	}
5225e9cd1aeSAssar Westerlund     }
5235e9cd1aeSAssar Westerlund 
524c19800e8SDoug Rabson     if (ent->entry.valid_end) {
525c19800e8SDoug Rabson  	if (orig.entry.valid_end == NULL || (*(ent->entry.valid_end) != *(orig.entry.valid_end))) {
526c19800e8SDoug Rabson 	    if (is_heimdal_entry) {
527c19800e8SDoug Rabson 		ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
5285e9cd1aeSAssar Westerlund 						   "krb5ValidEnd",
529c19800e8SDoug Rabson 						   ent->entry.valid_end);
530c19800e8SDoug Rabson 		if (ret)
531c19800e8SDoug Rabson 		    goto out;
532c19800e8SDoug Rabson             }
533c19800e8SDoug Rabson 	    if (is_samba_account) {
534c19800e8SDoug Rabson 		ret = LDAP_addmod_integer(context, &mods,  LDAP_MOD_REPLACE,
535c19800e8SDoug Rabson 					  "sambaKickoffTime",
536c19800e8SDoug Rabson 					  *(ent->entry.valid_end));
537c19800e8SDoug Rabson 		if (ret)
5385e9cd1aeSAssar Westerlund 		    goto out;
5395e9cd1aeSAssar Westerlund 	    }
5405e9cd1aeSAssar Westerlund    	}
5415e9cd1aeSAssar Westerlund     }
5425e9cd1aeSAssar Westerlund 
543c19800e8SDoug Rabson     if (ent->entry.pw_end) {
544c19800e8SDoug Rabson 	if (orig.entry.pw_end == NULL || (*(ent->entry.pw_end) != *(orig.entry.pw_end))) {
545c19800e8SDoug Rabson 	    if (is_heimdal_entry) {
546c19800e8SDoug Rabson 		ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
5475e9cd1aeSAssar Westerlund 						   "krb5PasswordEnd",
548c19800e8SDoug Rabson 						   ent->entry.pw_end);
549c19800e8SDoug Rabson 		if (ret)
550c19800e8SDoug Rabson 		    goto out;
551c19800e8SDoug Rabson 	    }
552c19800e8SDoug Rabson 
553c19800e8SDoug Rabson 	    if (is_samba_account) {
554c19800e8SDoug Rabson 		ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
555c19800e8SDoug Rabson 					  "sambaPwdMustChange",
556c19800e8SDoug Rabson 					  *(ent->entry.pw_end));
557c19800e8SDoug Rabson 		if (ret)
5585e9cd1aeSAssar Westerlund 		    goto out;
5595e9cd1aeSAssar Westerlund 	    }
5605e9cd1aeSAssar Westerlund 	}
5615e9cd1aeSAssar Westerlund     }
5625e9cd1aeSAssar Westerlund 
5635e9cd1aeSAssar Westerlund 
564c19800e8SDoug Rabson #if 0 /* we we have last_pw_change */
565c19800e8SDoug Rabson     if (is_samba_account && ent->entry.last_pw_change) {
566c19800e8SDoug Rabson 	if (orig.entry.last_pw_change == NULL || (*(ent->entry.last_pw_change) != *(orig.entry.last_pw_change))) {
567c19800e8SDoug Rabson 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
568c19800e8SDoug Rabson 				      "sambaPwdLastSet",
569c19800e8SDoug Rabson 				      *(ent->entry.last_pw_change));
570c19800e8SDoug Rabson 	    if (ret)
5715e9cd1aeSAssar Westerlund 		goto out;
5725e9cd1aeSAssar Westerlund 	}
5735e9cd1aeSAssar Westerlund     }
574c19800e8SDoug Rabson #endif
5755e9cd1aeSAssar Westerlund 
576c19800e8SDoug Rabson     if (is_heimdal_entry && ent->entry.max_life) {
577c19800e8SDoug Rabson 	if (orig.entry.max_life == NULL
578c19800e8SDoug Rabson 	    || (*(ent->entry.max_life) != *(orig.entry.max_life))) {
5795e9cd1aeSAssar Westerlund 
580c19800e8SDoug Rabson 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
581c19800e8SDoug Rabson 				      "krb5MaxLife",
582c19800e8SDoug Rabson 				      *(ent->entry.max_life));
583c19800e8SDoug Rabson 	    if (ret)
5845e9cd1aeSAssar Westerlund 		goto out;
5855e9cd1aeSAssar Westerlund 	}
5865e9cd1aeSAssar Westerlund     }
5875e9cd1aeSAssar Westerlund 
588c19800e8SDoug Rabson     if (is_heimdal_entry && ent->entry.max_renew) {
589c19800e8SDoug Rabson 	if (orig.entry.max_renew == NULL
590c19800e8SDoug Rabson 	    || (*(ent->entry.max_renew) != *(orig.entry.max_renew))) {
591c19800e8SDoug Rabson 
592c19800e8SDoug Rabson 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
593c19800e8SDoug Rabson 				      "krb5MaxRenew",
594c19800e8SDoug Rabson 				      *(ent->entry.max_renew));
595c19800e8SDoug Rabson 	    if (ret)
596c19800e8SDoug Rabson 		goto out;
597c19800e8SDoug Rabson 	}
598c19800e8SDoug Rabson     }
599c19800e8SDoug Rabson 
600c19800e8SDoug Rabson     oflags = HDBFlags2int(orig.entry.flags);
601c19800e8SDoug Rabson     nflags = HDBFlags2int(ent->entry.flags);
602c19800e8SDoug Rabson 
603c19800e8SDoug Rabson     if (is_heimdal_entry && oflags != nflags) {
604c19800e8SDoug Rabson 
605c19800e8SDoug Rabson 	ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
606c19800e8SDoug Rabson 				  "krb5KDCFlags",
607c19800e8SDoug Rabson 				  nflags);
608c19800e8SDoug Rabson 	if (ret)
609c19800e8SDoug Rabson 	    goto out;
610c19800e8SDoug Rabson     }
611c19800e8SDoug Rabson 
612c19800e8SDoug Rabson     /* Remove keys if they exists, and then replace keys. */
613c19800e8SDoug Rabson     if (!is_new_entry && orig.entry.keys.len > 0) {
614*ae771770SStanislav Sedov 	vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key");
615*ae771770SStanislav Sedov 	if (vals) {
616*ae771770SStanislav Sedov 	    ldap_value_free_len(vals);
617c19800e8SDoug Rabson 
6185e9cd1aeSAssar Westerlund 	    ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5Key", NULL);
619c19800e8SDoug Rabson 	    if (ret)
6205e9cd1aeSAssar Westerlund 		goto out;
6215e9cd1aeSAssar Westerlund 	}
6225e9cd1aeSAssar Westerlund     }
6235e9cd1aeSAssar Westerlund 
624c19800e8SDoug Rabson     for (i = 0; i < ent->entry.keys.len; i++) {
625c19800e8SDoug Rabson 
626c19800e8SDoug Rabson 	if (is_samba_account
627c19800e8SDoug Rabson 	    && ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
628c19800e8SDoug Rabson 	    char *ntHexPassword;
629c19800e8SDoug Rabson 	    char *nt;
630*ae771770SStanislav Sedov 	    time_t now = time(NULL);
631c19800e8SDoug Rabson 
632c19800e8SDoug Rabson 	    /* the key might have been 'sealed', but samba passwords
633c19800e8SDoug Rabson 	       are clear in the directory */
634c19800e8SDoug Rabson 	    ret = hdb_unseal_key(context, db, &ent->entry.keys.val[i]);
635c19800e8SDoug Rabson 	    if (ret)
636c19800e8SDoug Rabson 		goto out;
637c19800e8SDoug Rabson 
638c19800e8SDoug Rabson 	    nt = ent->entry.keys.val[i].key.keyvalue.data;
639c19800e8SDoug Rabson 	    /* store in ntPassword, not krb5key */
640c19800e8SDoug Rabson 	    ret = hex_encode(nt, 16, &ntHexPassword);
641c19800e8SDoug Rabson 	    if (ret < 0) {
642c19800e8SDoug Rabson 		ret = ENOMEM;
643*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, "hdb-ldap: failed to "
644*ae771770SStanislav Sedov 				      "hex encode key");
645c19800e8SDoug Rabson 		goto out;
646c19800e8SDoug Rabson 	    }
647c19800e8SDoug Rabson 	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "sambaNTPassword",
648c19800e8SDoug Rabson 			      ntHexPassword);
649c19800e8SDoug Rabson 	    free(ntHexPassword);
650c19800e8SDoug Rabson 	    if (ret)
651c19800e8SDoug Rabson 		goto out;
652*ae771770SStanislav Sedov 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
653*ae771770SStanislav Sedov 				      "sambaPwdLastSet", now);
654*ae771770SStanislav Sedov 	    if (ret)
655*ae771770SStanislav Sedov 		goto out;
656c19800e8SDoug Rabson 
657c19800e8SDoug Rabson 	    /* have to kill the LM passwod if it exists */
658*ae771770SStanislav Sedov 	    vals = ldap_get_values_len(HDB2LDAP(db), msg, "sambaLMPassword");
659*ae771770SStanislav Sedov 	    if (vals) {
660*ae771770SStanislav Sedov 		ldap_value_free_len(vals);
661c19800e8SDoug Rabson 		ret = LDAP_addmod(&mods, LDAP_MOD_DELETE,
662c19800e8SDoug Rabson 				  "sambaLMPassword", NULL);
663c19800e8SDoug Rabson 		if (ret)
664c19800e8SDoug Rabson 		    goto out;
665c19800e8SDoug Rabson 	    }
666c19800e8SDoug Rabson 
667c19800e8SDoug Rabson 	} else if (is_heimdal_entry) {
6685e9cd1aeSAssar Westerlund 	    unsigned char *buf;
669c19800e8SDoug Rabson 	    size_t len, buf_size;
6705e9cd1aeSAssar Westerlund 
671c19800e8SDoug Rabson 	    ASN1_MALLOC_ENCODE(Key, buf, buf_size, &ent->entry.keys.val[i], &len, ret);
672c19800e8SDoug Rabson 	    if (ret)
6735e9cd1aeSAssar Westerlund 		goto out;
674c19800e8SDoug Rabson 	    if(buf_size != len)
675c19800e8SDoug Rabson 		krb5_abortx(context, "internal error in ASN.1 encoder");
6765e9cd1aeSAssar Westerlund 
6775e9cd1aeSAssar Westerlund 	    /* addmod_len _owns_ the key, doesn't need to copy it */
6785e9cd1aeSAssar Westerlund 	    ret = LDAP_addmod_len(&mods, LDAP_MOD_ADD, "krb5Key", buf, len);
679c19800e8SDoug Rabson 	    if (ret)
6805e9cd1aeSAssar Westerlund 		goto out;
6815e9cd1aeSAssar Westerlund 	}
6825e9cd1aeSAssar Westerlund     }
6835e9cd1aeSAssar Westerlund 
684c19800e8SDoug Rabson     if (ent->entry.etypes) {
685c19800e8SDoug Rabson 	int add_krb5EncryptionType = 0;
686c19800e8SDoug Rabson 
687c19800e8SDoug Rabson 	/*
688c19800e8SDoug Rabson 	 * Only add/modify krb5EncryptionType if it's a new heimdal
689c19800e8SDoug Rabson 	 * entry or krb5EncryptionType already exists on the entry.
690c19800e8SDoug Rabson 	 */
691c19800e8SDoug Rabson 
692c19800e8SDoug Rabson 	if (!is_new_entry) {
693*ae771770SStanislav Sedov 	    vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType");
694*ae771770SStanislav Sedov 	    if (vals) {
695*ae771770SStanislav Sedov 		ldap_value_free_len(vals);
696c19800e8SDoug Rabson 		ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5EncryptionType",
6975e9cd1aeSAssar Westerlund 				  NULL);
698c19800e8SDoug Rabson 		if (ret)
699c19800e8SDoug Rabson 		    goto out;
700c19800e8SDoug Rabson 		add_krb5EncryptionType = 1;
7015e9cd1aeSAssar Westerlund 	    }
702c19800e8SDoug Rabson 	} else if (is_heimdal_entry)
703c19800e8SDoug Rabson 	    add_krb5EncryptionType = 1;
704c19800e8SDoug Rabson 
705c19800e8SDoug Rabson 	if (add_krb5EncryptionType) {
706c19800e8SDoug Rabson 	    for (i = 0; i < ent->entry.etypes->len; i++) {
707c19800e8SDoug Rabson 		if (is_samba_account &&
708c19800e8SDoug Rabson 		    ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5)
709c19800e8SDoug Rabson 		{
710c19800e8SDoug Rabson 		    ;
711c19800e8SDoug Rabson 		} else if (is_heimdal_entry) {
712c19800e8SDoug Rabson 		    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_ADD,
713c19800e8SDoug Rabson 					      "krb5EncryptionType",
714c19800e8SDoug Rabson 					      ent->entry.etypes->val[i]);
715c19800e8SDoug Rabson 		    if (ret)
7165e9cd1aeSAssar Westerlund 			goto out;
7175e9cd1aeSAssar Westerlund 		}
7185e9cd1aeSAssar Westerlund 	    }
7195e9cd1aeSAssar Westerlund 	}
7205e9cd1aeSAssar Westerlund     }
7215e9cd1aeSAssar Westerlund 
7225e9cd1aeSAssar Westerlund     /* for clarity */
7235e9cd1aeSAssar Westerlund     ret = 0;
7245e9cd1aeSAssar Westerlund 
7255e9cd1aeSAssar Westerlund  out:
7265e9cd1aeSAssar Westerlund 
727c19800e8SDoug Rabson     if (ret == 0)
7285e9cd1aeSAssar Westerlund 	*pmods = mods;
729c19800e8SDoug Rabson     else if (mods != NULL) {
7305e9cd1aeSAssar Westerlund 	ldap_mods_free(mods, 1);
7315e9cd1aeSAssar Westerlund 	*pmods = NULL;
7325e9cd1aeSAssar Westerlund     }
7335e9cd1aeSAssar Westerlund 
734c19800e8SDoug Rabson     if (msg)
7355e9cd1aeSAssar Westerlund 	hdb_free_entry(context, &orig);
7365e9cd1aeSAssar Westerlund 
7375e9cd1aeSAssar Westerlund     return ret;
7385e9cd1aeSAssar Westerlund }
7395e9cd1aeSAssar Westerlund 
7405e9cd1aeSAssar Westerlund static krb5_error_code
7415e9cd1aeSAssar Westerlund LDAP_dn2principal(krb5_context context, HDB * db, const char *dn,
7425e9cd1aeSAssar Westerlund 		  krb5_principal * principal)
7435e9cd1aeSAssar Westerlund {
7445e9cd1aeSAssar Westerlund     krb5_error_code ret;
745c19800e8SDoug Rabson     int rc;
746c19800e8SDoug Rabson     const char *filter = "(objectClass=krb5Principal)";
7475e9cd1aeSAssar Westerlund     LDAPMessage *res = NULL, *e;
748*ae771770SStanislav Sedov     char *p;
7495e9cd1aeSAssar Westerlund 
750c19800e8SDoug Rabson     ret = LDAP_no_size_limit(context, HDB2LDAP(db));
751c19800e8SDoug Rabson     if (ret)
7524137ff4cSJacques Vidrine 	goto out;
7534137ff4cSJacques Vidrine 
754*ae771770SStanislav Sedov     rc = ldap_search_ext_s(HDB2LDAP(db), dn, LDAP_SCOPE_SUBTREE,
755*ae771770SStanislav Sedov 			   filter, krb5principal_attrs, 0,
756*ae771770SStanislav Sedov 			   NULL, NULL, NULL,
7575e9cd1aeSAssar Westerlund 			   0, &res);
758c19800e8SDoug Rabson     if (check_ldap(context, db, rc)) {
7595e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
760*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "ldap_search_ext_s: "
761*ae771770SStanislav Sedov 			       "filter: %s error: %s",
762*ae771770SStanislav Sedov 			       filter, ldap_err2string(rc));
7635e9cd1aeSAssar Westerlund 	goto out;
7645e9cd1aeSAssar Westerlund     }
7655e9cd1aeSAssar Westerlund 
766c19800e8SDoug Rabson     e = ldap_first_entry(HDB2LDAP(db), res);
7675e9cd1aeSAssar Westerlund     if (e == NULL) {
7685e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
7695e9cd1aeSAssar Westerlund 	goto out;
7705e9cd1aeSAssar Westerlund     }
7715e9cd1aeSAssar Westerlund 
772*ae771770SStanislav Sedov     ret = LDAP_get_string_value(db, e, "krb5PrincipalName", &p);
773*ae771770SStanislav Sedov     if (ret) {
7745e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
7755e9cd1aeSAssar Westerlund 	goto out;
7765e9cd1aeSAssar Westerlund     }
7775e9cd1aeSAssar Westerlund 
778*ae771770SStanislav Sedov     ret = krb5_parse_name(context, p, principal);
779*ae771770SStanislav Sedov     free(p);
7805e9cd1aeSAssar Westerlund 
7815e9cd1aeSAssar Westerlund   out:
782c19800e8SDoug Rabson     if (res)
7835e9cd1aeSAssar Westerlund 	ldap_msgfree(res);
784c19800e8SDoug Rabson 
7855e9cd1aeSAssar Westerlund     return ret;
7865e9cd1aeSAssar Westerlund }
7875e9cd1aeSAssar Westerlund 
788*ae771770SStanislav Sedov static int
789*ae771770SStanislav Sedov need_quote(unsigned char c)
790*ae771770SStanislav Sedov {
791*ae771770SStanislav Sedov     return (c & 0x80) ||
792*ae771770SStanislav Sedov 	(c < 32) ||
793*ae771770SStanislav Sedov 	(c == '(') ||
794*ae771770SStanislav Sedov 	(c == ')') ||
795*ae771770SStanislav Sedov 	(c == '*') ||
796*ae771770SStanislav Sedov 	(c == '\\') ||
797*ae771770SStanislav Sedov 	(c == 0x7f);
798*ae771770SStanislav Sedov }
799*ae771770SStanislav Sedov 
800*ae771770SStanislav Sedov const static char hexchar[] = "0123456789ABCDEF";
801*ae771770SStanislav Sedov 
802*ae771770SStanislav Sedov static krb5_error_code
803*ae771770SStanislav Sedov escape_value(krb5_context context, const unsigned char *unquoted, char **quoted)
804*ae771770SStanislav Sedov {
805*ae771770SStanislav Sedov     size_t i, len;
806*ae771770SStanislav Sedov 
807*ae771770SStanislav Sedov     for (i = 0, len = 0; unquoted[i] != '\0'; i++, len++) {
808*ae771770SStanislav Sedov 	if (need_quote((unsigned char)unquoted[i]))
809*ae771770SStanislav Sedov 	    len += 2;
810*ae771770SStanislav Sedov     }
811*ae771770SStanislav Sedov 
812*ae771770SStanislav Sedov     *quoted = malloc(len + 1);
813*ae771770SStanislav Sedov     if (*quoted == NULL) {
814*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
815*ae771770SStanislav Sedov 	return ENOMEM;
816*ae771770SStanislav Sedov     }
817*ae771770SStanislav Sedov 
818*ae771770SStanislav Sedov     for (i = 0; unquoted[0] ; unquoted++) {
819*ae771770SStanislav Sedov 	if (need_quote((unsigned char *)unquoted[0])) {
820*ae771770SStanislav Sedov 	    (*quoted)[i++] = '\\';
821*ae771770SStanislav Sedov 	    (*quoted)[i++] = hexchar[(unquoted[0] >> 4) & 0xf];
822*ae771770SStanislav Sedov 	    (*quoted)[i++] = hexchar[(unquoted[0]     ) & 0xf];
823*ae771770SStanislav Sedov 	} else
824*ae771770SStanislav Sedov 	    (*quoted)[i++] = (char)unquoted[0];
825*ae771770SStanislav Sedov     }
826*ae771770SStanislav Sedov     (*quoted)[i] = '\0';
827*ae771770SStanislav Sedov     return 0;
828*ae771770SStanislav Sedov }
829*ae771770SStanislav Sedov 
830*ae771770SStanislav Sedov 
8315e9cd1aeSAssar Westerlund static krb5_error_code
832c19800e8SDoug Rabson LDAP__lookup_princ(krb5_context context,
833c19800e8SDoug Rabson 		   HDB *db,
834c19800e8SDoug Rabson 		   const char *princname,
835c19800e8SDoug Rabson 		   const char *userid,
8365e9cd1aeSAssar Westerlund 		   LDAPMessage **msg)
8375e9cd1aeSAssar Westerlund {
8385e9cd1aeSAssar Westerlund     krb5_error_code ret;
839c19800e8SDoug Rabson     int rc;
840*ae771770SStanislav Sedov     char *quote, *filter = NULL;
8415e9cd1aeSAssar Westerlund 
842c19800e8SDoug Rabson     ret = LDAP__connect(context, db);
843c19800e8SDoug Rabson     if (ret)
844c19800e8SDoug Rabson 	return ret;
8455e9cd1aeSAssar Westerlund 
846*ae771770SStanislav Sedov     /*
847*ae771770SStanislav Sedov      * Quote searches that contain filter language, this quote
848*ae771770SStanislav Sedov      * searches for *@REALM, which takes very long time.
849*ae771770SStanislav Sedov      */
850*ae771770SStanislav Sedov 
851*ae771770SStanislav Sedov     ret = escape_value(context, princname, &quote);
852*ae771770SStanislav Sedov     if (ret)
853*ae771770SStanislav Sedov 	goto out;
854*ae771770SStanislav Sedov 
855c19800e8SDoug Rabson     rc = asprintf(&filter,
856c19800e8SDoug Rabson 		  "(&(objectClass=krb5Principal)(krb5PrincipalName=%s))",
857*ae771770SStanislav Sedov 		  quote);
858*ae771770SStanislav Sedov     free(quote);
859*ae771770SStanislav Sedov 
8605e9cd1aeSAssar Westerlund     if (rc < 0) {
8615e9cd1aeSAssar Westerlund 	ret = ENOMEM;
862*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "malloc: out of memory");
8635e9cd1aeSAssar Westerlund 	goto out;
8645e9cd1aeSAssar Westerlund     }
8655e9cd1aeSAssar Westerlund 
866c19800e8SDoug Rabson     ret = LDAP_no_size_limit(context, HDB2LDAP(db));
867c19800e8SDoug Rabson     if (ret)
868c19800e8SDoug Rabson 	goto out;
869c19800e8SDoug Rabson 
870*ae771770SStanislav Sedov     rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db),
871*ae771770SStanislav Sedov 			   LDAP_SCOPE_SUBTREE, filter,
872*ae771770SStanislav Sedov 			   krb5kdcentry_attrs, 0,
873*ae771770SStanislav Sedov 			   NULL, NULL, NULL,
874*ae771770SStanislav Sedov 			   0, msg);
875c19800e8SDoug Rabson     if (check_ldap(context, db, rc)) {
876c19800e8SDoug Rabson 	ret = HDB_ERR_NOENTRY;
877*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "ldap_search_ext_s: "
878*ae771770SStanislav Sedov 			      "filter: %s - error: %s",
879*ae771770SStanislav Sedov 			      filter, ldap_err2string(rc));
8804137ff4cSJacques Vidrine 	goto out;
8814137ff4cSJacques Vidrine     }
8825e9cd1aeSAssar Westerlund 
883c19800e8SDoug Rabson     if (userid && ldap_count_entries(HDB2LDAP(db), *msg) == 0) {
884c19800e8SDoug Rabson 	free(filter);
885c19800e8SDoug Rabson 	filter = NULL;
886c19800e8SDoug Rabson 	ldap_msgfree(*msg);
887c19800e8SDoug Rabson 	*msg = NULL;
888c19800e8SDoug Rabson 
889*ae771770SStanislav Sedov 	ret = escape_value(context, userid, &quote);
890*ae771770SStanislav Sedov 	if (ret)
891*ae771770SStanislav Sedov 	    goto out;
892*ae771770SStanislav Sedov 
893c19800e8SDoug Rabson 	rc = asprintf(&filter,
894c19800e8SDoug Rabson 	    "(&(|(objectClass=sambaSamAccount)(objectClass=%s))(uid=%s))",
895*ae771770SStanislav Sedov 		      structural_object, quote);
896*ae771770SStanislav Sedov 	free(quote);
897c19800e8SDoug Rabson 	if (rc < 0) {
898c19800e8SDoug Rabson 	    ret = ENOMEM;
899*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "asprintf: out of memory");
900c19800e8SDoug Rabson 	    goto out;
901c19800e8SDoug Rabson 	}
902c19800e8SDoug Rabson 
903c19800e8SDoug Rabson 	ret = LDAP_no_size_limit(context, HDB2LDAP(db));
904c19800e8SDoug Rabson 	if (ret)
905c19800e8SDoug Rabson 	    goto out;
906c19800e8SDoug Rabson 
907*ae771770SStanislav Sedov 	rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE,
908*ae771770SStanislav Sedov 			       filter, krb5kdcentry_attrs, 0,
909*ae771770SStanislav Sedov 			       NULL, NULL, NULL,
910*ae771770SStanislav Sedov 			       0, msg);
911c19800e8SDoug Rabson 	if (check_ldap(context, db, rc)) {
9125e9cd1aeSAssar Westerlund 	    ret = HDB_ERR_NOENTRY;
913*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,
914*ae771770SStanislav Sedov 				   "ldap_search_ext_s: filter: %s error: %s",
915*ae771770SStanislav Sedov 				   filter, ldap_err2string(rc));
9165e9cd1aeSAssar Westerlund 	    goto out;
9175e9cd1aeSAssar Westerlund 	}
918c19800e8SDoug Rabson     }
9195e9cd1aeSAssar Westerlund 
9205e9cd1aeSAssar Westerlund     ret = 0;
9215e9cd1aeSAssar Westerlund 
9225e9cd1aeSAssar Westerlund   out:
923c19800e8SDoug Rabson     if (filter)
9245e9cd1aeSAssar Westerlund 	free(filter);
925c19800e8SDoug Rabson 
9265e9cd1aeSAssar Westerlund     return ret;
9275e9cd1aeSAssar Westerlund }
9285e9cd1aeSAssar Westerlund 
9295e9cd1aeSAssar Westerlund static krb5_error_code
9305e9cd1aeSAssar Westerlund LDAP_principal2message(krb5_context context, HDB * db,
931c19800e8SDoug Rabson 		       krb5_const_principal princ, LDAPMessage ** msg)
9325e9cd1aeSAssar Westerlund {
933c19800e8SDoug Rabson     char *name, *name_short = NULL;
9345e9cd1aeSAssar Westerlund     krb5_error_code ret;
935c19800e8SDoug Rabson     krb5_realm *r, *r0;
9365e9cd1aeSAssar Westerlund 
937c19800e8SDoug Rabson     *msg = NULL;
938c19800e8SDoug Rabson 
939c19800e8SDoug Rabson     ret = krb5_unparse_name(context, princ, &name);
940c19800e8SDoug Rabson     if (ret)
941c19800e8SDoug Rabson 	return ret;
942c19800e8SDoug Rabson 
943c19800e8SDoug Rabson     ret = krb5_get_default_realms(context, &r0);
944c19800e8SDoug Rabson     if(ret) {
945c19800e8SDoug Rabson 	free(name);
9465e9cd1aeSAssar Westerlund 	return ret;
9475e9cd1aeSAssar Westerlund     }
948c19800e8SDoug Rabson     for (r = r0; *r != NULL; r++) {
949c19800e8SDoug Rabson 	if(strcmp(krb5_principal_get_realm(context, princ), *r) == 0) {
950c19800e8SDoug Rabson 	    ret = krb5_unparse_name_short(context, princ, &name_short);
951c19800e8SDoug Rabson 	    if (ret) {
952c19800e8SDoug Rabson 		krb5_free_host_realm(context, r0);
953c19800e8SDoug Rabson 		free(name);
954c19800e8SDoug Rabson 		return ret;
955c19800e8SDoug Rabson 	    }
956c19800e8SDoug Rabson 	    break;
957c19800e8SDoug Rabson 	}
958c19800e8SDoug Rabson     }
959c19800e8SDoug Rabson     krb5_free_host_realm(context, r0);
9605e9cd1aeSAssar Westerlund 
961c19800e8SDoug Rabson     ret = LDAP__lookup_princ(context, db, name, name_short, msg);
962c19800e8SDoug Rabson     free(name);
963c19800e8SDoug Rabson     free(name_short);
9645e9cd1aeSAssar Westerlund 
9655e9cd1aeSAssar Westerlund     return ret;
9665e9cd1aeSAssar Westerlund }
9675e9cd1aeSAssar Westerlund 
9685e9cd1aeSAssar Westerlund /*
9695e9cd1aeSAssar Westerlund  * Construct an hdb_entry from a directory entry.
9705e9cd1aeSAssar Westerlund  */
9715e9cd1aeSAssar Westerlund static krb5_error_code
9725e9cd1aeSAssar Westerlund LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
973*ae771770SStanislav Sedov 		   int flags, hdb_entry_ex * ent)
9745e9cd1aeSAssar Westerlund {
975c19800e8SDoug Rabson     char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL;
976c19800e8SDoug Rabson     char *samba_acct_flags = NULL;
9775e9cd1aeSAssar Westerlund     struct berval **keys;
978*ae771770SStanislav Sedov     struct berval **vals;
979*ae771770SStanislav Sedov     int tmp, tmp_time, i, ret, have_arcfour = 0;
9805e9cd1aeSAssar Westerlund 
9815e9cd1aeSAssar Westerlund     memset(ent, 0, sizeof(*ent));
982c19800e8SDoug Rabson     ent->entry.flags = int2HDBFlags(0);
9835e9cd1aeSAssar Westerlund 
984c19800e8SDoug Rabson     ret = LDAP_get_string_value(db, msg, "krb5PrincipalName", &unparsed_name);
985c19800e8SDoug Rabson     if (ret == 0) {
986c19800e8SDoug Rabson 	ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal);
987c19800e8SDoug Rabson 	if (ret)
9885e9cd1aeSAssar Westerlund 	    goto out;
989c19800e8SDoug Rabson     } else {
990c19800e8SDoug Rabson 	ret = LDAP_get_string_value(db, msg, "uid",
991c19800e8SDoug Rabson 				    &unparsed_name);
992c19800e8SDoug Rabson 	if (ret == 0) {
993c19800e8SDoug Rabson 	    ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal);
994c19800e8SDoug Rabson 	    if (ret)
995c19800e8SDoug Rabson 		goto out;
996c19800e8SDoug Rabson 	} else {
997*ae771770SStanislav Sedov 	    krb5_set_error_message(context, HDB_ERR_NOENTRY,
998*ae771770SStanislav Sedov 				   "hdb-ldap: ldap entry missing"
999c19800e8SDoug Rabson 				  "principal name");
1000c19800e8SDoug Rabson 	    return HDB_ERR_NOENTRY;
1001c19800e8SDoug Rabson 	}
10025e9cd1aeSAssar Westerlund     }
10035e9cd1aeSAssar Westerlund 
1004c19800e8SDoug Rabson     {
1005c19800e8SDoug Rabson 	int integer;
1006c19800e8SDoug Rabson 	ret = LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber",
1007c19800e8SDoug Rabson 				     &integer);
1008c19800e8SDoug Rabson 	if (ret)
1009c19800e8SDoug Rabson 	    ent->entry.kvno = 0;
1010c19800e8SDoug Rabson 	else
1011c19800e8SDoug Rabson 	    ent->entry.kvno = integer;
10125e9cd1aeSAssar Westerlund     }
10135e9cd1aeSAssar Westerlund 
1014c19800e8SDoug Rabson     keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key");
10155e9cd1aeSAssar Westerlund     if (keys != NULL) {
10165e9cd1aeSAssar Westerlund 	int i;
10175e9cd1aeSAssar Westerlund 	size_t l;
10185e9cd1aeSAssar Westerlund 
1019c19800e8SDoug Rabson 	ent->entry.keys.len = ldap_count_values_len(keys);
1020c19800e8SDoug Rabson 	ent->entry.keys.val = (Key *) calloc(ent->entry.keys.len, sizeof(Key));
1021c19800e8SDoug Rabson 	if (ent->entry.keys.val == NULL) {
10224137ff4cSJacques Vidrine 	    ret = ENOMEM;
1023*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "calloc: out of memory");
10244137ff4cSJacques Vidrine 	    goto out;
10254137ff4cSJacques Vidrine 	}
1026c19800e8SDoug Rabson 	for (i = 0; i < ent->entry.keys.len; i++) {
10275e9cd1aeSAssar Westerlund 	    decode_Key((unsigned char *) keys[i]->bv_val,
1028c19800e8SDoug Rabson 		       (size_t) keys[i]->bv_len, &ent->entry.keys.val[i], &l);
10295e9cd1aeSAssar Westerlund 	}
10305e9cd1aeSAssar Westerlund 	ber_bvecfree(keys);
10315e9cd1aeSAssar Westerlund     } else {
10325e9cd1aeSAssar Westerlund #if 1
10335e9cd1aeSAssar Westerlund 	/*
10345e9cd1aeSAssar Westerlund 	 * This violates the ASN1 but it allows a principal to
10355e9cd1aeSAssar Westerlund 	 * be related to a general directory entry without creating
10365e9cd1aeSAssar Westerlund 	 * the keys. Hopefully it's OK.
10375e9cd1aeSAssar Westerlund 	 */
1038c19800e8SDoug Rabson 	ent->entry.keys.len = 0;
1039c19800e8SDoug Rabson 	ent->entry.keys.val = NULL;
10405e9cd1aeSAssar Westerlund #else
10415e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
10425e9cd1aeSAssar Westerlund 	goto out;
10435e9cd1aeSAssar Westerlund #endif
10445e9cd1aeSAssar Westerlund     }
10455e9cd1aeSAssar Westerlund 
1046*ae771770SStanislav Sedov     vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType");
1047*ae771770SStanislav Sedov     if (vals != NULL) {
1048c19800e8SDoug Rabson 	int i;
1049c19800e8SDoug Rabson 
1050c19800e8SDoug Rabson 	ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes)));
1051c19800e8SDoug Rabson 	if (ent->entry.etypes == NULL) {
1052c19800e8SDoug Rabson 	    ret = ENOMEM;
1053*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret,"malloc: out of memory");
1054c19800e8SDoug Rabson 	    goto out;
1055c19800e8SDoug Rabson 	}
1056*ae771770SStanislav Sedov 	ent->entry.etypes->len = ldap_count_values_len(vals);
1057c19800e8SDoug Rabson 	ent->entry.etypes->val = calloc(ent->entry.etypes->len, sizeof(int));
1058c19800e8SDoug Rabson 	if (ent->entry.etypes->val == NULL) {
1059c19800e8SDoug Rabson 	    ret = ENOMEM;
1060*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1061*ae771770SStanislav Sedov 	    ent->entry.etypes->len = 0;
1062c19800e8SDoug Rabson 	    goto out;
1063c19800e8SDoug Rabson 	}
1064c19800e8SDoug Rabson 	for (i = 0; i < ent->entry.etypes->len; i++) {
1065*ae771770SStanislav Sedov 	    char *buf;
1066*ae771770SStanislav Sedov 
1067*ae771770SStanislav Sedov 	    buf = malloc(vals[i]->bv_len + 1);
1068*ae771770SStanislav Sedov 	    if (buf == NULL) {
1069*ae771770SStanislav Sedov 		ret = ENOMEM;
1070*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, "malloc: out of memory");
1071*ae771770SStanislav Sedov 		goto out;
1072c19800e8SDoug Rabson 	    }
1073*ae771770SStanislav Sedov 	    memcpy(buf, vals[i]->bv_val, vals[i]->bv_len);
1074*ae771770SStanislav Sedov 	    buf[vals[i]->bv_len] = '\0';
1075*ae771770SStanislav Sedov 	    ent->entry.etypes->val[i] = atoi(buf);
1076*ae771770SStanislav Sedov 	    free(buf);
1077*ae771770SStanislav Sedov 	}
1078*ae771770SStanislav Sedov 	ldap_value_free_len(vals);
10795e9cd1aeSAssar Westerlund     }
10805e9cd1aeSAssar Westerlund 
1081c19800e8SDoug Rabson     for (i = 0; i < ent->entry.keys.len; i++) {
1082c19800e8SDoug Rabson 	if (ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
1083c19800e8SDoug Rabson 	    have_arcfour = 1;
1084c19800e8SDoug Rabson 	    break;
1085c19800e8SDoug Rabson 	}
1086c19800e8SDoug Rabson     }
1087c19800e8SDoug Rabson 
1088c19800e8SDoug Rabson     /* manually construct the NT (type 23) key */
1089c19800e8SDoug Rabson     ret = LDAP_get_string_value(db, msg, "sambaNTPassword", &ntPasswordIN);
1090c19800e8SDoug Rabson     if (ret == 0 && have_arcfour == 0) {
1091c19800e8SDoug Rabson 	unsigned *etypes;
1092c19800e8SDoug Rabson 	Key *keys;
1093c19800e8SDoug Rabson 	int i;
1094c19800e8SDoug Rabson 
1095c19800e8SDoug Rabson 	keys = realloc(ent->entry.keys.val,
1096c19800e8SDoug Rabson 		       (ent->entry.keys.len + 1) * sizeof(ent->entry.keys.val[0]));
1097c19800e8SDoug Rabson 	if (keys == NULL) {
1098c19800e8SDoug Rabson 	    free(ntPasswordIN);
1099c19800e8SDoug Rabson 	    ret = ENOMEM;
1100*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1101c19800e8SDoug Rabson 	    goto out;
1102c19800e8SDoug Rabson 	}
1103c19800e8SDoug Rabson 	ent->entry.keys.val = keys;
1104c19800e8SDoug Rabson 	memset(&ent->entry.keys.val[ent->entry.keys.len], 0, sizeof(Key));
1105c19800e8SDoug Rabson 	ent->entry.keys.val[ent->entry.keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5;
1106c19800e8SDoug Rabson 	ret = krb5_data_alloc (&ent->entry.keys.val[ent->entry.keys.len].key.keyvalue, 16);
1107c19800e8SDoug Rabson 	if (ret) {
1108*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1109c19800e8SDoug Rabson 	    free(ntPasswordIN);
1110c19800e8SDoug Rabson 	    ret = ENOMEM;
1111c19800e8SDoug Rabson 	    goto out;
1112c19800e8SDoug Rabson 	}
1113c19800e8SDoug Rabson 	ret = hex_decode(ntPasswordIN,
1114c19800e8SDoug Rabson 			 ent->entry.keys.val[ent->entry.keys.len].key.keyvalue.data, 16);
1115c19800e8SDoug Rabson 	ent->entry.keys.len++;
1116c19800e8SDoug Rabson 
1117c19800e8SDoug Rabson 	if (ent->entry.etypes == NULL) {
1118c19800e8SDoug Rabson 	    ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes)));
1119c19800e8SDoug Rabson 	    if (ent->entry.etypes == NULL) {
1120c19800e8SDoug Rabson 		ret = ENOMEM;
1121*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, "malloc: out of memory");
1122c19800e8SDoug Rabson 		goto out;
1123c19800e8SDoug Rabson 	    }
1124c19800e8SDoug Rabson 	    ent->entry.etypes->val = NULL;
1125c19800e8SDoug Rabson 	    ent->entry.etypes->len = 0;
1126c19800e8SDoug Rabson 	}
1127c19800e8SDoug Rabson 
1128c19800e8SDoug Rabson 	for (i = 0; i < ent->entry.etypes->len; i++)
1129c19800e8SDoug Rabson 	    if (ent->entry.etypes->val[i] == ETYPE_ARCFOUR_HMAC_MD5)
1130c19800e8SDoug Rabson 		break;
1131c19800e8SDoug Rabson 	/* If there is no ARCFOUR enctype, add one */
1132c19800e8SDoug Rabson 	if (i == ent->entry.etypes->len) {
1133c19800e8SDoug Rabson 	    etypes = realloc(ent->entry.etypes->val,
1134c19800e8SDoug Rabson 			     (ent->entry.etypes->len + 1) *
1135c19800e8SDoug Rabson 			     sizeof(ent->entry.etypes->val[0]));
1136c19800e8SDoug Rabson 	    if (etypes == NULL) {
1137c19800e8SDoug Rabson 		ret = ENOMEM;
1138*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, "malloc: out of memory");
1139c19800e8SDoug Rabson 		goto out;
1140c19800e8SDoug Rabson 	    }
1141c19800e8SDoug Rabson 	    ent->entry.etypes->val = etypes;
1142c19800e8SDoug Rabson 	    ent->entry.etypes->val[ent->entry.etypes->len] =
1143c19800e8SDoug Rabson 		ETYPE_ARCFOUR_HMAC_MD5;
1144c19800e8SDoug Rabson 	    ent->entry.etypes->len++;
1145c19800e8SDoug Rabson 	}
1146c19800e8SDoug Rabson     }
1147c19800e8SDoug Rabson 
1148c19800e8SDoug Rabson     ret = LDAP_get_generalized_time_value(db, msg, "createTimestamp",
1149c19800e8SDoug Rabson 					  &ent->entry.created_by.time);
1150c19800e8SDoug Rabson     if (ret)
1151c19800e8SDoug Rabson 	ent->entry.created_by.time = time(NULL);
1152c19800e8SDoug Rabson 
1153c19800e8SDoug Rabson     ent->entry.created_by.principal = NULL;
11545e9cd1aeSAssar Westerlund 
1155*ae771770SStanislav Sedov     if (flags & HDB_F_ADMIN_DATA) {
11565e9cd1aeSAssar Westerlund 	ret = LDAP_get_string_value(db, msg, "creatorsName", &dn);
11575e9cd1aeSAssar Westerlund 	if (ret == 0) {
1158*ae771770SStanislav Sedov 	    LDAP_dn2principal(context, db, dn, &ent->entry.created_by.principal);
11595e9cd1aeSAssar Westerlund 	    free(dn);
11605e9cd1aeSAssar Westerlund 	}
11615e9cd1aeSAssar Westerlund 
1162*ae771770SStanislav Sedov 	ent->entry.modified_by = calloc(1, sizeof(*ent->entry.modified_by));
1163c19800e8SDoug Rabson 	if (ent->entry.modified_by == NULL) {
11645e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
1165*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
11665e9cd1aeSAssar Westerlund 	    goto out;
11675e9cd1aeSAssar Westerlund 	}
1168*ae771770SStanislav Sedov 
1169c19800e8SDoug Rabson 	ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp",
1170c19800e8SDoug Rabson 					      &ent->entry.modified_by->time);
11715e9cd1aeSAssar Westerlund 	if (ret == 0) {
11725e9cd1aeSAssar Westerlund 	    ret = LDAP_get_string_value(db, msg, "modifiersName", &dn);
1173*ae771770SStanislav Sedov 	    if (ret == 0) {
1174*ae771770SStanislav Sedov 		LDAP_dn2principal(context, db, dn, &ent->entry.modified_by->principal);
11755e9cd1aeSAssar Westerlund 		free(dn);
11765e9cd1aeSAssar Westerlund 	    } else {
1177c19800e8SDoug Rabson 		free(ent->entry.modified_by);
1178c19800e8SDoug Rabson 		ent->entry.modified_by = NULL;
11795e9cd1aeSAssar Westerlund 	    }
1180*ae771770SStanislav Sedov 	}
1181*ae771770SStanislav Sedov     }
11825e9cd1aeSAssar Westerlund 
1183c19800e8SDoug Rabson     ent->entry.valid_start = malloc(sizeof(*ent->entry.valid_start));
1184c19800e8SDoug Rabson     if (ent->entry.valid_start == NULL) {
11855e9cd1aeSAssar Westerlund 	ret = ENOMEM;
1186*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "malloc: out of memory");
11875e9cd1aeSAssar Westerlund 	goto out;
11885e9cd1aeSAssar Westerlund     }
1189c19800e8SDoug Rabson     ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart",
1190c19800e8SDoug Rabson 					  ent->entry.valid_start);
1191c19800e8SDoug Rabson     if (ret) {
11925e9cd1aeSAssar Westerlund 	/* OPTIONAL */
1193c19800e8SDoug Rabson 	free(ent->entry.valid_start);
1194c19800e8SDoug Rabson 	ent->entry.valid_start = NULL;
11955e9cd1aeSAssar Westerlund     }
11965e9cd1aeSAssar Westerlund 
1197c19800e8SDoug Rabson     ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end));
1198c19800e8SDoug Rabson     if (ent->entry.valid_end == NULL) {
11994137ff4cSJacques Vidrine 	ret = ENOMEM;
1200*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "malloc: out of memory");
12015e9cd1aeSAssar Westerlund 	goto out;
12025e9cd1aeSAssar Westerlund     }
1203c19800e8SDoug Rabson     ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd",
1204c19800e8SDoug Rabson 					  ent->entry.valid_end);
1205c19800e8SDoug Rabson     if (ret) {
12065e9cd1aeSAssar Westerlund 	/* OPTIONAL */
1207c19800e8SDoug Rabson 	free(ent->entry.valid_end);
1208c19800e8SDoug Rabson 	ent->entry.valid_end = NULL;
12095e9cd1aeSAssar Westerlund     }
12105e9cd1aeSAssar Westerlund 
1211c19800e8SDoug Rabson     ret = LDAP_get_integer_value(db, msg, "sambaKickoffTime", &tmp_time);
1212c19800e8SDoug Rabson     if (ret == 0) {
1213c19800e8SDoug Rabson  	if (ent->entry.valid_end == NULL) {
1214c19800e8SDoug Rabson  	    ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end));
1215c19800e8SDoug Rabson  	    if (ent->entry.valid_end == NULL) {
12164137ff4cSJacques Vidrine  		ret = ENOMEM;
1217*ae771770SStanislav Sedov  		krb5_set_error_message(context, ret, "malloc: out of memory");
12185e9cd1aeSAssar Westerlund  		goto out;
12195e9cd1aeSAssar Westerlund  	    }
1220c19800e8SDoug Rabson  	}
1221c19800e8SDoug Rabson  	*ent->entry.valid_end = tmp_time;
1222c19800e8SDoug Rabson     }
1223c19800e8SDoug Rabson 
1224c19800e8SDoug Rabson     ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
1225c19800e8SDoug Rabson     if (ent->entry.pw_end == NULL) {
1226c19800e8SDoug Rabson 	ret = ENOMEM;
1227*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "malloc: out of memory");
1228c19800e8SDoug Rabson 	goto out;
1229c19800e8SDoug Rabson     }
1230c19800e8SDoug Rabson     ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd",
1231c19800e8SDoug Rabson 					  ent->entry.pw_end);
1232c19800e8SDoug Rabson     if (ret) {
12335e9cd1aeSAssar Westerlund 	/* OPTIONAL */
1234c19800e8SDoug Rabson 	free(ent->entry.pw_end);
1235c19800e8SDoug Rabson 	ent->entry.pw_end = NULL;
12365e9cd1aeSAssar Westerlund     }
12375e9cd1aeSAssar Westerlund 
1238*ae771770SStanislav Sedov     ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time);
1239*ae771770SStanislav Sedov     if (ret == 0) {
1240*ae771770SStanislav Sedov 	time_t delta;
1241*ae771770SStanislav Sedov 
1242*ae771770SStanislav Sedov 	if (ent->entry.pw_end == NULL) {
1243*ae771770SStanislav Sedov             ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
1244*ae771770SStanislav Sedov             if (ent->entry.pw_end == NULL) {
1245*ae771770SStanislav Sedov                 ret = ENOMEM;
1246*ae771770SStanislav Sedov                 krb5_set_error_message(context, ret, "malloc: out of memory");
1247*ae771770SStanislav Sedov                 goto out;
1248*ae771770SStanislav Sedov             }
1249*ae771770SStanislav Sedov         }
1250*ae771770SStanislav Sedov 
1251*ae771770SStanislav Sedov 	delta = krb5_config_get_time_default(context, NULL,
1252*ae771770SStanislav Sedov 					     365 * 24 * 60 * 60,
1253*ae771770SStanislav Sedov 					     "kadmin",
1254*ae771770SStanislav Sedov 					     "password_lifetime",
1255*ae771770SStanislav Sedov 					     NULL);
1256*ae771770SStanislav Sedov         *ent->entry.pw_end = tmp_time + delta;
1257*ae771770SStanislav Sedov     }
1258*ae771770SStanislav Sedov 
1259c19800e8SDoug Rabson     ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time);
1260c19800e8SDoug Rabson     if (ret == 0) {
1261c19800e8SDoug Rabson 	if (ent->entry.pw_end == NULL) {
1262c19800e8SDoug Rabson 	    ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
1263c19800e8SDoug Rabson 	    if (ent->entry.pw_end == NULL) {
12645e9cd1aeSAssar Westerlund 		ret = ENOMEM;
1265*ae771770SStanislav Sedov 		krb5_set_error_message(context, ret, "malloc: out of memory");
12665e9cd1aeSAssar Westerlund 		goto out;
12675e9cd1aeSAssar Westerlund 	    }
1268c19800e8SDoug Rabson 	}
1269c19800e8SDoug Rabson 	*ent->entry.pw_end = tmp_time;
12705e9cd1aeSAssar Westerlund     }
12715e9cd1aeSAssar Westerlund 
1272c19800e8SDoug Rabson     /* OPTIONAL */
1273c19800e8SDoug Rabson     ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time);
1274c19800e8SDoug Rabson     if (ret == 0)
1275c19800e8SDoug Rabson 	hdb_entry_set_pw_change_time(context, &ent->entry, tmp_time);
1276c19800e8SDoug Rabson 
1277c19800e8SDoug Rabson     {
1278c19800e8SDoug Rabson 	int max_life;
1279c19800e8SDoug Rabson 
1280c19800e8SDoug Rabson 	ent->entry.max_life = malloc(sizeof(*ent->entry.max_life));
1281c19800e8SDoug Rabson 	if (ent->entry.max_life == NULL) {
12825e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
1283*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
12845e9cd1aeSAssar Westerlund 	    goto out;
12855e9cd1aeSAssar Westerlund 	}
1286c19800e8SDoug Rabson 	ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", &max_life);
1287c19800e8SDoug Rabson 	if (ret) {
1288c19800e8SDoug Rabson 	    free(ent->entry.max_life);
1289c19800e8SDoug Rabson 	    ent->entry.max_life = NULL;
1290c19800e8SDoug Rabson 	} else
1291c19800e8SDoug Rabson 	    *ent->entry.max_life = max_life;
12925e9cd1aeSAssar Westerlund     }
12935e9cd1aeSAssar Westerlund 
1294c19800e8SDoug Rabson     {
1295c19800e8SDoug Rabson 	int max_renew;
1296c19800e8SDoug Rabson 
1297c19800e8SDoug Rabson 	ent->entry.max_renew = malloc(sizeof(*ent->entry.max_renew));
1298c19800e8SDoug Rabson 	if (ent->entry.max_renew == NULL) {
1299c19800e8SDoug Rabson 	    ret = ENOMEM;
1300*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1301c19800e8SDoug Rabson 	    goto out;
1302c19800e8SDoug Rabson 	}
1303c19800e8SDoug Rabson 	ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", &max_renew);
1304c19800e8SDoug Rabson 	if (ret) {
1305c19800e8SDoug Rabson 	    free(ent->entry.max_renew);
1306c19800e8SDoug Rabson 	    ent->entry.max_renew = NULL;
1307c19800e8SDoug Rabson 	} else
1308c19800e8SDoug Rabson 	    *ent->entry.max_renew = max_renew;
1309c19800e8SDoug Rabson     }
1310c19800e8SDoug Rabson 
1311*ae771770SStanislav Sedov     ret = LDAP_get_integer_value(db, msg, "krb5KDCFlags", &tmp);
1312*ae771770SStanislav Sedov     if (ret)
13135e9cd1aeSAssar Westerlund 	tmp = 0;
13145e9cd1aeSAssar Westerlund 
1315c19800e8SDoug Rabson     ent->entry.flags = int2HDBFlags(tmp);
1316c19800e8SDoug Rabson 
1317c19800e8SDoug Rabson     /* Try and find Samba flags to put into the mix */
1318c19800e8SDoug Rabson     ret = LDAP_get_string_value(db, msg, "sambaAcctFlags", &samba_acct_flags);
1319c19800e8SDoug Rabson     if (ret == 0) {
1320c19800e8SDoug Rabson 	/* parse the [UXW...] string:
1321c19800e8SDoug Rabson 
1322c19800e8SDoug Rabson 	   'N'    No password
1323c19800e8SDoug Rabson 	   'D'    Disabled
1324c19800e8SDoug Rabson 	   'H'    Homedir required
1325c19800e8SDoug Rabson 	   'T'    Temp account.
1326c19800e8SDoug Rabson 	   'U'    User account (normal)
1327c19800e8SDoug Rabson 	   'M'    MNS logon user account - what is this ?
1328c19800e8SDoug Rabson 	   'W'    Workstation account
1329c19800e8SDoug Rabson 	   'S'    Server account
1330c19800e8SDoug Rabson 	   'L'    Locked account
1331c19800e8SDoug Rabson 	   'X'    No Xpiry on password
1332c19800e8SDoug Rabson 	   'I'    Interdomain trust account
1333c19800e8SDoug Rabson 
1334c19800e8SDoug Rabson 	*/
1335c19800e8SDoug Rabson 
13365e9cd1aeSAssar Westerlund 	int i;
1337c19800e8SDoug Rabson 	int flags_len = strlen(samba_acct_flags);
13385e9cd1aeSAssar Westerlund 
1339c19800e8SDoug Rabson 	if (flags_len < 2)
1340c19800e8SDoug Rabson 	    goto out2;
1341c19800e8SDoug Rabson 
1342c19800e8SDoug Rabson 	if (samba_acct_flags[0] != '['
1343c19800e8SDoug Rabson 	    || samba_acct_flags[flags_len - 1] != ']')
1344c19800e8SDoug Rabson 	    goto out2;
1345c19800e8SDoug Rabson 
1346c19800e8SDoug Rabson 	/* Allow forwarding */
1347c19800e8SDoug Rabson 	if (samba_forwardable)
1348c19800e8SDoug Rabson 	    ent->entry.flags.forwardable = TRUE;
1349c19800e8SDoug Rabson 
1350c19800e8SDoug Rabson 	for (i=0; i < flags_len; i++) {
1351c19800e8SDoug Rabson 	    switch (samba_acct_flags[i]) {
1352c19800e8SDoug Rabson 	    case ' ':
1353c19800e8SDoug Rabson 	    case '[':
1354c19800e8SDoug Rabson 	    case ']':
1355c19800e8SDoug Rabson 		break;
1356c19800e8SDoug Rabson 	    case 'N':
1357c19800e8SDoug Rabson 		/* how to handle no password in kerberos? */
1358c19800e8SDoug Rabson 		break;
1359c19800e8SDoug Rabson 	    case 'D':
1360c19800e8SDoug Rabson 		ent->entry.flags.invalid = TRUE;
1361c19800e8SDoug Rabson 		break;
1362c19800e8SDoug Rabson 	    case 'H':
1363c19800e8SDoug Rabson 		break;
1364c19800e8SDoug Rabson 	    case 'T':
1365c19800e8SDoug Rabson 		/* temp duplicate */
1366c19800e8SDoug Rabson 		ent->entry.flags.invalid = TRUE;
1367c19800e8SDoug Rabson 		break;
1368c19800e8SDoug Rabson 	    case 'U':
1369c19800e8SDoug Rabson 		ent->entry.flags.client = TRUE;
1370c19800e8SDoug Rabson 		break;
1371c19800e8SDoug Rabson 	    case 'M':
1372c19800e8SDoug Rabson 		break;
1373c19800e8SDoug Rabson 	    case 'W':
1374c19800e8SDoug Rabson 	    case 'S':
1375c19800e8SDoug Rabson 		ent->entry.flags.server = TRUE;
1376c19800e8SDoug Rabson 		ent->entry.flags.client = TRUE;
1377c19800e8SDoug Rabson 		break;
1378c19800e8SDoug Rabson 	    case 'L':
1379c19800e8SDoug Rabson 		ent->entry.flags.invalid = TRUE;
1380c19800e8SDoug Rabson 		break;
1381c19800e8SDoug Rabson 	    case 'X':
1382c19800e8SDoug Rabson 		if (ent->entry.pw_end) {
1383c19800e8SDoug Rabson 		    free(ent->entry.pw_end);
1384c19800e8SDoug Rabson 		    ent->entry.pw_end = NULL;
13855e9cd1aeSAssar Westerlund 		}
1386c19800e8SDoug Rabson 		break;
1387c19800e8SDoug Rabson 	    case 'I':
1388c19800e8SDoug Rabson 		ent->entry.flags.server = TRUE;
1389c19800e8SDoug Rabson 		ent->entry.flags.client = TRUE;
1390c19800e8SDoug Rabson 		break;
13915e9cd1aeSAssar Westerlund 	    }
1392c19800e8SDoug Rabson 	}
1393c19800e8SDoug Rabson     out2:
1394c19800e8SDoug Rabson 	free(samba_acct_flags);
13955e9cd1aeSAssar Westerlund     }
13965e9cd1aeSAssar Westerlund 
13975e9cd1aeSAssar Westerlund     ret = 0;
13985e9cd1aeSAssar Westerlund 
13995e9cd1aeSAssar Westerlund out:
1400c19800e8SDoug Rabson     if (unparsed_name)
14015e9cd1aeSAssar Westerlund 	free(unparsed_name);
14025e9cd1aeSAssar Westerlund 
1403c19800e8SDoug Rabson     if (ret)
14045e9cd1aeSAssar Westerlund 	hdb_free_entry(context, ent);
14055e9cd1aeSAssar Westerlund 
14065e9cd1aeSAssar Westerlund     return ret;
14075e9cd1aeSAssar Westerlund }
14085e9cd1aeSAssar Westerlund 
1409c19800e8SDoug Rabson static krb5_error_code
1410c19800e8SDoug Rabson LDAP_close(krb5_context context, HDB * db)
14115e9cd1aeSAssar Westerlund {
1412c19800e8SDoug Rabson     if (HDB2LDAP(db)) {
1413c19800e8SDoug Rabson 	ldap_unbind_ext(HDB2LDAP(db), NULL, NULL);
1414c19800e8SDoug Rabson 	((struct hdbldapdb *)db->hdb_db)->h_lp = NULL;
1415c19800e8SDoug Rabson     }
14164137ff4cSJacques Vidrine 
14175e9cd1aeSAssar Westerlund     return 0;
14185e9cd1aeSAssar Westerlund }
14195e9cd1aeSAssar Westerlund 
14205e9cd1aeSAssar Westerlund static krb5_error_code
14215e9cd1aeSAssar Westerlund LDAP_lock(krb5_context context, HDB * db, int operation)
14225e9cd1aeSAssar Westerlund {
14235e9cd1aeSAssar Westerlund     return 0;
14245e9cd1aeSAssar Westerlund }
14255e9cd1aeSAssar Westerlund 
1426c19800e8SDoug Rabson static krb5_error_code
1427c19800e8SDoug Rabson LDAP_unlock(krb5_context context, HDB * db)
14285e9cd1aeSAssar Westerlund {
14295e9cd1aeSAssar Westerlund     return 0;
14305e9cd1aeSAssar Westerlund }
14315e9cd1aeSAssar Westerlund 
14325e9cd1aeSAssar Westerlund static krb5_error_code
1433c19800e8SDoug Rabson LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry)
14345e9cd1aeSAssar Westerlund {
14355e9cd1aeSAssar Westerlund     int msgid, rc, parserc;
14365e9cd1aeSAssar Westerlund     krb5_error_code ret;
14375e9cd1aeSAssar Westerlund     LDAPMessage *e;
14385e9cd1aeSAssar Westerlund 
1439c19800e8SDoug Rabson     msgid = HDB2MSGID(db);
1440c19800e8SDoug Rabson     if (msgid < 0)
14415e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
14425e9cd1aeSAssar Westerlund 
14435e9cd1aeSAssar Westerlund     do {
1444c19800e8SDoug Rabson 	rc = ldap_result(HDB2LDAP(db), msgid, LDAP_MSG_ONE, NULL, &e);
14455e9cd1aeSAssar Westerlund 	switch (rc) {
1446c19800e8SDoug Rabson 	case LDAP_RES_SEARCH_REFERENCE:
1447c19800e8SDoug Rabson 	    ldap_msgfree(e);
1448c19800e8SDoug Rabson 	    ret = 0;
1449c19800e8SDoug Rabson 	    break;
14505e9cd1aeSAssar Westerlund 	case LDAP_RES_SEARCH_ENTRY:
14515e9cd1aeSAssar Westerlund 	    /* We have an entry. Parse it. */
1452*ae771770SStanislav Sedov 	    ret = LDAP_message2entry(context, db, e, flags, entry);
14535e9cd1aeSAssar Westerlund 	    ldap_msgfree(e);
14545e9cd1aeSAssar Westerlund 	    break;
14555e9cd1aeSAssar Westerlund 	case LDAP_RES_SEARCH_RESULT:
14565e9cd1aeSAssar Westerlund 	    /* We're probably at the end of the results. If not, abandon. */
14575e9cd1aeSAssar Westerlund 	    parserc =
1458c19800e8SDoug Rabson 		ldap_parse_result(HDB2LDAP(db), e, NULL, NULL, NULL,
14595e9cd1aeSAssar Westerlund 				  NULL, NULL, 1);
1460*ae771770SStanislav Sedov 	    ret = HDB_ERR_NOENTRY;
14615e9cd1aeSAssar Westerlund 	    if (parserc != LDAP_SUCCESS
14625e9cd1aeSAssar Westerlund 		&& parserc != LDAP_MORE_RESULTS_TO_RETURN) {
1463*ae771770SStanislav Sedov 	        krb5_set_error_message(context, ret, "ldap_parse_result: %s",
1464c19800e8SDoug Rabson 				       ldap_err2string(parserc));
1465*ae771770SStanislav Sedov 		ldap_abandon_ext(HDB2LDAP(db), msgid, NULL, NULL);
14665e9cd1aeSAssar Westerlund 	    }
1467c19800e8SDoug Rabson 	    HDBSETMSGID(db, -1);
14685e9cd1aeSAssar Westerlund 	    break;
1469c19800e8SDoug Rabson 	case LDAP_SERVER_DOWN:
1470c19800e8SDoug Rabson 	    ldap_msgfree(e);
1471c19800e8SDoug Rabson 	    LDAP_close(context, db);
1472c19800e8SDoug Rabson 	    HDBSETMSGID(db, -1);
1473c19800e8SDoug Rabson 	    ret = ENETDOWN;
1474c19800e8SDoug Rabson 	    break;
14755e9cd1aeSAssar Westerlund 	default:
14765e9cd1aeSAssar Westerlund 	    /* Some unspecified error (timeout?). Abandon. */
14775e9cd1aeSAssar Westerlund 	    ldap_msgfree(e);
1478*ae771770SStanislav Sedov 	    ldap_abandon_ext(HDB2LDAP(db), msgid, NULL, NULL);
14795e9cd1aeSAssar Westerlund 	    ret = HDB_ERR_NOENTRY;
1480c19800e8SDoug Rabson 	    HDBSETMSGID(db, -1);
14815e9cd1aeSAssar Westerlund 	    break;
14825e9cd1aeSAssar Westerlund 	}
14835e9cd1aeSAssar Westerlund     } while (rc == LDAP_RES_SEARCH_REFERENCE);
14845e9cd1aeSAssar Westerlund 
14855e9cd1aeSAssar Westerlund     if (ret == 0) {
1486c19800e8SDoug Rabson 	if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
1487c19800e8SDoug Rabson 	    ret = hdb_unseal_keys(context, db, &entry->entry);
14885e9cd1aeSAssar Westerlund 	    if (ret)
14895e9cd1aeSAssar Westerlund 		hdb_free_entry(context, entry);
14905e9cd1aeSAssar Westerlund 	}
14915e9cd1aeSAssar Westerlund     }
14925e9cd1aeSAssar Westerlund 
14935e9cd1aeSAssar Westerlund     return ret;
14945e9cd1aeSAssar Westerlund }
14955e9cd1aeSAssar Westerlund 
14965e9cd1aeSAssar Westerlund static krb5_error_code
14975e9cd1aeSAssar Westerlund LDAP_firstkey(krb5_context context, HDB *db, unsigned flags,
1498c19800e8SDoug Rabson 	      hdb_entry_ex *entry)
14995e9cd1aeSAssar Westerlund {
1500c19800e8SDoug Rabson     krb5_error_code ret;
1501c19800e8SDoug Rabson     int msgid;
15025e9cd1aeSAssar Westerlund 
1503c19800e8SDoug Rabson     ret = LDAP__connect(context, db);
1504c19800e8SDoug Rabson     if (ret)
1505c19800e8SDoug Rabson 	return ret;
15065e9cd1aeSAssar Westerlund 
1507c19800e8SDoug Rabson     ret = LDAP_no_size_limit(context, HDB2LDAP(db));
1508c19800e8SDoug Rabson     if (ret)
1509c19800e8SDoug Rabson 	return ret;
15105e9cd1aeSAssar Westerlund 
1511*ae771770SStanislav Sedov     ret = ldap_search_ext(HDB2LDAP(db), HDB2BASE(db),
1512c19800e8SDoug Rabson 			LDAP_SCOPE_SUBTREE,
1513c19800e8SDoug Rabson 			"(|(objectClass=krb5Principal)(objectClass=sambaSamAccount))",
1514*ae771770SStanislav Sedov 			krb5kdcentry_attrs, 0,
1515*ae771770SStanislav Sedov 			NULL, NULL, NULL, 0, &msgid);
1516c19800e8SDoug Rabson     if (msgid < 0)
15175e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
15185e9cd1aeSAssar Westerlund 
1519c19800e8SDoug Rabson     HDBSETMSGID(db, msgid);
15205e9cd1aeSAssar Westerlund 
15215e9cd1aeSAssar Westerlund     return LDAP_seq(context, db, flags, entry);
15225e9cd1aeSAssar Westerlund }
15235e9cd1aeSAssar Westerlund 
15245e9cd1aeSAssar Westerlund static krb5_error_code
15255e9cd1aeSAssar Westerlund LDAP_nextkey(krb5_context context, HDB * db, unsigned flags,
1526c19800e8SDoug Rabson 	     hdb_entry_ex * entry)
15275e9cd1aeSAssar Westerlund {
15285e9cd1aeSAssar Westerlund     return LDAP_seq(context, db, flags, entry);
15295e9cd1aeSAssar Westerlund }
15305e9cd1aeSAssar Westerlund 
15315e9cd1aeSAssar Westerlund static krb5_error_code
1532c19800e8SDoug Rabson LDAP__connect(krb5_context context, HDB * db)
15335e9cd1aeSAssar Westerlund {
15344137ff4cSJacques Vidrine     int rc, version = LDAP_VERSION3;
15351c43270aSJacques Vidrine     /*
15361c43270aSJacques Vidrine      * Empty credentials to do a SASL bind with LDAP. Note that empty
15371c43270aSJacques Vidrine      * different from NULL credentials. If you provide NULL
15381c43270aSJacques Vidrine      * credentials instead of empty credentials you will get a SASL
15391c43270aSJacques Vidrine      * bind in progress message.
15401c43270aSJacques Vidrine      */
15411c43270aSJacques Vidrine     struct berval bv = { 0, "" };
15425e9cd1aeSAssar Westerlund 
1543c19800e8SDoug Rabson     if (HDB2LDAP(db)) {
15445e9cd1aeSAssar Westerlund 	/* connection has been opened. ping server. */
15455e9cd1aeSAssar Westerlund 	struct sockaddr_un addr;
1546c19800e8SDoug Rabson 	socklen_t len = sizeof(addr);
15475e9cd1aeSAssar Westerlund 	int sd;
15485e9cd1aeSAssar Westerlund 
1549c19800e8SDoug Rabson 	if (ldap_get_option(HDB2LDAP(db), LDAP_OPT_DESC, &sd) == 0 &&
15505e9cd1aeSAssar Westerlund 	    getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
15515e9cd1aeSAssar Westerlund 	    /* the other end has died. reopen. */
15525e9cd1aeSAssar Westerlund 	    LDAP_close(context, db);
15535e9cd1aeSAssar Westerlund 	}
15545e9cd1aeSAssar Westerlund     }
15555e9cd1aeSAssar Westerlund 
1556c19800e8SDoug Rabson     if (HDB2LDAP(db) != NULL) /* server is UP */
15575e9cd1aeSAssar Westerlund 	return 0;
15585e9cd1aeSAssar Westerlund 
1559c19800e8SDoug Rabson     rc = ldap_initialize(&((struct hdbldapdb *)db->hdb_db)->h_lp, HDB2URL(db));
15605e9cd1aeSAssar Westerlund     if (rc != LDAP_SUCCESS) {
1561*ae771770SStanislav Sedov 	krb5_set_error_message(context, HDB_ERR_NOENTRY, "ldap_initialize: %s",
1562c19800e8SDoug Rabson 			       ldap_err2string(rc));
15635e9cd1aeSAssar Westerlund 	return HDB_ERR_NOENTRY;
15645e9cd1aeSAssar Westerlund     }
15655e9cd1aeSAssar Westerlund 
1566c19800e8SDoug Rabson     rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_PROTOCOL_VERSION,
1567c19800e8SDoug Rabson 			 (const void *)&version);
15685e9cd1aeSAssar Westerlund     if (rc != LDAP_SUCCESS) {
1569*ae771770SStanislav Sedov 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
1570*ae771770SStanislav Sedov 			       "ldap_set_option: %s", ldap_err2string(rc));
1571c19800e8SDoug Rabson 	LDAP_close(context, db);
15724137ff4cSJacques Vidrine 	return HDB_ERR_BADVERSION;
15735e9cd1aeSAssar Westerlund     }
15745e9cd1aeSAssar Westerlund 
1575c19800e8SDoug Rabson     rc = ldap_sasl_bind_s(HDB2LDAP(db), NULL, "EXTERNAL", &bv,
1576c19800e8SDoug Rabson 			  NULL, NULL, NULL);
15771c43270aSJacques Vidrine     if (rc != LDAP_SUCCESS) {
1578*ae771770SStanislav Sedov 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
1579*ae771770SStanislav Sedov 			      "ldap_sasl_bind_s: %s", ldap_err2string(rc));
1580c19800e8SDoug Rabson 	LDAP_close(context, db);
15811c43270aSJacques Vidrine 	return HDB_ERR_BADVERSION;
15821c43270aSJacques Vidrine     }
15831c43270aSJacques Vidrine 
15844137ff4cSJacques Vidrine     return 0;
15855e9cd1aeSAssar Westerlund }
15865e9cd1aeSAssar Westerlund 
15875e9cd1aeSAssar Westerlund static krb5_error_code
15885e9cd1aeSAssar Westerlund LDAP_open(krb5_context context, HDB * db, int flags, mode_t mode)
15895e9cd1aeSAssar Westerlund {
15905e9cd1aeSAssar Westerlund     /* Not the right place for this. */
15915e9cd1aeSAssar Westerlund #ifdef HAVE_SIGACTION
15925e9cd1aeSAssar Westerlund     struct sigaction sa;
15935e9cd1aeSAssar Westerlund 
15945e9cd1aeSAssar Westerlund     sa.sa_flags = 0;
15955e9cd1aeSAssar Westerlund     sa.sa_handler = SIG_IGN;
15965e9cd1aeSAssar Westerlund     sigemptyset(&sa.sa_mask);
15975e9cd1aeSAssar Westerlund 
15985e9cd1aeSAssar Westerlund     sigaction(SIGPIPE, &sa, NULL);
15995e9cd1aeSAssar Westerlund #else
16005e9cd1aeSAssar Westerlund     signal(SIGPIPE, SIG_IGN);
16014137ff4cSJacques Vidrine #endif /* HAVE_SIGACTION */
16025e9cd1aeSAssar Westerlund 
16034137ff4cSJacques Vidrine     return LDAP__connect(context, db);
16045e9cd1aeSAssar Westerlund }
16055e9cd1aeSAssar Westerlund 
16065e9cd1aeSAssar Westerlund static krb5_error_code
1607*ae771770SStanislav Sedov LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
1608*ae771770SStanislav Sedov 		unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry)
16095e9cd1aeSAssar Westerlund {
16105e9cd1aeSAssar Westerlund     LDAPMessage *msg, *e;
16115e9cd1aeSAssar Westerlund     krb5_error_code ret;
16125e9cd1aeSAssar Westerlund 
1613c19800e8SDoug Rabson     ret = LDAP_principal2message(context, db, principal, &msg);
1614c19800e8SDoug Rabson     if (ret)
16155e9cd1aeSAssar Westerlund 	return ret;
16165e9cd1aeSAssar Westerlund 
1617c19800e8SDoug Rabson     e = ldap_first_entry(HDB2LDAP(db), msg);
16185e9cd1aeSAssar Westerlund     if (e == NULL) {
16195e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
16205e9cd1aeSAssar Westerlund 	goto out;
16215e9cd1aeSAssar Westerlund     }
16225e9cd1aeSAssar Westerlund 
1623*ae771770SStanislav Sedov     ret = LDAP_message2entry(context, db, e, flags, entry);
16245e9cd1aeSAssar Westerlund     if (ret == 0) {
1625c19800e8SDoug Rabson 	if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
1626c19800e8SDoug Rabson 	    ret = hdb_unseal_keys(context, db, &entry->entry);
16275e9cd1aeSAssar Westerlund 	    if (ret)
16285e9cd1aeSAssar Westerlund 		hdb_free_entry(context, entry);
16295e9cd1aeSAssar Westerlund 	}
16305e9cd1aeSAssar Westerlund     }
16315e9cd1aeSAssar Westerlund 
16325e9cd1aeSAssar Westerlund   out:
16335e9cd1aeSAssar Westerlund     ldap_msgfree(msg);
16345e9cd1aeSAssar Westerlund 
16355e9cd1aeSAssar Westerlund     return ret;
16365e9cd1aeSAssar Westerlund }
16375e9cd1aeSAssar Westerlund 
16385e9cd1aeSAssar Westerlund static krb5_error_code
1639*ae771770SStanislav Sedov LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal,
1640*ae771770SStanislav Sedov 	   unsigned flags, hdb_entry_ex * entry)
1641*ae771770SStanislav Sedov {
1642*ae771770SStanislav Sedov     return LDAP_fetch_kvno(context, db, principal,
1643*ae771770SStanislav Sedov 			   flags & (~HDB_F_KVNO_SPECIFIED), 0, entry);
1644*ae771770SStanislav Sedov }
1645*ae771770SStanislav Sedov 
1646*ae771770SStanislav Sedov static krb5_error_code
16475e9cd1aeSAssar Westerlund LDAP_store(krb5_context context, HDB * db, unsigned flags,
1648c19800e8SDoug Rabson 	   hdb_entry_ex * entry)
16495e9cd1aeSAssar Westerlund {
16505e9cd1aeSAssar Westerlund     LDAPMod **mods = NULL;
16515e9cd1aeSAssar Westerlund     krb5_error_code ret;
16524137ff4cSJacques Vidrine     const char *errfn;
16534137ff4cSJacques Vidrine     int rc;
16545e9cd1aeSAssar Westerlund     LDAPMessage *msg = NULL, *e = NULL;
16555e9cd1aeSAssar Westerlund     char *dn = NULL, *name = NULL;
16565e9cd1aeSAssar Westerlund 
1657c19800e8SDoug Rabson     ret = LDAP_principal2message(context, db, entry->entry.principal, &msg);
1658c19800e8SDoug Rabson     if (ret == 0)
1659c19800e8SDoug Rabson 	e = ldap_first_entry(HDB2LDAP(db), msg);
1660c19800e8SDoug Rabson 
1661c19800e8SDoug Rabson     ret = krb5_unparse_name(context, entry->entry.principal, &name);
1662c19800e8SDoug Rabson     if (ret) {
1663c19800e8SDoug Rabson 	free(name);
1664c19800e8SDoug Rabson 	return ret;
16655e9cd1aeSAssar Westerlund     }
16665e9cd1aeSAssar Westerlund 
1667c19800e8SDoug Rabson     ret = hdb_seal_keys(context, db, &entry->entry);
1668c19800e8SDoug Rabson     if (ret)
16695e9cd1aeSAssar Westerlund 	goto out;
16705e9cd1aeSAssar Westerlund 
16715e9cd1aeSAssar Westerlund     /* turn new entry into LDAPMod array */
16725e9cd1aeSAssar Westerlund     ret = LDAP_entry2mods(context, db, entry, e, &mods);
1673c19800e8SDoug Rabson     if (ret)
16745e9cd1aeSAssar Westerlund 	goto out;
16755e9cd1aeSAssar Westerlund 
16765e9cd1aeSAssar Westerlund     if (e == NULL) {
1677c19800e8SDoug Rabson 	ret = asprintf(&dn, "krb5PrincipalName=%s,%s", name, HDB2CREATE(db));
16785e9cd1aeSAssar Westerlund 	if (ret < 0) {
16795e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
1680*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ret, "asprintf: out of memory");
16815e9cd1aeSAssar Westerlund 	    goto out;
16825e9cd1aeSAssar Westerlund 	}
16835e9cd1aeSAssar Westerlund     } else if (flags & HDB_F_REPLACE) {
16845e9cd1aeSAssar Westerlund 	/* Entry exists, and we're allowed to replace it. */
1685c19800e8SDoug Rabson 	dn = ldap_get_dn(HDB2LDAP(db), e);
16865e9cd1aeSAssar Westerlund     } else {
16875e9cd1aeSAssar Westerlund 	/* Entry exists, but we're not allowed to replace it. Bail. */
16885e9cd1aeSAssar Westerlund 	ret = HDB_ERR_EXISTS;
16895e9cd1aeSAssar Westerlund 	goto out;
16905e9cd1aeSAssar Westerlund     }
16915e9cd1aeSAssar Westerlund 
16925e9cd1aeSAssar Westerlund     /* write entry into directory */
16935e9cd1aeSAssar Westerlund     if (e == NULL) {
16945e9cd1aeSAssar Westerlund 	/* didn't exist before */
1695*ae771770SStanislav Sedov 	rc = ldap_add_ext_s(HDB2LDAP(db), dn, mods, NULL, NULL );
1696*ae771770SStanislav Sedov 	errfn = "ldap_add_ext_s";
16975e9cd1aeSAssar Westerlund     } else {
16985e9cd1aeSAssar Westerlund 	/* already existed, send deltas only */
1699*ae771770SStanislav Sedov 	rc = ldap_modify_ext_s(HDB2LDAP(db), dn, mods, NULL, NULL );
1700*ae771770SStanislav Sedov 	errfn = "ldap_modify_ext_s";
17015e9cd1aeSAssar Westerlund     }
17025e9cd1aeSAssar Westerlund 
1703c19800e8SDoug Rabson     if (check_ldap(context, db, rc)) {
1704c19800e8SDoug Rabson 	char *ld_error = NULL;
1705c19800e8SDoug Rabson 	ldap_get_option(HDB2LDAP(db), LDAP_OPT_ERROR_STRING,
1706c19800e8SDoug Rabson 			&ld_error);
17075e9cd1aeSAssar Westerlund 	ret = HDB_ERR_CANT_LOCK_DB;
1708*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "%s: %s (DN=%s) %s: %s",
1709*ae771770SStanislav Sedov 			      errfn, name, dn, ldap_err2string(rc), ld_error);
1710c19800e8SDoug Rabson     } else
1711c19800e8SDoug Rabson 	ret = 0;
17125e9cd1aeSAssar Westerlund 
17135e9cd1aeSAssar Westerlund   out:
17145e9cd1aeSAssar Westerlund     /* free stuff */
1715c19800e8SDoug Rabson     if (dn)
17165e9cd1aeSAssar Westerlund 	free(dn);
1717c19800e8SDoug Rabson     if (msg)
17185e9cd1aeSAssar Westerlund 	ldap_msgfree(msg);
1719c19800e8SDoug Rabson     if (mods)
17205e9cd1aeSAssar Westerlund 	ldap_mods_free(mods, 1);
1721c19800e8SDoug Rabson     if (name)
17225e9cd1aeSAssar Westerlund 	free(name);
17235e9cd1aeSAssar Westerlund 
17245e9cd1aeSAssar Westerlund     return ret;
17255e9cd1aeSAssar Westerlund }
17265e9cd1aeSAssar Westerlund 
17275e9cd1aeSAssar Westerlund static krb5_error_code
1728c19800e8SDoug Rabson LDAP_remove(krb5_context context, HDB *db, krb5_const_principal principal)
17295e9cd1aeSAssar Westerlund {
17305e9cd1aeSAssar Westerlund     krb5_error_code ret;
17315e9cd1aeSAssar Westerlund     LDAPMessage *msg, *e;
17325e9cd1aeSAssar Westerlund     char *dn = NULL;
17334137ff4cSJacques Vidrine     int rc, limit = LDAP_NO_LIMIT;
17345e9cd1aeSAssar Westerlund 
1735c19800e8SDoug Rabson     ret = LDAP_principal2message(context, db, principal, &msg);
1736c19800e8SDoug Rabson     if (ret)
17375e9cd1aeSAssar Westerlund 	goto out;
17385e9cd1aeSAssar Westerlund 
1739c19800e8SDoug Rabson     e = ldap_first_entry(HDB2LDAP(db), msg);
17405e9cd1aeSAssar Westerlund     if (e == NULL) {
17415e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
17425e9cd1aeSAssar Westerlund 	goto out;
17435e9cd1aeSAssar Westerlund     }
17445e9cd1aeSAssar Westerlund 
1745c19800e8SDoug Rabson     dn = ldap_get_dn(HDB2LDAP(db), e);
17465e9cd1aeSAssar Westerlund     if (dn == NULL) {
17475e9cd1aeSAssar Westerlund 	ret = HDB_ERR_NOENTRY;
17485e9cd1aeSAssar Westerlund 	goto out;
17495e9cd1aeSAssar Westerlund     }
17505e9cd1aeSAssar Westerlund 
1751c19800e8SDoug Rabson     rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_SIZELIMIT, (const void *)&limit);
17524137ff4cSJacques Vidrine     if (rc != LDAP_SUCCESS) {
17534137ff4cSJacques Vidrine 	ret = HDB_ERR_BADVERSION;
1754*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "ldap_set_option: %s",
1755*ae771770SStanislav Sedov 			      ldap_err2string(rc));
17564137ff4cSJacques Vidrine 	goto out;
17574137ff4cSJacques Vidrine     }
17585e9cd1aeSAssar Westerlund 
1759*ae771770SStanislav Sedov     rc = ldap_delete_ext_s(HDB2LDAP(db), dn, NULL, NULL );
1760c19800e8SDoug Rabson     if (check_ldap(context, db, rc)) {
17615e9cd1aeSAssar Westerlund 	ret = HDB_ERR_CANT_LOCK_DB;
1762*ae771770SStanislav Sedov 	krb5_set_error_message(context, ret, "ldap_delete_ext_s: %s",
1763*ae771770SStanislav Sedov 			       ldap_err2string(rc));
1764c19800e8SDoug Rabson     } else
1765c19800e8SDoug Rabson 	ret = 0;
17665e9cd1aeSAssar Westerlund 
17675e9cd1aeSAssar Westerlund   out:
1768c19800e8SDoug Rabson     if (dn != NULL)
17695e9cd1aeSAssar Westerlund 	free(dn);
1770c19800e8SDoug Rabson     if (msg != NULL)
17715e9cd1aeSAssar Westerlund 	ldap_msgfree(msg);
17725e9cd1aeSAssar Westerlund 
17735e9cd1aeSAssar Westerlund     return ret;
17745e9cd1aeSAssar Westerlund }
17755e9cd1aeSAssar Westerlund 
17765e9cd1aeSAssar Westerlund static krb5_error_code
1777c19800e8SDoug Rabson LDAP_destroy(krb5_context context, HDB * db)
17785e9cd1aeSAssar Westerlund {
17795e9cd1aeSAssar Westerlund     krb5_error_code ret;
17805e9cd1aeSAssar Westerlund 
1781c19800e8SDoug Rabson     LDAP_close(context, db);
1782c19800e8SDoug Rabson 
17835e9cd1aeSAssar Westerlund     ret = hdb_clear_master_key(context, db);
1784c19800e8SDoug Rabson     if (HDB2BASE(db))
1785c19800e8SDoug Rabson 	free(HDB2BASE(db));
1786c19800e8SDoug Rabson     if (HDB2CREATE(db))
1787c19800e8SDoug Rabson 	free(HDB2CREATE(db));
1788c19800e8SDoug Rabson     if (HDB2URL(db))
1789c19800e8SDoug Rabson 	free(HDB2URL(db));
1790c19800e8SDoug Rabson     if (db->hdb_name)
1791c19800e8SDoug Rabson 	free(db->hdb_name);
1792c19800e8SDoug Rabson     free(db->hdb_db);
17935e9cd1aeSAssar Westerlund     free(db);
17945e9cd1aeSAssar Westerlund 
17955e9cd1aeSAssar Westerlund     return ret;
17965e9cd1aeSAssar Westerlund }
17975e9cd1aeSAssar Westerlund 
1798*ae771770SStanislav Sedov static krb5_error_code
1799c19800e8SDoug Rabson hdb_ldap_common(krb5_context context,
1800c19800e8SDoug Rabson 		HDB ** db,
1801c19800e8SDoug Rabson 		const char *search_base,
1802c19800e8SDoug Rabson 		const char *url)
18035e9cd1aeSAssar Westerlund {
1804c19800e8SDoug Rabson     struct hdbldapdb *h;
1805c19800e8SDoug Rabson     const char *create_base = NULL;
1806c19800e8SDoug Rabson 
1807c19800e8SDoug Rabson     if (search_base == NULL && search_base[0] == '\0') {
1808*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "ldap search base not configured");
1809c19800e8SDoug Rabson 	return ENOMEM; /* XXX */
1810c19800e8SDoug Rabson     }
1811c19800e8SDoug Rabson 
1812c19800e8SDoug Rabson     if (structural_object == NULL) {
1813c19800e8SDoug Rabson 	const char *p;
1814c19800e8SDoug Rabson 
1815c19800e8SDoug Rabson 	p = krb5_config_get_string(context, NULL, "kdc",
1816c19800e8SDoug Rabson 				   "hdb-ldap-structural-object", NULL);
1817c19800e8SDoug Rabson 	if (p == NULL)
1818c19800e8SDoug Rabson 	    p = default_structural_object;
1819c19800e8SDoug Rabson 	structural_object = strdup(p);
1820c19800e8SDoug Rabson 	if (structural_object == NULL) {
1821*ae771770SStanislav Sedov 	    krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1822c19800e8SDoug Rabson 	    return ENOMEM;
1823c19800e8SDoug Rabson 	}
1824c19800e8SDoug Rabson     }
1825c19800e8SDoug Rabson 
1826c19800e8SDoug Rabson     samba_forwardable =
1827c19800e8SDoug Rabson 	krb5_config_get_bool_default(context, NULL, TRUE,
1828c19800e8SDoug Rabson 				     "kdc", "hdb-samba-forwardable", NULL);
1829c19800e8SDoug Rabson 
1830c19800e8SDoug Rabson     *db = calloc(1, sizeof(**db));
18314137ff4cSJacques Vidrine     if (*db == NULL) {
1832*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
18335e9cd1aeSAssar Westerlund 	return ENOMEM;
18344137ff4cSJacques Vidrine     }
1835c19800e8SDoug Rabson     memset(*db, 0, sizeof(**db));
18365e9cd1aeSAssar Westerlund 
1837c19800e8SDoug Rabson     h = calloc(1, sizeof(*h));
1838c19800e8SDoug Rabson     if (h == NULL) {
18394137ff4cSJacques Vidrine 	free(*db);
18404137ff4cSJacques Vidrine 	*db = NULL;
1841*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
18424137ff4cSJacques Vidrine 	return ENOMEM;
18434137ff4cSJacques Vidrine     }
1844c19800e8SDoug Rabson     (*db)->hdb_db = h;
1845c19800e8SDoug Rabson 
1846c19800e8SDoug Rabson     /* XXX */
1847c19800e8SDoug Rabson     if (asprintf(&(*db)->hdb_name, "ldap:%s", search_base) == -1) {
1848c19800e8SDoug Rabson 	LDAP_destroy(context, *db);
1849c19800e8SDoug Rabson 	*db = NULL;
1850*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "strdup: out of memory");
1851c19800e8SDoug Rabson 	return ENOMEM;
18524137ff4cSJacques Vidrine     }
18534137ff4cSJacques Vidrine 
1854c19800e8SDoug Rabson     h->h_url = strdup(url);
1855c19800e8SDoug Rabson     h->h_base = strdup(search_base);
1856c19800e8SDoug Rabson     if (h->h_url == NULL || h->h_base == NULL) {
1857c19800e8SDoug Rabson 	LDAP_destroy(context, *db);
1858c19800e8SDoug Rabson 	*db = NULL;
1859*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "strdup: out of memory");
1860c19800e8SDoug Rabson 	return ENOMEM;
1861c19800e8SDoug Rabson     }
1862c19800e8SDoug Rabson 
1863c19800e8SDoug Rabson     create_base = krb5_config_get_string(context, NULL, "kdc",
1864c19800e8SDoug Rabson 					 "hdb-ldap-create-base", NULL);
1865c19800e8SDoug Rabson     if (create_base == NULL)
1866c19800e8SDoug Rabson 	create_base = h->h_base;
1867c19800e8SDoug Rabson 
1868c19800e8SDoug Rabson     h->h_createbase = strdup(create_base);
1869c19800e8SDoug Rabson     if (h->h_createbase == NULL) {
1870c19800e8SDoug Rabson 	LDAP_destroy(context, *db);
1871c19800e8SDoug Rabson 	*db = NULL;
1872*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "strdup: out of memory");
1873c19800e8SDoug Rabson 	return ENOMEM;
1874c19800e8SDoug Rabson     }
1875c19800e8SDoug Rabson 
1876c19800e8SDoug Rabson     (*db)->hdb_master_key_set = 0;
1877c19800e8SDoug Rabson     (*db)->hdb_openp = 0;
1878*ae771770SStanislav Sedov     (*db)->hdb_capability_flags = 0;
1879c19800e8SDoug Rabson     (*db)->hdb_open = LDAP_open;
1880c19800e8SDoug Rabson     (*db)->hdb_close = LDAP_close;
1881*ae771770SStanislav Sedov     (*db)->hdb_fetch_kvno = LDAP_fetch_kvno;
1882c19800e8SDoug Rabson     (*db)->hdb_store = LDAP_store;
1883c19800e8SDoug Rabson     (*db)->hdb_remove = LDAP_remove;
1884c19800e8SDoug Rabson     (*db)->hdb_firstkey = LDAP_firstkey;
1885c19800e8SDoug Rabson     (*db)->hdb_nextkey = LDAP_nextkey;
1886c19800e8SDoug Rabson     (*db)->hdb_lock = LDAP_lock;
1887c19800e8SDoug Rabson     (*db)->hdb_unlock = LDAP_unlock;
1888c19800e8SDoug Rabson     (*db)->hdb_rename = NULL;
1889c19800e8SDoug Rabson     (*db)->hdb__get = NULL;
1890c19800e8SDoug Rabson     (*db)->hdb__put = NULL;
1891c19800e8SDoug Rabson     (*db)->hdb__del = NULL;
1892c19800e8SDoug Rabson     (*db)->hdb_destroy = LDAP_destroy;
18935e9cd1aeSAssar Westerlund 
18945e9cd1aeSAssar Westerlund     return 0;
18955e9cd1aeSAssar Westerlund }
18965e9cd1aeSAssar Westerlund 
1897c19800e8SDoug Rabson krb5_error_code
1898c19800e8SDoug Rabson hdb_ldap_create(krb5_context context, HDB ** db, const char *arg)
1899c19800e8SDoug Rabson {
1900c19800e8SDoug Rabson     return hdb_ldap_common(context, db, arg, "ldapi:///");
1901c19800e8SDoug Rabson }
1902c19800e8SDoug Rabson 
1903c19800e8SDoug Rabson krb5_error_code
1904c19800e8SDoug Rabson hdb_ldapi_create(krb5_context context, HDB ** db, const char *arg)
1905c19800e8SDoug Rabson {
1906c19800e8SDoug Rabson     krb5_error_code ret;
1907c19800e8SDoug Rabson     char *search_base, *p;
1908c19800e8SDoug Rabson 
1909c19800e8SDoug Rabson     asprintf(&p, "ldapi:%s", arg);
1910c19800e8SDoug Rabson     if (p == NULL) {
1911c19800e8SDoug Rabson 	*db = NULL;
1912*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, "out of memory");
1913c19800e8SDoug Rabson 	return ENOMEM;
1914c19800e8SDoug Rabson     }
1915c19800e8SDoug Rabson     search_base = strchr(p + strlen("ldapi://"), ':');
1916c19800e8SDoug Rabson     if (search_base == NULL) {
1917c19800e8SDoug Rabson 	*db = NULL;
1918*ae771770SStanislav Sedov 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
1919*ae771770SStanislav Sedov 			       "search base missing");
1920c19800e8SDoug Rabson 	return HDB_ERR_BADVERSION;
1921c19800e8SDoug Rabson     }
1922c19800e8SDoug Rabson     *search_base = '\0';
1923c19800e8SDoug Rabson     search_base++;
1924c19800e8SDoug Rabson 
1925c19800e8SDoug Rabson     ret = hdb_ldap_common(context, db, search_base, p);
1926c19800e8SDoug Rabson     free(p);
1927c19800e8SDoug Rabson     return ret;
1928c19800e8SDoug Rabson }
1929c19800e8SDoug Rabson 
1930c19800e8SDoug Rabson #ifdef OPENLDAP_MODULE
1931c19800e8SDoug Rabson 
1932c19800e8SDoug Rabson struct hdb_so_method hdb_ldap_interface = {
1933c19800e8SDoug Rabson     HDB_INTERFACE_VERSION,
1934c19800e8SDoug Rabson     "ldap",
1935c19800e8SDoug Rabson     hdb_ldap_create
1936c19800e8SDoug Rabson };
1937c19800e8SDoug Rabson 
1938c19800e8SDoug Rabson struct hdb_so_method hdb_ldapi_interface = {
1939c19800e8SDoug Rabson     HDB_INTERFACE_VERSION,
1940c19800e8SDoug Rabson     "ldapi",
1941c19800e8SDoug Rabson     hdb_ldapi_create
1942c19800e8SDoug Rabson };
1943c19800e8SDoug Rabson 
1944c19800e8SDoug Rabson #endif
1945c19800e8SDoug Rabson 
19465e9cd1aeSAssar Westerlund #endif				/* OPENLDAP */
1947