xref: /netbsd-src/crypto/external/bsd/heimdal/dist/lib/hdb/hdb-ldap.c (revision 241bea01a19bbb306af27777a870b86d41cb3fda)
1*241bea01Schristos /*	$NetBSD: hdb-ldap.c,v 1.3 2019/12/15 22:50:49 christos Exp $	*/
2ca1c9b0cSelric 
3ca1c9b0cSelric /*
4ca1c9b0cSelric  * Copyright (c) 1999-2001, 2003, PADL Software Pty Ltd.
5ca1c9b0cSelric  * Copyright (c) 2004, Andrew Bartlett.
6ca1c9b0cSelric  * Copyright (c) 2003 - 2008, Kungliga Tekniska Högskolan.
7b9d004c6Schristos  * Copyright (c) 2015, Timothy Pearson.
8ca1c9b0cSelric  * All rights reserved.
9ca1c9b0cSelric  *
10ca1c9b0cSelric  * Redistribution and use in source and binary forms, with or without
11ca1c9b0cSelric  * modification, are permitted provided that the following conditions
12ca1c9b0cSelric  * are met:
13ca1c9b0cSelric  *
14ca1c9b0cSelric  * 1. Redistributions of source code must retain the above copyright
15ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer.
16ca1c9b0cSelric  *
17ca1c9b0cSelric  * 2. Redistributions in binary form must reproduce the above copyright
18ca1c9b0cSelric  *    notice, this list of conditions and the following disclaimer in the
19ca1c9b0cSelric  *    documentation and/or other materials provided with the distribution.
20ca1c9b0cSelric  *
21ca1c9b0cSelric  * 3. Neither the name of PADL Software  nor the names of its contributors
22ca1c9b0cSelric  *    may be used to endorse or promote products derived from this software
23ca1c9b0cSelric  *    without specific prior written permission.
24ca1c9b0cSelric  *
25ca1c9b0cSelric  * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
26ca1c9b0cSelric  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27ca1c9b0cSelric  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28ca1c9b0cSelric  * ARE DISCLAIMED.  IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
29ca1c9b0cSelric  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30ca1c9b0cSelric  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31ca1c9b0cSelric  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32ca1c9b0cSelric  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33ca1c9b0cSelric  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34ca1c9b0cSelric  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35ca1c9b0cSelric  * SUCH DAMAGE.
36ca1c9b0cSelric  */
37ca1c9b0cSelric 
38ca1c9b0cSelric #include "hdb_locl.h"
39ca1c9b0cSelric 
40ca1c9b0cSelric #ifdef OPENLDAP
41ca1c9b0cSelric 
42ca1c9b0cSelric #include <lber.h>
43ca1c9b0cSelric #include <ldap.h>
44ca1c9b0cSelric #include <sys/un.h>
45ca1c9b0cSelric #include <krb5/hex.h>
46ca1c9b0cSelric 
47ca1c9b0cSelric static krb5_error_code LDAP__connect(krb5_context context, HDB *);
48ca1c9b0cSelric static krb5_error_code LDAP_close(krb5_context context, HDB *);
49ca1c9b0cSelric 
50ca1c9b0cSelric static krb5_error_code
51ca1c9b0cSelric LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
52ca1c9b0cSelric 		   int flags, hdb_entry_ex * ent);
53ca1c9b0cSelric 
54ca1c9b0cSelric static const char *default_structural_object = "account";
55ca1c9b0cSelric static char *structural_object;
56b9d004c6Schristos static const char *default_ldap_url = "ldapi:///";
57ca1c9b0cSelric static krb5_boolean samba_forwardable;
58ca1c9b0cSelric 
59ca1c9b0cSelric struct hdbldapdb {
60ca1c9b0cSelric     LDAP *h_lp;
61ca1c9b0cSelric     int   h_msgid;
62ca1c9b0cSelric     char *h_base;
63ca1c9b0cSelric     char *h_url;
64b9d004c6Schristos     char *h_bind_dn;
65b9d004c6Schristos     char *h_bind_password;
66b9d004c6Schristos     krb5_boolean h_start_tls;
67ca1c9b0cSelric     char *h_createbase;
68ca1c9b0cSelric };
69ca1c9b0cSelric 
70ca1c9b0cSelric #define HDB2LDAP(db) (((struct hdbldapdb *)(db)->hdb_db)->h_lp)
71ca1c9b0cSelric #define HDB2MSGID(db) (((struct hdbldapdb *)(db)->hdb_db)->h_msgid)
72ca1c9b0cSelric #define HDBSETMSGID(db,msgid) \
73ca1c9b0cSelric 	do { ((struct hdbldapdb *)(db)->hdb_db)->h_msgid = msgid; } while(0)
74ca1c9b0cSelric #define HDB2BASE(dn) (((struct hdbldapdb *)(db)->hdb_db)->h_base)
75ca1c9b0cSelric #define HDB2URL(dn) (((struct hdbldapdb *)(db)->hdb_db)->h_url)
76b9d004c6Schristos #define HDB2BINDDN(db) (((struct hdbldapdb *)(db)->hdb_db)->h_bind_dn)
77b9d004c6Schristos #define HDB2BINDPW(db) (((struct hdbldapdb *)(db)->hdb_db)->h_bind_password)
78ca1c9b0cSelric #define HDB2CREATE(db) (((struct hdbldapdb *)(db)->hdb_db)->h_createbase)
79ca1c9b0cSelric 
80ca1c9b0cSelric /*
81ca1c9b0cSelric  *
82ca1c9b0cSelric  */
83ca1c9b0cSelric 
84ca1c9b0cSelric static char * krb5kdcentry_attrs[] = {
85ca1c9b0cSelric     "cn",
86ca1c9b0cSelric     "createTimestamp",
87ca1c9b0cSelric     "creatorsName",
88ca1c9b0cSelric     "krb5EncryptionType",
89ca1c9b0cSelric     "krb5KDCFlags",
90ca1c9b0cSelric     "krb5Key",
91ca1c9b0cSelric     "krb5KeyVersionNumber",
92ca1c9b0cSelric     "krb5MaxLife",
93ca1c9b0cSelric     "krb5MaxRenew",
94ca1c9b0cSelric     "krb5PasswordEnd",
95ca1c9b0cSelric     "krb5PrincipalName",
96ca1c9b0cSelric     "krb5PrincipalRealm",
97b9d004c6Schristos     "krb5ExtendedAttributes",
98ca1c9b0cSelric     "krb5ValidEnd",
99ca1c9b0cSelric     "krb5ValidStart",
100ca1c9b0cSelric     "modifiersName",
101ca1c9b0cSelric     "modifyTimestamp",
102ca1c9b0cSelric     "objectClass",
103ca1c9b0cSelric     "sambaAcctFlags",
104ca1c9b0cSelric     "sambaKickoffTime",
105ca1c9b0cSelric     "sambaNTPassword",
106ca1c9b0cSelric     "sambaPwdLastSet",
107ca1c9b0cSelric     "sambaPwdMustChange",
108ca1c9b0cSelric     "uid",
109ca1c9b0cSelric     NULL
110ca1c9b0cSelric };
111ca1c9b0cSelric 
112ca1c9b0cSelric static char *krb5principal_attrs[] = {
113ca1c9b0cSelric     "cn",
114ca1c9b0cSelric     "createTimestamp",
115ca1c9b0cSelric     "creatorsName",
116ca1c9b0cSelric     "krb5PrincipalName",
117ca1c9b0cSelric     "krb5PrincipalRealm",
118ca1c9b0cSelric     "modifiersName",
119ca1c9b0cSelric     "modifyTimestamp",
120ca1c9b0cSelric     "objectClass",
121ca1c9b0cSelric     "uid",
122ca1c9b0cSelric     NULL
123ca1c9b0cSelric };
124ca1c9b0cSelric 
125ca1c9b0cSelric static int
LDAP_no_size_limit(krb5_context context,LDAP * lp)126ca1c9b0cSelric LDAP_no_size_limit(krb5_context context, LDAP *lp)
127ca1c9b0cSelric {
128ca1c9b0cSelric     int ret, limit = LDAP_NO_LIMIT;
129ca1c9b0cSelric 
130ca1c9b0cSelric     ret = ldap_set_option(lp, LDAP_OPT_SIZELIMIT, (const void *)&limit);
131ca1c9b0cSelric     if (ret != LDAP_SUCCESS) {
132ca1c9b0cSelric 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
133ca1c9b0cSelric 			       "ldap_set_option: %s",
134ca1c9b0cSelric 			       ldap_err2string(ret));
135ca1c9b0cSelric 	return HDB_ERR_BADVERSION;
136ca1c9b0cSelric     }
137ca1c9b0cSelric     return 0;
138ca1c9b0cSelric }
139ca1c9b0cSelric 
140ca1c9b0cSelric static int
check_ldap(krb5_context context,HDB * db,int ret)141ca1c9b0cSelric check_ldap(krb5_context context, HDB *db, int ret)
142ca1c9b0cSelric {
143ca1c9b0cSelric     switch (ret) {
144ca1c9b0cSelric     case LDAP_SUCCESS:
145ca1c9b0cSelric 	return 0;
146ca1c9b0cSelric     case LDAP_SERVER_DOWN:
147ca1c9b0cSelric 	LDAP_close(context, db);
148ca1c9b0cSelric 	return 1;
149ca1c9b0cSelric     default:
150ca1c9b0cSelric 	return 1;
151ca1c9b0cSelric     }
152ca1c9b0cSelric }
153ca1c9b0cSelric 
154ca1c9b0cSelric static krb5_error_code
LDAP__setmod(LDAPMod *** modlist,int modop,const char * attribute,int * pIndex)155ca1c9b0cSelric LDAP__setmod(LDAPMod *** modlist, int modop, const char *attribute,
156ca1c9b0cSelric 	     int *pIndex)
157ca1c9b0cSelric {
158ca1c9b0cSelric     int cMods;
159ca1c9b0cSelric 
160ca1c9b0cSelric     if (*modlist == NULL) {
161ca1c9b0cSelric 	*modlist = (LDAPMod **)ber_memcalloc(1, sizeof(LDAPMod *));
162ca1c9b0cSelric 	if (*modlist == NULL)
163ca1c9b0cSelric 	    return ENOMEM;
164ca1c9b0cSelric     }
165ca1c9b0cSelric 
166ca1c9b0cSelric     for (cMods = 0; (*modlist)[cMods] != NULL; cMods++) {
167ca1c9b0cSelric 	if ((*modlist)[cMods]->mod_op == modop &&
168ca1c9b0cSelric 	    strcasecmp((*modlist)[cMods]->mod_type, attribute) == 0) {
169ca1c9b0cSelric 	    break;
170ca1c9b0cSelric 	}
171ca1c9b0cSelric     }
172ca1c9b0cSelric 
173ca1c9b0cSelric     *pIndex = cMods;
174ca1c9b0cSelric 
175ca1c9b0cSelric     if ((*modlist)[cMods] == NULL) {
176ca1c9b0cSelric 	LDAPMod *mod;
177ca1c9b0cSelric 
178ca1c9b0cSelric 	*modlist = (LDAPMod **)ber_memrealloc(*modlist,
179ca1c9b0cSelric 					      (cMods + 2) * sizeof(LDAPMod *));
180ca1c9b0cSelric 	if (*modlist == NULL)
181ca1c9b0cSelric 	    return ENOMEM;
182ca1c9b0cSelric 
183ca1c9b0cSelric 	(*modlist)[cMods] = (LDAPMod *)ber_memalloc(sizeof(LDAPMod));
184ca1c9b0cSelric 	if ((*modlist)[cMods] == NULL)
185ca1c9b0cSelric 	    return ENOMEM;
186ca1c9b0cSelric 
187ca1c9b0cSelric 	mod = (*modlist)[cMods];
188ca1c9b0cSelric 	mod->mod_op = modop;
189ca1c9b0cSelric 	mod->mod_type = ber_strdup(attribute);
190ca1c9b0cSelric 	if (mod->mod_type == NULL) {
191ca1c9b0cSelric 	    ber_memfree(mod);
192ca1c9b0cSelric 	    (*modlist)[cMods] = NULL;
193ca1c9b0cSelric 	    return ENOMEM;
194ca1c9b0cSelric 	}
195ca1c9b0cSelric 
196ca1c9b0cSelric 	if (modop & LDAP_MOD_BVALUES) {
197ca1c9b0cSelric 	    mod->mod_bvalues = NULL;
198ca1c9b0cSelric 	} else {
199ca1c9b0cSelric 	    mod->mod_values = NULL;
200ca1c9b0cSelric 	}
201ca1c9b0cSelric 
202ca1c9b0cSelric 	(*modlist)[cMods + 1] = NULL;
203ca1c9b0cSelric     }
204ca1c9b0cSelric 
205ca1c9b0cSelric     return 0;
206ca1c9b0cSelric }
207ca1c9b0cSelric 
208ca1c9b0cSelric static krb5_error_code
LDAP_addmod_len(LDAPMod *** modlist,int modop,const char * attribute,unsigned char * value,size_t len)209ca1c9b0cSelric LDAP_addmod_len(LDAPMod *** modlist, int modop, const char *attribute,
210ca1c9b0cSelric 		unsigned char *value, size_t len)
211ca1c9b0cSelric {
212ca1c9b0cSelric     krb5_error_code ret;
213ca1c9b0cSelric     int cMods, i = 0;
214ca1c9b0cSelric 
215ca1c9b0cSelric     ret = LDAP__setmod(modlist, modop | LDAP_MOD_BVALUES, attribute, &cMods);
216ca1c9b0cSelric     if (ret)
217ca1c9b0cSelric 	return ret;
218ca1c9b0cSelric 
219ca1c9b0cSelric     if (value != NULL) {
220ca1c9b0cSelric 	struct berval **bv;
221ca1c9b0cSelric 
222ca1c9b0cSelric 	bv = (*modlist)[cMods]->mod_bvalues;
223ca1c9b0cSelric 	if (bv != NULL) {
224ca1c9b0cSelric 	    for (i = 0; bv[i] != NULL; i++)
225ca1c9b0cSelric 		;
226ca1c9b0cSelric 	    bv = ber_memrealloc(bv, (i + 2) * sizeof(*bv));
227ca1c9b0cSelric 	} else
228ca1c9b0cSelric 	    bv = ber_memalloc(2 * sizeof(*bv));
229ca1c9b0cSelric 	if (bv == NULL)
230ca1c9b0cSelric 	    return ENOMEM;
231ca1c9b0cSelric 
232ca1c9b0cSelric 	(*modlist)[cMods]->mod_bvalues = bv;
233ca1c9b0cSelric 
234ca1c9b0cSelric 	bv[i] = ber_memalloc(sizeof(**bv));;
235ca1c9b0cSelric 	if (bv[i] == NULL)
236ca1c9b0cSelric 	    return ENOMEM;
237ca1c9b0cSelric 
238ca1c9b0cSelric 	bv[i]->bv_val = (void *)value;
239ca1c9b0cSelric 	bv[i]->bv_len = len;
240ca1c9b0cSelric 
241ca1c9b0cSelric 	bv[i + 1] = NULL;
242ca1c9b0cSelric     }
243ca1c9b0cSelric 
244ca1c9b0cSelric     return 0;
245ca1c9b0cSelric }
246ca1c9b0cSelric 
247ca1c9b0cSelric static krb5_error_code
LDAP_addmod(LDAPMod *** modlist,int modop,const char * attribute,const char * value)248ca1c9b0cSelric LDAP_addmod(LDAPMod *** modlist, int modop, const char *attribute,
249ca1c9b0cSelric 	    const char *value)
250ca1c9b0cSelric {
251ca1c9b0cSelric     int cMods, i = 0;
252ca1c9b0cSelric     krb5_error_code ret;
253ca1c9b0cSelric 
254ca1c9b0cSelric     ret = LDAP__setmod(modlist, modop, attribute, &cMods);
255ca1c9b0cSelric     if (ret)
256ca1c9b0cSelric 	return ret;
257ca1c9b0cSelric 
258ca1c9b0cSelric     if (value != NULL) {
259ca1c9b0cSelric 	char **bv;
260ca1c9b0cSelric 
261ca1c9b0cSelric 	bv = (*modlist)[cMods]->mod_values;
262ca1c9b0cSelric 	if (bv != NULL) {
263ca1c9b0cSelric 	    for (i = 0; bv[i] != NULL; i++)
264ca1c9b0cSelric 		;
265ca1c9b0cSelric 	    bv = ber_memrealloc(bv, (i + 2) * sizeof(*bv));
266ca1c9b0cSelric 	} else
267ca1c9b0cSelric 	    bv = ber_memalloc(2 * sizeof(*bv));
268ca1c9b0cSelric 	if (bv == NULL)
269ca1c9b0cSelric 	    return ENOMEM;
270ca1c9b0cSelric 
271ca1c9b0cSelric 	(*modlist)[cMods]->mod_values = bv;
272ca1c9b0cSelric 
273ca1c9b0cSelric 	bv[i] = ber_strdup(value);
274ca1c9b0cSelric 	if (bv[i] == NULL)
275ca1c9b0cSelric 	    return ENOMEM;
276ca1c9b0cSelric 
277ca1c9b0cSelric 	bv[i + 1] = NULL;
278ca1c9b0cSelric     }
279ca1c9b0cSelric 
280ca1c9b0cSelric     return 0;
281ca1c9b0cSelric }
282ca1c9b0cSelric 
283ca1c9b0cSelric static krb5_error_code
LDAP_addmod_generalized_time(LDAPMod *** mods,int modop,const char * attribute,KerberosTime * time)284ca1c9b0cSelric LDAP_addmod_generalized_time(LDAPMod *** mods, int modop,
285ca1c9b0cSelric 			     const char *attribute, KerberosTime * time)
286ca1c9b0cSelric {
287ca1c9b0cSelric     char buf[22];
288ca1c9b0cSelric     struct tm *tm;
289ca1c9b0cSelric 
290ca1c9b0cSelric     /* XXX not threadsafe */
291ca1c9b0cSelric     tm = gmtime(time);
292ca1c9b0cSelric     strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", tm);
293ca1c9b0cSelric 
294ca1c9b0cSelric     return LDAP_addmod(mods, modop, attribute, buf);
295ca1c9b0cSelric }
296ca1c9b0cSelric 
297ca1c9b0cSelric static krb5_error_code
LDAP_addmod_integer(krb5_context context,LDAPMod *** mods,int modop,const char * attribute,unsigned long l)298ca1c9b0cSelric LDAP_addmod_integer(krb5_context context,
299ca1c9b0cSelric 		    LDAPMod *** mods, int modop,
300ca1c9b0cSelric 		    const char *attribute, unsigned long l)
301ca1c9b0cSelric {
302ca1c9b0cSelric     krb5_error_code ret;
303ca1c9b0cSelric     char *buf;
304ca1c9b0cSelric 
305ca1c9b0cSelric     ret = asprintf(&buf, "%ld", l);
306ca1c9b0cSelric     if (ret < 0) {
307ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM,
308ca1c9b0cSelric 			       "asprintf: out of memory:");
309ca1c9b0cSelric 	return ENOMEM;
310ca1c9b0cSelric     }
311ca1c9b0cSelric     ret = LDAP_addmod(mods, modop, attribute, buf);
312ca1c9b0cSelric     free (buf);
313ca1c9b0cSelric     return ret;
314ca1c9b0cSelric }
315ca1c9b0cSelric 
316ca1c9b0cSelric static krb5_error_code
LDAP_get_string_value(HDB * db,LDAPMessage * entry,const char * attribute,char ** ptr)317ca1c9b0cSelric LDAP_get_string_value(HDB * db, LDAPMessage * entry,
318ca1c9b0cSelric 		      const char *attribute, char **ptr)
319ca1c9b0cSelric {
320ca1c9b0cSelric     struct berval **vals;
321ca1c9b0cSelric 
322ca1c9b0cSelric     vals = ldap_get_values_len(HDB2LDAP(db), entry, attribute);
323ca1c9b0cSelric     if (vals == NULL || vals[0] == NULL) {
324ca1c9b0cSelric 	*ptr = NULL;
325ca1c9b0cSelric 	return HDB_ERR_NOENTRY;
326ca1c9b0cSelric     }
327ca1c9b0cSelric 
328ca1c9b0cSelric     *ptr = malloc(vals[0]->bv_len + 1);
329ca1c9b0cSelric     if (*ptr == NULL) {
330ca1c9b0cSelric 	ldap_value_free_len(vals);
331ca1c9b0cSelric 	return ENOMEM;
332ca1c9b0cSelric     }
333ca1c9b0cSelric 
334ca1c9b0cSelric     memcpy(*ptr, vals[0]->bv_val, vals[0]->bv_len);
335ca1c9b0cSelric     (*ptr)[vals[0]->bv_len] = 0;
336ca1c9b0cSelric 
337ca1c9b0cSelric     ldap_value_free_len(vals);
338ca1c9b0cSelric 
339ca1c9b0cSelric     return 0;
340ca1c9b0cSelric }
341ca1c9b0cSelric 
342ca1c9b0cSelric static krb5_error_code
LDAP_get_integer_value(HDB * db,LDAPMessage * entry,const char * attribute,int * ptr)343ca1c9b0cSelric LDAP_get_integer_value(HDB * db, LDAPMessage * entry,
344ca1c9b0cSelric 		       const char *attribute, int *ptr)
345ca1c9b0cSelric {
346ca1c9b0cSelric     krb5_error_code ret;
347ca1c9b0cSelric     char *val;
348ca1c9b0cSelric 
349ca1c9b0cSelric     ret = LDAP_get_string_value(db, entry, attribute, &val);
350ca1c9b0cSelric     if (ret)
351ca1c9b0cSelric 	return ret;
352ca1c9b0cSelric     *ptr = atoi(val);
353ca1c9b0cSelric     free(val);
354ca1c9b0cSelric     return 0;
355ca1c9b0cSelric }
356ca1c9b0cSelric 
357ca1c9b0cSelric static krb5_error_code
LDAP_get_generalized_time_value(HDB * db,LDAPMessage * entry,const char * attribute,KerberosTime * kt)358ca1c9b0cSelric LDAP_get_generalized_time_value(HDB * db, LDAPMessage * entry,
359ca1c9b0cSelric 				const char *attribute, KerberosTime * kt)
360ca1c9b0cSelric {
361ca1c9b0cSelric     char *tmp, *gentime;
362ca1c9b0cSelric     struct tm tm;
363ca1c9b0cSelric     int ret;
364ca1c9b0cSelric 
365ca1c9b0cSelric     *kt = 0;
366ca1c9b0cSelric 
367ca1c9b0cSelric     ret = LDAP_get_string_value(db, entry, attribute, &gentime);
368ca1c9b0cSelric     if (ret)
369ca1c9b0cSelric 	return ret;
370ca1c9b0cSelric 
371ca1c9b0cSelric     tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm);
372ca1c9b0cSelric     if (tmp == NULL) {
373ca1c9b0cSelric 	free(gentime);
374ca1c9b0cSelric 	return HDB_ERR_NOENTRY;
375ca1c9b0cSelric     }
376ca1c9b0cSelric 
377ca1c9b0cSelric     free(gentime);
378ca1c9b0cSelric 
379ca1c9b0cSelric     *kt = timegm(&tm);
380ca1c9b0cSelric 
381ca1c9b0cSelric     return 0;
382ca1c9b0cSelric }
383ca1c9b0cSelric 
384ca1c9b0cSelric static int
bervalstrcmp(struct berval * v,const char * str)385ca1c9b0cSelric bervalstrcmp(struct berval *v, const char *str)
386ca1c9b0cSelric {
387ca1c9b0cSelric     size_t len = strlen(str);
388ca1c9b0cSelric     return (v->bv_len == len) && strncasecmp(str, (char *)v->bv_val, len) == 0;
389ca1c9b0cSelric }
390ca1c9b0cSelric 
391ca1c9b0cSelric 
392ca1c9b0cSelric static krb5_error_code
LDAP_entry2mods(krb5_context context,HDB * db,hdb_entry_ex * ent,LDAPMessage * msg,LDAPMod *** pmods)393ca1c9b0cSelric LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
394ca1c9b0cSelric 		LDAPMessage * msg, LDAPMod *** pmods)
395ca1c9b0cSelric {
396ca1c9b0cSelric     krb5_error_code ret;
397ca1c9b0cSelric     krb5_boolean is_new_entry;
398ca1c9b0cSelric     char *tmp = NULL;
399ca1c9b0cSelric     LDAPMod **mods = NULL;
400ca1c9b0cSelric     hdb_entry_ex orig;
401ca1c9b0cSelric     unsigned long oflags, nflags;
402ca1c9b0cSelric     int i;
403ca1c9b0cSelric 
404ca1c9b0cSelric     krb5_boolean is_samba_account = FALSE;
405ca1c9b0cSelric     krb5_boolean is_account = FALSE;
406ca1c9b0cSelric     krb5_boolean is_heimdal_entry = FALSE;
407ca1c9b0cSelric     krb5_boolean is_heimdal_principal = FALSE;
408ca1c9b0cSelric 
409ca1c9b0cSelric     struct berval **vals;
410ca1c9b0cSelric 
411ca1c9b0cSelric     *pmods = NULL;
412ca1c9b0cSelric 
413ca1c9b0cSelric     if (msg != NULL) {
414ca1c9b0cSelric 
415ca1c9b0cSelric 	ret = LDAP_message2entry(context, db, msg, 0, &orig);
416ca1c9b0cSelric 	if (ret)
417ca1c9b0cSelric 	    goto out;
418ca1c9b0cSelric 
419ca1c9b0cSelric 	is_new_entry = FALSE;
420ca1c9b0cSelric 
421ca1c9b0cSelric 	vals = ldap_get_values_len(HDB2LDAP(db), msg, "objectClass");
422ca1c9b0cSelric 	if (vals) {
423ca1c9b0cSelric 	    int num_objectclasses = ldap_count_values_len(vals);
424ca1c9b0cSelric 	    for (i=0; i < num_objectclasses; i++) {
425ca1c9b0cSelric 		if (bervalstrcmp(vals[i], "sambaSamAccount"))
426ca1c9b0cSelric 		    is_samba_account = TRUE;
427ca1c9b0cSelric 		else if (bervalstrcmp(vals[i], structural_object))
428ca1c9b0cSelric 		    is_account = TRUE;
429ca1c9b0cSelric 		else if (bervalstrcmp(vals[i], "krb5Principal"))
430ca1c9b0cSelric 		    is_heimdal_principal = TRUE;
431ca1c9b0cSelric 		else if (bervalstrcmp(vals[i], "krb5KDCEntry"))
432ca1c9b0cSelric 		    is_heimdal_entry = TRUE;
433ca1c9b0cSelric 	    }
434ca1c9b0cSelric 	    ldap_value_free_len(vals);
435ca1c9b0cSelric 	}
436ca1c9b0cSelric 
437ca1c9b0cSelric 	/*
438ca1c9b0cSelric 	 * If this is just a "account" entry and no other objectclass
439ca1c9b0cSelric 	 * is hanging on this entry, it's really a new entry.
440ca1c9b0cSelric 	 */
441ca1c9b0cSelric 	if (is_samba_account == FALSE && is_heimdal_principal == FALSE &&
442ca1c9b0cSelric 	    is_heimdal_entry == FALSE) {
443ca1c9b0cSelric 	    if (is_account == TRUE) {
444ca1c9b0cSelric 		is_new_entry = TRUE;
445ca1c9b0cSelric 	    } else {
446ca1c9b0cSelric 		ret = HDB_ERR_NOENTRY;
447ca1c9b0cSelric 		goto out;
448ca1c9b0cSelric 	    }
449ca1c9b0cSelric 	}
450ca1c9b0cSelric     } else
451ca1c9b0cSelric 	is_new_entry = TRUE;
452ca1c9b0cSelric 
453ca1c9b0cSelric     if (is_new_entry) {
454ca1c9b0cSelric 
455ca1c9b0cSelric 	/* to make it perfectly obvious we're depending on
456ca1c9b0cSelric 	 * orig being intiialized to zero */
457ca1c9b0cSelric 	memset(&orig, 0, sizeof(orig));
458ca1c9b0cSelric 
459ca1c9b0cSelric 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "top");
460ca1c9b0cSelric 	if (ret)
461ca1c9b0cSelric 	    goto out;
462ca1c9b0cSelric 
463ca1c9b0cSelric 	/* account is the structural object class */
464ca1c9b0cSelric 	if (is_account == FALSE) {
465ca1c9b0cSelric 	    ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass",
466ca1c9b0cSelric 			      structural_object);
467ca1c9b0cSelric 	    is_account = TRUE;
468ca1c9b0cSelric 	    if (ret)
469ca1c9b0cSelric 		goto out;
470ca1c9b0cSelric 	}
471ca1c9b0cSelric 
472ca1c9b0cSelric 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5Principal");
473ca1c9b0cSelric 	is_heimdal_principal = TRUE;
474ca1c9b0cSelric 	if (ret)
475ca1c9b0cSelric 	    goto out;
476ca1c9b0cSelric 
477ca1c9b0cSelric 	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5KDCEntry");
478ca1c9b0cSelric 	is_heimdal_entry = TRUE;
479ca1c9b0cSelric 	if (ret)
480ca1c9b0cSelric 	    goto out;
481ca1c9b0cSelric     }
482ca1c9b0cSelric 
483ca1c9b0cSelric     if (is_new_entry ||
484ca1c9b0cSelric 	krb5_principal_compare(context, ent->entry.principal, orig.entry.principal)
485ca1c9b0cSelric 	== FALSE)
486ca1c9b0cSelric     {
487ca1c9b0cSelric 	if (is_heimdal_principal || is_heimdal_entry) {
488ca1c9b0cSelric 
489ca1c9b0cSelric 	    ret = krb5_unparse_name(context, ent->entry.principal, &tmp);
490ca1c9b0cSelric 	    if (ret)
491ca1c9b0cSelric 		goto out;
492ca1c9b0cSelric 
493ca1c9b0cSelric 	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE,
494ca1c9b0cSelric 			      "krb5PrincipalName", tmp);
495ca1c9b0cSelric 	    if (ret) {
496ca1c9b0cSelric 		free(tmp);
497ca1c9b0cSelric 		goto out;
498ca1c9b0cSelric 	    }
499ca1c9b0cSelric 	    free(tmp);
500ca1c9b0cSelric 	}
501ca1c9b0cSelric 
502ca1c9b0cSelric 	if (is_account || is_samba_account) {
503ca1c9b0cSelric 	    ret = krb5_unparse_name_short(context, ent->entry.principal, &tmp);
504ca1c9b0cSelric 	    if (ret)
505ca1c9b0cSelric 		goto out;
506ca1c9b0cSelric 	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "uid", tmp);
507ca1c9b0cSelric 	    if (ret) {
508ca1c9b0cSelric 		free(tmp);
509ca1c9b0cSelric 		goto out;
510ca1c9b0cSelric 	    }
511ca1c9b0cSelric 	    free(tmp);
512ca1c9b0cSelric 	}
513ca1c9b0cSelric     }
514ca1c9b0cSelric 
515ca1c9b0cSelric     if (is_heimdal_entry && (ent->entry.kvno != orig.entry.kvno || is_new_entry)) {
516ca1c9b0cSelric 	ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
517ca1c9b0cSelric 			    "krb5KeyVersionNumber",
518ca1c9b0cSelric 			    ent->entry.kvno);
519ca1c9b0cSelric 	if (ret)
520ca1c9b0cSelric 	    goto out;
521ca1c9b0cSelric     }
522ca1c9b0cSelric 
523b9d004c6Schristos     if (is_heimdal_entry && ent->entry.extensions) {
524b9d004c6Schristos 	if (!is_new_entry) {
525b9d004c6Schristos 	    vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5ExtendedAttributes");
526b9d004c6Schristos 	    if (vals) {
527b9d004c6Schristos 		ldap_value_free_len(vals);
528b9d004c6Schristos 		ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5ExtendedAttributes", NULL);
529b9d004c6Schristos 		if (ret)
530b9d004c6Schristos 		    goto out;
531b9d004c6Schristos 	    }
532b9d004c6Schristos 	}
533b9d004c6Schristos 
534b9d004c6Schristos 	for (i = 0; i < ent->entry.extensions->len; i++) {
535b9d004c6Schristos 	    unsigned char *buf;
536b9d004c6Schristos 	    size_t size, sz = 0;
537b9d004c6Schristos 
538b9d004c6Schristos 	    ASN1_MALLOC_ENCODE(HDB_extension, buf, size, &ent->entry.extensions->val[i], &sz, ret);
539b9d004c6Schristos 	    if (ret)
540b9d004c6Schristos 		goto out;
541b9d004c6Schristos 	    if (size != sz)
542b9d004c6Schristos 		krb5_abortx(context, "internal error in ASN.1 encoder");
543b9d004c6Schristos 
544b9d004c6Schristos 	    ret = LDAP_addmod_len(&mods, LDAP_MOD_ADD, "krb5ExtendedAttributes", buf, sz);
545b9d004c6Schristos 	    if (ret)
546b9d004c6Schristos 		goto out;
547b9d004c6Schristos 	}
548b9d004c6Schristos     }
549b9d004c6Schristos 
550ca1c9b0cSelric     if (is_heimdal_entry && ent->entry.valid_start) {
551ca1c9b0cSelric 	if (orig.entry.valid_end == NULL
552ca1c9b0cSelric 	    || (*(ent->entry.valid_start) != *(orig.entry.valid_start))) {
553ca1c9b0cSelric 	    ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
554ca1c9b0cSelric 					       "krb5ValidStart",
555ca1c9b0cSelric 					       ent->entry.valid_start);
556ca1c9b0cSelric 	    if (ret)
557ca1c9b0cSelric 		goto out;
558ca1c9b0cSelric 	}
559ca1c9b0cSelric     }
560ca1c9b0cSelric 
561ca1c9b0cSelric     if (ent->entry.valid_end) {
562ca1c9b0cSelric  	if (orig.entry.valid_end == NULL || (*(ent->entry.valid_end) != *(orig.entry.valid_end))) {
563ca1c9b0cSelric 	    if (is_heimdal_entry) {
564ca1c9b0cSelric 		ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
565ca1c9b0cSelric 						   "krb5ValidEnd",
566ca1c9b0cSelric 						   ent->entry.valid_end);
567ca1c9b0cSelric 		if (ret)
568ca1c9b0cSelric 		    goto out;
569ca1c9b0cSelric             }
570ca1c9b0cSelric 	    if (is_samba_account) {
571ca1c9b0cSelric 		ret = LDAP_addmod_integer(context, &mods,  LDAP_MOD_REPLACE,
572ca1c9b0cSelric 					  "sambaKickoffTime",
573ca1c9b0cSelric 					  *(ent->entry.valid_end));
574ca1c9b0cSelric 		if (ret)
575ca1c9b0cSelric 		    goto out;
576ca1c9b0cSelric 	    }
577ca1c9b0cSelric    	}
578ca1c9b0cSelric     }
579ca1c9b0cSelric 
580ca1c9b0cSelric     if (ent->entry.pw_end) {
581ca1c9b0cSelric 	if (orig.entry.pw_end == NULL || (*(ent->entry.pw_end) != *(orig.entry.pw_end))) {
582ca1c9b0cSelric 	    if (is_heimdal_entry) {
583ca1c9b0cSelric 		ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
584ca1c9b0cSelric 						   "krb5PasswordEnd",
585ca1c9b0cSelric 						   ent->entry.pw_end);
586ca1c9b0cSelric 		if (ret)
587ca1c9b0cSelric 		    goto out;
588ca1c9b0cSelric 	    }
589ca1c9b0cSelric 
590ca1c9b0cSelric 	    if (is_samba_account) {
591ca1c9b0cSelric 		ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
592ca1c9b0cSelric 					  "sambaPwdMustChange",
593ca1c9b0cSelric 					  *(ent->entry.pw_end));
594ca1c9b0cSelric 		if (ret)
595ca1c9b0cSelric 		    goto out;
596ca1c9b0cSelric 	    }
597ca1c9b0cSelric 	}
598ca1c9b0cSelric     }
599ca1c9b0cSelric 
600ca1c9b0cSelric 
601ca1c9b0cSelric #if 0 /* we we have last_pw_change */
602ca1c9b0cSelric     if (is_samba_account && ent->entry.last_pw_change) {
603ca1c9b0cSelric 	if (orig.entry.last_pw_change == NULL || (*(ent->entry.last_pw_change) != *(orig.entry.last_pw_change))) {
604ca1c9b0cSelric 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
605ca1c9b0cSelric 				      "sambaPwdLastSet",
606ca1c9b0cSelric 				      *(ent->entry.last_pw_change));
607ca1c9b0cSelric 	    if (ret)
608ca1c9b0cSelric 		goto out;
609ca1c9b0cSelric 	}
610ca1c9b0cSelric     }
611ca1c9b0cSelric #endif
612ca1c9b0cSelric 
613ca1c9b0cSelric     if (is_heimdal_entry && ent->entry.max_life) {
614ca1c9b0cSelric 	if (orig.entry.max_life == NULL
615ca1c9b0cSelric 	    || (*(ent->entry.max_life) != *(orig.entry.max_life))) {
616ca1c9b0cSelric 
617ca1c9b0cSelric 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
618ca1c9b0cSelric 				      "krb5MaxLife",
619ca1c9b0cSelric 				      *(ent->entry.max_life));
620ca1c9b0cSelric 	    if (ret)
621ca1c9b0cSelric 		goto out;
622ca1c9b0cSelric 	}
623ca1c9b0cSelric     }
624ca1c9b0cSelric 
625ca1c9b0cSelric     if (is_heimdal_entry && ent->entry.max_renew) {
626ca1c9b0cSelric 	if (orig.entry.max_renew == NULL
627ca1c9b0cSelric 	    || (*(ent->entry.max_renew) != *(orig.entry.max_renew))) {
628ca1c9b0cSelric 
629ca1c9b0cSelric 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
630ca1c9b0cSelric 				      "krb5MaxRenew",
631ca1c9b0cSelric 				      *(ent->entry.max_renew));
632ca1c9b0cSelric 	    if (ret)
633ca1c9b0cSelric 		goto out;
634ca1c9b0cSelric 	}
635ca1c9b0cSelric     }
636ca1c9b0cSelric 
637ca1c9b0cSelric     oflags = HDBFlags2int(orig.entry.flags);
638ca1c9b0cSelric     nflags = HDBFlags2int(ent->entry.flags);
639ca1c9b0cSelric 
640ca1c9b0cSelric     if (is_heimdal_entry && oflags != nflags) {
641ca1c9b0cSelric 
642ca1c9b0cSelric 	ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
643ca1c9b0cSelric 				  "krb5KDCFlags",
644ca1c9b0cSelric 				  nflags);
645ca1c9b0cSelric 	if (ret)
646ca1c9b0cSelric 	    goto out;
647ca1c9b0cSelric     }
648ca1c9b0cSelric 
649ca1c9b0cSelric     /* Remove keys if they exists, and then replace keys. */
650ca1c9b0cSelric     if (!is_new_entry && orig.entry.keys.len > 0) {
651ca1c9b0cSelric 	vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key");
652ca1c9b0cSelric 	if (vals) {
653ca1c9b0cSelric 	    ldap_value_free_len(vals);
654ca1c9b0cSelric 
655ca1c9b0cSelric 	    ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5Key", NULL);
656ca1c9b0cSelric 	    if (ret)
657ca1c9b0cSelric 		goto out;
658ca1c9b0cSelric 	}
659ca1c9b0cSelric     }
660ca1c9b0cSelric 
661ca1c9b0cSelric     for (i = 0; i < ent->entry.keys.len; i++) {
662ca1c9b0cSelric 
663ca1c9b0cSelric 	if (is_samba_account
664ca1c9b0cSelric 	    && ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
665ca1c9b0cSelric 	    char *ntHexPassword;
666ca1c9b0cSelric 	    char *nt;
667ca1c9b0cSelric 	    time_t now = time(NULL);
668ca1c9b0cSelric 
669ca1c9b0cSelric 	    /* the key might have been 'sealed', but samba passwords
670ca1c9b0cSelric 	       are clear in the directory */
671ca1c9b0cSelric 	    ret = hdb_unseal_key(context, db, &ent->entry.keys.val[i]);
672ca1c9b0cSelric 	    if (ret)
673ca1c9b0cSelric 		goto out;
674ca1c9b0cSelric 
675ca1c9b0cSelric 	    nt = ent->entry.keys.val[i].key.keyvalue.data;
676ca1c9b0cSelric 	    /* store in ntPassword, not krb5key */
677ca1c9b0cSelric 	    ret = hex_encode(nt, 16, &ntHexPassword);
678ca1c9b0cSelric 	    if (ret < 0) {
679ca1c9b0cSelric 		ret = ENOMEM;
680ca1c9b0cSelric 		krb5_set_error_message(context, ret, "hdb-ldap: failed to "
681ca1c9b0cSelric 				      "hex encode key");
682ca1c9b0cSelric 		goto out;
683ca1c9b0cSelric 	    }
684ca1c9b0cSelric 	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "sambaNTPassword",
685ca1c9b0cSelric 			      ntHexPassword);
686ca1c9b0cSelric 	    free(ntHexPassword);
687ca1c9b0cSelric 	    if (ret)
688ca1c9b0cSelric 		goto out;
689ca1c9b0cSelric 	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
690ca1c9b0cSelric 				      "sambaPwdLastSet", now);
691ca1c9b0cSelric 	    if (ret)
692ca1c9b0cSelric 		goto out;
693ca1c9b0cSelric 
694ca1c9b0cSelric 	    /* have to kill the LM passwod if it exists */
695ca1c9b0cSelric 	    vals = ldap_get_values_len(HDB2LDAP(db), msg, "sambaLMPassword");
696ca1c9b0cSelric 	    if (vals) {
697ca1c9b0cSelric 		ldap_value_free_len(vals);
698ca1c9b0cSelric 		ret = LDAP_addmod(&mods, LDAP_MOD_DELETE,
699ca1c9b0cSelric 				  "sambaLMPassword", NULL);
700ca1c9b0cSelric 		if (ret)
701ca1c9b0cSelric 		    goto out;
702ca1c9b0cSelric 	    }
703ca1c9b0cSelric 
704ca1c9b0cSelric 	} else if (is_heimdal_entry) {
705ca1c9b0cSelric 	    unsigned char *buf;
706ca1c9b0cSelric 	    size_t len, buf_size;
707ca1c9b0cSelric 
708ca1c9b0cSelric 	    ASN1_MALLOC_ENCODE(Key, buf, buf_size, &ent->entry.keys.val[i], &len, ret);
709ca1c9b0cSelric 	    if (ret)
710ca1c9b0cSelric 		goto out;
711ca1c9b0cSelric 	    if(buf_size != len)
712ca1c9b0cSelric 		krb5_abortx(context, "internal error in ASN.1 encoder");
713ca1c9b0cSelric 
714ca1c9b0cSelric 	    /* addmod_len _owns_ the key, doesn't need to copy it */
715ca1c9b0cSelric 	    ret = LDAP_addmod_len(&mods, LDAP_MOD_ADD, "krb5Key", buf, len);
716ca1c9b0cSelric 	    if (ret)
717ca1c9b0cSelric 		goto out;
718ca1c9b0cSelric 	}
719ca1c9b0cSelric     }
720ca1c9b0cSelric 
721ca1c9b0cSelric     if (ent->entry.etypes) {
722ca1c9b0cSelric 	int add_krb5EncryptionType = 0;
723ca1c9b0cSelric 
724ca1c9b0cSelric 	/*
725ca1c9b0cSelric 	 * Only add/modify krb5EncryptionType if it's a new heimdal
726ca1c9b0cSelric 	 * entry or krb5EncryptionType already exists on the entry.
727ca1c9b0cSelric 	 */
728ca1c9b0cSelric 
729ca1c9b0cSelric 	if (!is_new_entry) {
730ca1c9b0cSelric 	    vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType");
731ca1c9b0cSelric 	    if (vals) {
732ca1c9b0cSelric 		ldap_value_free_len(vals);
733ca1c9b0cSelric 		ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5EncryptionType",
734ca1c9b0cSelric 				  NULL);
735ca1c9b0cSelric 		if (ret)
736ca1c9b0cSelric 		    goto out;
737ca1c9b0cSelric 		add_krb5EncryptionType = 1;
738ca1c9b0cSelric 	    }
739ca1c9b0cSelric 	} else if (is_heimdal_entry)
740ca1c9b0cSelric 	    add_krb5EncryptionType = 1;
741ca1c9b0cSelric 
742ca1c9b0cSelric 	if (add_krb5EncryptionType) {
743ca1c9b0cSelric 	    for (i = 0; i < ent->entry.etypes->len; i++) {
744ca1c9b0cSelric 		if (is_samba_account &&
745ca1c9b0cSelric 		    ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5)
746ca1c9b0cSelric 		{
747ca1c9b0cSelric 		    ;
748ca1c9b0cSelric 		} else if (is_heimdal_entry) {
749ca1c9b0cSelric 		    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_ADD,
750ca1c9b0cSelric 					      "krb5EncryptionType",
751ca1c9b0cSelric 					      ent->entry.etypes->val[i]);
752ca1c9b0cSelric 		    if (ret)
753ca1c9b0cSelric 			goto out;
754ca1c9b0cSelric 		}
755ca1c9b0cSelric 	    }
756ca1c9b0cSelric 	}
757ca1c9b0cSelric     }
758ca1c9b0cSelric 
759ca1c9b0cSelric     /* for clarity */
760ca1c9b0cSelric     ret = 0;
761ca1c9b0cSelric 
762ca1c9b0cSelric  out:
763ca1c9b0cSelric 
764ca1c9b0cSelric     if (ret == 0)
765ca1c9b0cSelric 	*pmods = mods;
766ca1c9b0cSelric     else if (mods != NULL) {
767ca1c9b0cSelric 	ldap_mods_free(mods, 1);
768ca1c9b0cSelric 	*pmods = NULL;
769ca1c9b0cSelric     }
770ca1c9b0cSelric 
771ca1c9b0cSelric     if (msg)
772ca1c9b0cSelric 	hdb_free_entry(context, &orig);
773ca1c9b0cSelric 
774ca1c9b0cSelric     return ret;
775ca1c9b0cSelric }
776ca1c9b0cSelric 
777ca1c9b0cSelric static krb5_error_code
LDAP_dn2principal(krb5_context context,HDB * db,const char * dn,krb5_principal * principal)778ca1c9b0cSelric LDAP_dn2principal(krb5_context context, HDB * db, const char *dn,
779ca1c9b0cSelric 		  krb5_principal * principal)
780ca1c9b0cSelric {
781ca1c9b0cSelric     krb5_error_code ret;
782ca1c9b0cSelric     int rc;
783ca1c9b0cSelric     const char *filter = "(objectClass=krb5Principal)";
784ca1c9b0cSelric     LDAPMessage *res = NULL, *e;
785ca1c9b0cSelric     char *p;
786ca1c9b0cSelric 
787ca1c9b0cSelric     ret = LDAP_no_size_limit(context, HDB2LDAP(db));
788ca1c9b0cSelric     if (ret)
789ca1c9b0cSelric 	goto out;
790ca1c9b0cSelric 
791ca1c9b0cSelric     rc = ldap_search_ext_s(HDB2LDAP(db), dn, LDAP_SCOPE_SUBTREE,
792ca1c9b0cSelric 			   filter, krb5principal_attrs, 0,
793ca1c9b0cSelric 			   NULL, NULL, NULL,
794ca1c9b0cSelric 			   0, &res);
795ca1c9b0cSelric     if (check_ldap(context, db, rc)) {
796ca1c9b0cSelric 	ret = HDB_ERR_NOENTRY;
797ca1c9b0cSelric 	krb5_set_error_message(context, ret, "ldap_search_ext_s: "
798ca1c9b0cSelric 			       "filter: %s error: %s",
799ca1c9b0cSelric 			       filter, ldap_err2string(rc));
800ca1c9b0cSelric 	goto out;
801ca1c9b0cSelric     }
802ca1c9b0cSelric 
803ca1c9b0cSelric     e = ldap_first_entry(HDB2LDAP(db), res);
804ca1c9b0cSelric     if (e == NULL) {
805ca1c9b0cSelric 	ret = HDB_ERR_NOENTRY;
806ca1c9b0cSelric 	goto out;
807ca1c9b0cSelric     }
808ca1c9b0cSelric 
809ca1c9b0cSelric     ret = LDAP_get_string_value(db, e, "krb5PrincipalName", &p);
810ca1c9b0cSelric     if (ret) {
811ca1c9b0cSelric 	ret = HDB_ERR_NOENTRY;
812ca1c9b0cSelric 	goto out;
813ca1c9b0cSelric     }
814ca1c9b0cSelric 
815ca1c9b0cSelric     ret = krb5_parse_name(context, p, principal);
816ca1c9b0cSelric     free(p);
817ca1c9b0cSelric 
818ca1c9b0cSelric   out:
819ca1c9b0cSelric     if (res)
820ca1c9b0cSelric 	ldap_msgfree(res);
821ca1c9b0cSelric 
822ca1c9b0cSelric     return ret;
823ca1c9b0cSelric }
824ca1c9b0cSelric 
825ca1c9b0cSelric static int
need_quote(unsigned char c)826ca1c9b0cSelric need_quote(unsigned char c)
827ca1c9b0cSelric {
828ca1c9b0cSelric     return (c & 0x80) ||
829ca1c9b0cSelric 	(c < 32) ||
830ca1c9b0cSelric 	(c == '(') ||
831ca1c9b0cSelric 	(c == ')') ||
832ca1c9b0cSelric 	(c == '*') ||
833ca1c9b0cSelric 	(c == '\\') ||
834ca1c9b0cSelric 	(c == 0x7f);
835ca1c9b0cSelric }
836ca1c9b0cSelric 
837b9d004c6Schristos static const char hexchar[] = "0123456789ABCDEF";
838ca1c9b0cSelric 
839ca1c9b0cSelric static krb5_error_code
escape_value(krb5_context context,const char * unquoted,char ** quoted)840b9d004c6Schristos escape_value(krb5_context context, const char *unquoted, char **quoted)
841ca1c9b0cSelric {
842ca1c9b0cSelric     size_t i, len;
843ca1c9b0cSelric 
844ca1c9b0cSelric     for (i = 0, len = 0; unquoted[i] != '\0'; i++, len++) {
845ca1c9b0cSelric 	if (need_quote((unsigned char)unquoted[i]))
846ca1c9b0cSelric 	    len += 2;
847ca1c9b0cSelric     }
848ca1c9b0cSelric 
849ca1c9b0cSelric     *quoted = malloc(len + 1);
850ca1c9b0cSelric     if (*quoted == NULL) {
851ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
852ca1c9b0cSelric 	return ENOMEM;
853ca1c9b0cSelric     }
854ca1c9b0cSelric 
855ca1c9b0cSelric     for (i = 0; unquoted[0] ; unquoted++) {
856b9d004c6Schristos 	if (need_quote((unsigned char)unquoted[0])) {
857ca1c9b0cSelric 	    (*quoted)[i++] = '\\';
858ca1c9b0cSelric 	    (*quoted)[i++] = hexchar[(unquoted[0] >> 4) & 0xf];
859ca1c9b0cSelric 	    (*quoted)[i++] = hexchar[(unquoted[0]     ) & 0xf];
860ca1c9b0cSelric 	} else
861ca1c9b0cSelric 	    (*quoted)[i++] = (char)unquoted[0];
862ca1c9b0cSelric     }
863ca1c9b0cSelric     (*quoted)[i] = '\0';
864ca1c9b0cSelric     return 0;
865ca1c9b0cSelric }
866ca1c9b0cSelric 
867ca1c9b0cSelric 
868ca1c9b0cSelric static krb5_error_code
LDAP__lookup_princ(krb5_context context,HDB * db,const char * princname,const char * userid,LDAPMessage ** msg)869ca1c9b0cSelric LDAP__lookup_princ(krb5_context context,
870ca1c9b0cSelric 		   HDB *db,
871ca1c9b0cSelric 		   const char *princname,
872ca1c9b0cSelric 		   const char *userid,
873ca1c9b0cSelric 		   LDAPMessage **msg)
874ca1c9b0cSelric {
875ca1c9b0cSelric     krb5_error_code ret;
876ca1c9b0cSelric     int rc;
877ca1c9b0cSelric     char *quote, *filter = NULL;
878ca1c9b0cSelric 
879ca1c9b0cSelric     ret = LDAP__connect(context, db);
880ca1c9b0cSelric     if (ret)
881ca1c9b0cSelric 	return ret;
882ca1c9b0cSelric 
883ca1c9b0cSelric     /*
884ca1c9b0cSelric      * Quote searches that contain filter language, this quote
885ca1c9b0cSelric      * searches for *@REALM, which takes very long time.
886ca1c9b0cSelric      */
887ca1c9b0cSelric 
888ca1c9b0cSelric     ret = escape_value(context, princname, &quote);
889ca1c9b0cSelric     if (ret)
890ca1c9b0cSelric 	goto out;
891ca1c9b0cSelric 
892ca1c9b0cSelric     rc = asprintf(&filter,
893ca1c9b0cSelric 		  "(&(objectClass=krb5Principal)(krb5PrincipalName=%s))",
894ca1c9b0cSelric 		  quote);
895ca1c9b0cSelric     free(quote);
896ca1c9b0cSelric 
897ca1c9b0cSelric     if (rc < 0) {
898ca1c9b0cSelric 	ret = ENOMEM;
899ca1c9b0cSelric 	krb5_set_error_message(context, ret, "malloc: out of memory");
900ca1c9b0cSelric 	goto out;
901ca1c9b0cSelric     }
902ca1c9b0cSelric 
903ca1c9b0cSelric     ret = LDAP_no_size_limit(context, HDB2LDAP(db));
904ca1c9b0cSelric     if (ret)
905ca1c9b0cSelric 	goto out;
906ca1c9b0cSelric 
907ca1c9b0cSelric     rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db),
908ca1c9b0cSelric 			   LDAP_SCOPE_SUBTREE, filter,
909ca1c9b0cSelric 			   krb5kdcentry_attrs, 0,
910ca1c9b0cSelric 			   NULL, NULL, NULL,
911ca1c9b0cSelric 			   0, msg);
912ca1c9b0cSelric     if (check_ldap(context, db, rc)) {
913ca1c9b0cSelric 	ret = HDB_ERR_NOENTRY;
914ca1c9b0cSelric 	krb5_set_error_message(context, ret, "ldap_search_ext_s: "
915ca1c9b0cSelric 			      "filter: %s - error: %s",
916ca1c9b0cSelric 			      filter, ldap_err2string(rc));
917ca1c9b0cSelric 	goto out;
918ca1c9b0cSelric     }
919ca1c9b0cSelric 
920ca1c9b0cSelric     if (userid && ldap_count_entries(HDB2LDAP(db), *msg) == 0) {
921ca1c9b0cSelric 	free(filter);
922ca1c9b0cSelric 	filter = NULL;
923ca1c9b0cSelric 	ldap_msgfree(*msg);
924ca1c9b0cSelric 	*msg = NULL;
925ca1c9b0cSelric 
926ca1c9b0cSelric 	ret = escape_value(context, userid, &quote);
927ca1c9b0cSelric 	if (ret)
928ca1c9b0cSelric 	    goto out;
929ca1c9b0cSelric 
930ca1c9b0cSelric 	rc = asprintf(&filter,
931ca1c9b0cSelric 	    "(&(|(objectClass=sambaSamAccount)(objectClass=%s))(uid=%s))",
932ca1c9b0cSelric 		      structural_object, quote);
933ca1c9b0cSelric 	free(quote);
934ca1c9b0cSelric 	if (rc < 0) {
935ca1c9b0cSelric 	    ret = ENOMEM;
936ca1c9b0cSelric 	    krb5_set_error_message(context, ret, "asprintf: out of memory");
937ca1c9b0cSelric 	    goto out;
938ca1c9b0cSelric 	}
939ca1c9b0cSelric 
940ca1c9b0cSelric 	ret = LDAP_no_size_limit(context, HDB2LDAP(db));
941ca1c9b0cSelric 	if (ret)
942ca1c9b0cSelric 	    goto out;
943ca1c9b0cSelric 
944ca1c9b0cSelric 	rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE,
945ca1c9b0cSelric 			       filter, krb5kdcentry_attrs, 0,
946ca1c9b0cSelric 			       NULL, NULL, NULL,
947ca1c9b0cSelric 			       0, msg);
948ca1c9b0cSelric 	if (check_ldap(context, db, rc)) {
949ca1c9b0cSelric 	    ret = HDB_ERR_NOENTRY;
950ca1c9b0cSelric 	    krb5_set_error_message(context, ret,
951ca1c9b0cSelric 				   "ldap_search_ext_s: filter: %s error: %s",
952ca1c9b0cSelric 				   filter, ldap_err2string(rc));
953ca1c9b0cSelric 	    goto out;
954ca1c9b0cSelric 	}
955ca1c9b0cSelric     }
956ca1c9b0cSelric 
957ca1c9b0cSelric     ret = 0;
958ca1c9b0cSelric 
959ca1c9b0cSelric   out:
960ca1c9b0cSelric     if (filter)
961ca1c9b0cSelric 	free(filter);
962ca1c9b0cSelric 
963ca1c9b0cSelric     return ret;
964ca1c9b0cSelric }
965ca1c9b0cSelric 
966ca1c9b0cSelric static krb5_error_code
LDAP_principal2message(krb5_context context,HDB * db,krb5_const_principal princ,LDAPMessage ** msg)967ca1c9b0cSelric LDAP_principal2message(krb5_context context, HDB * db,
968ca1c9b0cSelric 		       krb5_const_principal princ, LDAPMessage ** msg)
969ca1c9b0cSelric {
970ca1c9b0cSelric     char *name, *name_short = NULL;
971ca1c9b0cSelric     krb5_error_code ret;
972ca1c9b0cSelric     krb5_realm *r, *r0;
973ca1c9b0cSelric 
974ca1c9b0cSelric     *msg = NULL;
975ca1c9b0cSelric 
976ca1c9b0cSelric     ret = krb5_unparse_name(context, princ, &name);
977ca1c9b0cSelric     if (ret)
978ca1c9b0cSelric 	return ret;
979ca1c9b0cSelric 
980ca1c9b0cSelric     ret = krb5_get_default_realms(context, &r0);
981ca1c9b0cSelric     if(ret) {
982ca1c9b0cSelric 	free(name);
983ca1c9b0cSelric 	return ret;
984ca1c9b0cSelric     }
985ca1c9b0cSelric     for (r = r0; *r != NULL; r++) {
986ca1c9b0cSelric 	if(strcmp(krb5_principal_get_realm(context, princ), *r) == 0) {
987ca1c9b0cSelric 	    ret = krb5_unparse_name_short(context, princ, &name_short);
988ca1c9b0cSelric 	    if (ret) {
989ca1c9b0cSelric 		krb5_free_host_realm(context, r0);
990ca1c9b0cSelric 		free(name);
991ca1c9b0cSelric 		return ret;
992ca1c9b0cSelric 	    }
993ca1c9b0cSelric 	    break;
994ca1c9b0cSelric 	}
995ca1c9b0cSelric     }
996ca1c9b0cSelric     krb5_free_host_realm(context, r0);
997ca1c9b0cSelric 
998ca1c9b0cSelric     ret = LDAP__lookup_princ(context, db, name, name_short, msg);
999ca1c9b0cSelric     free(name);
1000ca1c9b0cSelric     free(name_short);
1001ca1c9b0cSelric 
1002ca1c9b0cSelric     return ret;
1003ca1c9b0cSelric }
1004ca1c9b0cSelric 
1005ca1c9b0cSelric /*
1006ca1c9b0cSelric  * Construct an hdb_entry from a directory entry.
1007ca1c9b0cSelric  */
1008ca1c9b0cSelric static krb5_error_code
LDAP_message2entry(krb5_context context,HDB * db,LDAPMessage * msg,int flags,hdb_entry_ex * ent)1009ca1c9b0cSelric LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg,
1010ca1c9b0cSelric 		   int flags, hdb_entry_ex * ent)
1011ca1c9b0cSelric {
1012ca1c9b0cSelric     char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL;
1013ca1c9b0cSelric     char *samba_acct_flags = NULL;
1014ca1c9b0cSelric     struct berval **keys;
1015b9d004c6Schristos     struct berval **extensions;
1016ca1c9b0cSelric     struct berval **vals;
1017ca1c9b0cSelric     int tmp, tmp_time, i, ret, have_arcfour = 0;
1018ca1c9b0cSelric 
1019ca1c9b0cSelric     memset(ent, 0, sizeof(*ent));
1020ca1c9b0cSelric     ent->entry.flags = int2HDBFlags(0);
1021ca1c9b0cSelric 
1022ca1c9b0cSelric     ret = LDAP_get_string_value(db, msg, "krb5PrincipalName", &unparsed_name);
1023ca1c9b0cSelric     if (ret == 0) {
1024ca1c9b0cSelric 	ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal);
1025ca1c9b0cSelric 	if (ret)
1026ca1c9b0cSelric 	    goto out;
1027ca1c9b0cSelric     } else {
1028ca1c9b0cSelric 	ret = LDAP_get_string_value(db, msg, "uid",
1029ca1c9b0cSelric 				    &unparsed_name);
1030ca1c9b0cSelric 	if (ret == 0) {
1031ca1c9b0cSelric 	    ret = krb5_parse_name(context, unparsed_name, &ent->entry.principal);
1032ca1c9b0cSelric 	    if (ret)
1033ca1c9b0cSelric 		goto out;
1034ca1c9b0cSelric 	} else {
1035ca1c9b0cSelric 	    krb5_set_error_message(context, HDB_ERR_NOENTRY,
1036ca1c9b0cSelric 				   "hdb-ldap: ldap entry missing"
1037ca1c9b0cSelric 				  "principal name");
1038ca1c9b0cSelric 	    return HDB_ERR_NOENTRY;
1039ca1c9b0cSelric 	}
1040ca1c9b0cSelric     }
1041ca1c9b0cSelric 
1042ca1c9b0cSelric     {
1043ca1c9b0cSelric 	int integer;
1044ca1c9b0cSelric 	ret = LDAP_get_integer_value(db, msg, "krb5KeyVersionNumber",
1045ca1c9b0cSelric 				     &integer);
1046ca1c9b0cSelric 	if (ret)
1047ca1c9b0cSelric 	    ent->entry.kvno = 0;
1048ca1c9b0cSelric 	else
1049ca1c9b0cSelric 	    ent->entry.kvno = integer;
1050ca1c9b0cSelric     }
1051ca1c9b0cSelric 
1052ca1c9b0cSelric     keys = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key");
1053ca1c9b0cSelric     if (keys != NULL) {
1054ca1c9b0cSelric 	size_t l;
1055ca1c9b0cSelric 
1056ca1c9b0cSelric 	ent->entry.keys.len = ldap_count_values_len(keys);
1057ca1c9b0cSelric 	ent->entry.keys.val = (Key *) calloc(ent->entry.keys.len, sizeof(Key));
1058ca1c9b0cSelric 	if (ent->entry.keys.val == NULL) {
1059ca1c9b0cSelric 	    ret = ENOMEM;
1060ca1c9b0cSelric 	    krb5_set_error_message(context, ret, "calloc: out of memory");
1061ca1c9b0cSelric 	    goto out;
1062ca1c9b0cSelric 	}
1063ca1c9b0cSelric 	for (i = 0; i < ent->entry.keys.len; i++) {
1064ca1c9b0cSelric 	    decode_Key((unsigned char *) keys[i]->bv_val,
1065ca1c9b0cSelric 		       (size_t) keys[i]->bv_len, &ent->entry.keys.val[i], &l);
1066ca1c9b0cSelric 	}
1067ca1c9b0cSelric 	ber_bvecfree(keys);
1068ca1c9b0cSelric     } else {
1069ca1c9b0cSelric #if 1
1070ca1c9b0cSelric 	/*
1071ca1c9b0cSelric 	 * This violates the ASN1 but it allows a principal to
1072ca1c9b0cSelric 	 * be related to a general directory entry without creating
1073ca1c9b0cSelric 	 * the keys. Hopefully it's OK.
1074ca1c9b0cSelric 	 */
1075ca1c9b0cSelric 	ent->entry.keys.len = 0;
1076ca1c9b0cSelric 	ent->entry.keys.val = NULL;
1077ca1c9b0cSelric #else
1078ca1c9b0cSelric 	ret = HDB_ERR_NOENTRY;
1079ca1c9b0cSelric 	goto out;
1080ca1c9b0cSelric #endif
1081ca1c9b0cSelric     }
1082ca1c9b0cSelric 
1083b9d004c6Schristos     extensions = ldap_get_values_len(HDB2LDAP(db), msg, "krb5ExtendedAttributes");
1084b9d004c6Schristos     if (extensions != NULL) {
1085b9d004c6Schristos 	size_t l;
1086b9d004c6Schristos 
1087b9d004c6Schristos 	ent->entry.extensions = calloc(1, sizeof(*(ent->entry.extensions)));
1088b9d004c6Schristos 	if (ent->entry.extensions == NULL) {
1089b9d004c6Schristos 	    ret = krb5_enomem(context);
1090b9d004c6Schristos 	    goto out;
1091b9d004c6Schristos 	}
1092b9d004c6Schristos 	ent->entry.extensions->len = ldap_count_values_len(extensions);
1093b9d004c6Schristos 	ent->entry.extensions->val = (HDB_extension *) calloc(ent->entry.extensions->len, sizeof(HDB_extension));
1094b9d004c6Schristos 	if (ent->entry.extensions->val == NULL) {
1095b9d004c6Schristos 	    ent->entry.extensions->len = 0;
1096b9d004c6Schristos 	    ret = krb5_enomem(context);
1097b9d004c6Schristos 	    goto out;
1098b9d004c6Schristos 	}
1099b9d004c6Schristos 	for (i = 0; i < ent->entry.extensions->len; i++) {
1100b9d004c6Schristos 	    ret = decode_HDB_extension((unsigned char *) extensions[i]->bv_val,
1101b9d004c6Schristos 		       (size_t) extensions[i]->bv_len, &ent->entry.extensions->val[i], &l);
1102b9d004c6Schristos 	    if (ret)
1103b9d004c6Schristos 		krb5_set_error_message(context, ret, "decode_HDB_extension failed");
1104b9d004c6Schristos 	}
1105b9d004c6Schristos 	ber_bvecfree(extensions);
1106b9d004c6Schristos     } else {
1107b9d004c6Schristos 	ent->entry.extensions = NULL;
1108b9d004c6Schristos     }
1109b9d004c6Schristos 
1110ca1c9b0cSelric     vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType");
1111ca1c9b0cSelric     if (vals != NULL) {
1112ca1c9b0cSelric 	ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes)));
1113ca1c9b0cSelric 	if (ent->entry.etypes == NULL) {
1114ca1c9b0cSelric 	    ret = ENOMEM;
1115ca1c9b0cSelric 	    krb5_set_error_message(context, ret,"malloc: out of memory");
1116ca1c9b0cSelric 	    goto out;
1117ca1c9b0cSelric 	}
1118ca1c9b0cSelric 	ent->entry.etypes->len = ldap_count_values_len(vals);
1119b9d004c6Schristos 	ent->entry.etypes->val = calloc(ent->entry.etypes->len,
1120b9d004c6Schristos                                         sizeof(ent->entry.etypes->val[0]));
1121ca1c9b0cSelric 	if (ent->entry.etypes->val == NULL) {
1122ca1c9b0cSelric 	    ret = ENOMEM;
1123ca1c9b0cSelric 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1124ca1c9b0cSelric 	    ent->entry.etypes->len = 0;
1125ca1c9b0cSelric 	    goto out;
1126ca1c9b0cSelric 	}
1127ca1c9b0cSelric 	for (i = 0; i < ent->entry.etypes->len; i++) {
1128ca1c9b0cSelric 	    char *buf;
1129ca1c9b0cSelric 
1130ca1c9b0cSelric 	    buf = malloc(vals[i]->bv_len + 1);
1131ca1c9b0cSelric 	    if (buf == NULL) {
1132ca1c9b0cSelric 		ret = ENOMEM;
1133ca1c9b0cSelric 		krb5_set_error_message(context, ret, "malloc: out of memory");
1134ca1c9b0cSelric 		goto out;
1135ca1c9b0cSelric 	    }
1136ca1c9b0cSelric 	    memcpy(buf, vals[i]->bv_val, vals[i]->bv_len);
1137ca1c9b0cSelric 	    buf[vals[i]->bv_len] = '\0';
1138ca1c9b0cSelric 	    ent->entry.etypes->val[i] = atoi(buf);
1139ca1c9b0cSelric 	    free(buf);
1140ca1c9b0cSelric 	}
1141ca1c9b0cSelric 	ldap_value_free_len(vals);
1142ca1c9b0cSelric     }
1143ca1c9b0cSelric 
1144ca1c9b0cSelric     for (i = 0; i < ent->entry.keys.len; i++) {
1145ca1c9b0cSelric 	if (ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
1146ca1c9b0cSelric 	    have_arcfour = 1;
1147ca1c9b0cSelric 	    break;
1148ca1c9b0cSelric 	}
1149ca1c9b0cSelric     }
1150ca1c9b0cSelric 
1151ca1c9b0cSelric     /* manually construct the NT (type 23) key */
1152ca1c9b0cSelric     ret = LDAP_get_string_value(db, msg, "sambaNTPassword", &ntPasswordIN);
1153ca1c9b0cSelric     if (ret == 0 && have_arcfour == 0) {
1154ca1c9b0cSelric 	unsigned *etypes;
1155b9d004c6Schristos         Key *ks;
1156ca1c9b0cSelric 
1157b9d004c6Schristos 	ks = realloc(ent->entry.keys.val,
1158b9d004c6Schristos 		     (ent->entry.keys.len + 1) *
1159b9d004c6Schristos                      sizeof(ent->entry.keys.val[0]));
1160b9d004c6Schristos 	if (ks == NULL) {
1161ca1c9b0cSelric 	    ret = ENOMEM;
1162ca1c9b0cSelric 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1163ca1c9b0cSelric 	    goto out;
1164ca1c9b0cSelric 	}
1165b9d004c6Schristos 	ent->entry.keys.val = ks;
1166ca1c9b0cSelric 	memset(&ent->entry.keys.val[ent->entry.keys.len], 0, sizeof(Key));
1167ca1c9b0cSelric 	ent->entry.keys.val[ent->entry.keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5;
1168ca1c9b0cSelric 	ret = krb5_data_alloc (&ent->entry.keys.val[ent->entry.keys.len].key.keyvalue, 16);
1169ca1c9b0cSelric 	if (ret) {
1170ca1c9b0cSelric 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1171ca1c9b0cSelric 	    ret = ENOMEM;
1172ca1c9b0cSelric 	    goto out;
1173ca1c9b0cSelric 	}
1174ca1c9b0cSelric 	ret = hex_decode(ntPasswordIN,
1175ca1c9b0cSelric 			 ent->entry.keys.val[ent->entry.keys.len].key.keyvalue.data, 16);
1176ca1c9b0cSelric 	ent->entry.keys.len++;
1177ca1c9b0cSelric 
1178ca1c9b0cSelric 	if (ent->entry.etypes == NULL) {
1179ca1c9b0cSelric 	    ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes)));
1180ca1c9b0cSelric 	    if (ent->entry.etypes == NULL) {
1181ca1c9b0cSelric 		ret = ENOMEM;
1182ca1c9b0cSelric 		krb5_set_error_message(context, ret, "malloc: out of memory");
1183ca1c9b0cSelric 		goto out;
1184ca1c9b0cSelric 	    }
1185ca1c9b0cSelric 	    ent->entry.etypes->val = NULL;
1186ca1c9b0cSelric 	    ent->entry.etypes->len = 0;
1187ca1c9b0cSelric 	}
1188ca1c9b0cSelric 
1189ca1c9b0cSelric 	for (i = 0; i < ent->entry.etypes->len; i++)
1190ca1c9b0cSelric 	    if (ent->entry.etypes->val[i] == ETYPE_ARCFOUR_HMAC_MD5)
1191ca1c9b0cSelric 		break;
1192ca1c9b0cSelric 	/* If there is no ARCFOUR enctype, add one */
1193ca1c9b0cSelric 	if (i == ent->entry.etypes->len) {
1194ca1c9b0cSelric 	    etypes = realloc(ent->entry.etypes->val,
1195ca1c9b0cSelric 			     (ent->entry.etypes->len + 1) *
1196ca1c9b0cSelric 			     sizeof(ent->entry.etypes->val[0]));
1197ca1c9b0cSelric 	    if (etypes == NULL) {
1198ca1c9b0cSelric 		ret = ENOMEM;
1199ca1c9b0cSelric 		krb5_set_error_message(context, ret, "malloc: out of memory");
1200ca1c9b0cSelric 		goto out;
1201ca1c9b0cSelric 	    }
1202ca1c9b0cSelric 	    ent->entry.etypes->val = etypes;
1203ca1c9b0cSelric 	    ent->entry.etypes->val[ent->entry.etypes->len] =
1204ca1c9b0cSelric 		ETYPE_ARCFOUR_HMAC_MD5;
1205ca1c9b0cSelric 	    ent->entry.etypes->len++;
1206ca1c9b0cSelric 	}
1207ca1c9b0cSelric     }
1208ca1c9b0cSelric 
1209ca1c9b0cSelric     ret = LDAP_get_generalized_time_value(db, msg, "createTimestamp",
1210ca1c9b0cSelric 					  &ent->entry.created_by.time);
1211ca1c9b0cSelric     if (ret)
1212ca1c9b0cSelric 	ent->entry.created_by.time = time(NULL);
1213ca1c9b0cSelric 
1214ca1c9b0cSelric     ent->entry.created_by.principal = NULL;
1215ca1c9b0cSelric 
1216ca1c9b0cSelric     if (flags & HDB_F_ADMIN_DATA) {
1217ca1c9b0cSelric 	ret = LDAP_get_string_value(db, msg, "creatorsName", &dn);
1218ca1c9b0cSelric 	if (ret == 0) {
1219ca1c9b0cSelric 	    LDAP_dn2principal(context, db, dn, &ent->entry.created_by.principal);
1220ca1c9b0cSelric 	    free(dn);
1221ca1c9b0cSelric 	}
1222ca1c9b0cSelric 
1223ca1c9b0cSelric 	ent->entry.modified_by = calloc(1, sizeof(*ent->entry.modified_by));
1224ca1c9b0cSelric 	if (ent->entry.modified_by == NULL) {
1225ca1c9b0cSelric 	    ret = ENOMEM;
1226ca1c9b0cSelric 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1227ca1c9b0cSelric 	    goto out;
1228ca1c9b0cSelric 	}
1229ca1c9b0cSelric 
1230ca1c9b0cSelric 	ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp",
1231ca1c9b0cSelric 					      &ent->entry.modified_by->time);
1232ca1c9b0cSelric 	if (ret == 0) {
1233ca1c9b0cSelric 	    ret = LDAP_get_string_value(db, msg, "modifiersName", &dn);
1234ca1c9b0cSelric 	    if (ret == 0) {
1235ca1c9b0cSelric 		LDAP_dn2principal(context, db, dn, &ent->entry.modified_by->principal);
1236ca1c9b0cSelric 		free(dn);
1237ca1c9b0cSelric 	    } else {
1238ca1c9b0cSelric 		free(ent->entry.modified_by);
1239ca1c9b0cSelric 		ent->entry.modified_by = NULL;
1240ca1c9b0cSelric 	    }
1241ca1c9b0cSelric 	}
1242ca1c9b0cSelric     }
1243ca1c9b0cSelric 
1244ca1c9b0cSelric     ent->entry.valid_start = malloc(sizeof(*ent->entry.valid_start));
1245ca1c9b0cSelric     if (ent->entry.valid_start == NULL) {
1246ca1c9b0cSelric 	ret = ENOMEM;
1247ca1c9b0cSelric 	krb5_set_error_message(context, ret, "malloc: out of memory");
1248ca1c9b0cSelric 	goto out;
1249ca1c9b0cSelric     }
1250ca1c9b0cSelric     ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart",
1251ca1c9b0cSelric 					  ent->entry.valid_start);
1252ca1c9b0cSelric     if (ret) {
1253ca1c9b0cSelric 	/* OPTIONAL */
1254ca1c9b0cSelric 	free(ent->entry.valid_start);
1255ca1c9b0cSelric 	ent->entry.valid_start = NULL;
1256ca1c9b0cSelric     }
1257ca1c9b0cSelric 
1258ca1c9b0cSelric     ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end));
1259ca1c9b0cSelric     if (ent->entry.valid_end == NULL) {
1260ca1c9b0cSelric 	ret = ENOMEM;
1261ca1c9b0cSelric 	krb5_set_error_message(context, ret, "malloc: out of memory");
1262ca1c9b0cSelric 	goto out;
1263ca1c9b0cSelric     }
1264ca1c9b0cSelric     ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd",
1265ca1c9b0cSelric 					  ent->entry.valid_end);
1266ca1c9b0cSelric     if (ret) {
1267ca1c9b0cSelric 	/* OPTIONAL */
1268ca1c9b0cSelric 	free(ent->entry.valid_end);
1269ca1c9b0cSelric 	ent->entry.valid_end = NULL;
1270ca1c9b0cSelric     }
1271ca1c9b0cSelric 
1272ca1c9b0cSelric     ret = LDAP_get_integer_value(db, msg, "sambaKickoffTime", &tmp_time);
1273ca1c9b0cSelric     if (ret == 0) {
1274ca1c9b0cSelric  	if (ent->entry.valid_end == NULL) {
1275ca1c9b0cSelric  	    ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end));
1276ca1c9b0cSelric  	    if (ent->entry.valid_end == NULL) {
1277ca1c9b0cSelric  		ret = ENOMEM;
1278ca1c9b0cSelric  		krb5_set_error_message(context, ret, "malloc: out of memory");
1279ca1c9b0cSelric  		goto out;
1280ca1c9b0cSelric  	    }
1281ca1c9b0cSelric  	}
1282ca1c9b0cSelric  	*ent->entry.valid_end = tmp_time;
1283ca1c9b0cSelric     }
1284ca1c9b0cSelric 
1285ca1c9b0cSelric     ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
1286ca1c9b0cSelric     if (ent->entry.pw_end == NULL) {
1287ca1c9b0cSelric 	ret = ENOMEM;
1288ca1c9b0cSelric 	krb5_set_error_message(context, ret, "malloc: out of memory");
1289ca1c9b0cSelric 	goto out;
1290ca1c9b0cSelric     }
1291ca1c9b0cSelric     ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd",
1292ca1c9b0cSelric 					  ent->entry.pw_end);
1293ca1c9b0cSelric     if (ret) {
1294ca1c9b0cSelric 	/* OPTIONAL */
1295ca1c9b0cSelric 	free(ent->entry.pw_end);
1296ca1c9b0cSelric 	ent->entry.pw_end = NULL;
1297ca1c9b0cSelric     }
1298ca1c9b0cSelric 
1299ca1c9b0cSelric     ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time);
1300ca1c9b0cSelric     if (ret == 0) {
1301ca1c9b0cSelric 	time_t delta;
1302ca1c9b0cSelric 
1303b9d004c6Schristos 	delta = krb5_config_get_time_default(context, NULL,
1304b9d004c6Schristos 					     0,
1305b9d004c6Schristos 					     "kadmin",
1306b9d004c6Schristos 					     "password_lifetime",
1307b9d004c6Schristos 					     NULL);
1308b9d004c6Schristos 
1309b9d004c6Schristos 	if (delta) {
1310ca1c9b0cSelric 		if (ent->entry.pw_end == NULL) {
1311ca1c9b0cSelric 		    ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
1312ca1c9b0cSelric 		    if (ent->entry.pw_end == NULL) {
1313ca1c9b0cSelric 			ret = ENOMEM;
1314ca1c9b0cSelric 			krb5_set_error_message(context, ret, "malloc: out of memory");
1315ca1c9b0cSelric 			goto out;
1316ca1c9b0cSelric 		    }
1317ca1c9b0cSelric 		}
1318ca1c9b0cSelric 
1319ca1c9b0cSelric 		*ent->entry.pw_end = tmp_time + delta;
1320ca1c9b0cSelric 	}
1321b9d004c6Schristos     }
1322ca1c9b0cSelric 
1323ca1c9b0cSelric     ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time);
1324ca1c9b0cSelric     if (ret == 0) {
1325ca1c9b0cSelric 	if (ent->entry.pw_end == NULL) {
1326ca1c9b0cSelric 	    ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end));
1327ca1c9b0cSelric 	    if (ent->entry.pw_end == NULL) {
1328ca1c9b0cSelric 		ret = ENOMEM;
1329ca1c9b0cSelric 		krb5_set_error_message(context, ret, "malloc: out of memory");
1330ca1c9b0cSelric 		goto out;
1331ca1c9b0cSelric 	    }
1332ca1c9b0cSelric 	}
1333ca1c9b0cSelric 	*ent->entry.pw_end = tmp_time;
1334ca1c9b0cSelric     }
1335ca1c9b0cSelric 
1336ca1c9b0cSelric     /* OPTIONAL */
1337ca1c9b0cSelric     ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time);
1338ca1c9b0cSelric     if (ret == 0)
1339ca1c9b0cSelric 	hdb_entry_set_pw_change_time(context, &ent->entry, tmp_time);
1340ca1c9b0cSelric 
1341ca1c9b0cSelric     {
1342ca1c9b0cSelric 	int max_life;
1343ca1c9b0cSelric 
1344ca1c9b0cSelric 	ent->entry.max_life = malloc(sizeof(*ent->entry.max_life));
1345ca1c9b0cSelric 	if (ent->entry.max_life == NULL) {
1346ca1c9b0cSelric 	    ret = ENOMEM;
1347ca1c9b0cSelric 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1348ca1c9b0cSelric 	    goto out;
1349ca1c9b0cSelric 	}
1350ca1c9b0cSelric 	ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", &max_life);
1351ca1c9b0cSelric 	if (ret) {
1352ca1c9b0cSelric 	    free(ent->entry.max_life);
1353ca1c9b0cSelric 	    ent->entry.max_life = NULL;
1354ca1c9b0cSelric 	} else
1355ca1c9b0cSelric 	    *ent->entry.max_life = max_life;
1356ca1c9b0cSelric     }
1357ca1c9b0cSelric 
1358ca1c9b0cSelric     {
1359ca1c9b0cSelric 	int max_renew;
1360ca1c9b0cSelric 
1361ca1c9b0cSelric 	ent->entry.max_renew = malloc(sizeof(*ent->entry.max_renew));
1362ca1c9b0cSelric 	if (ent->entry.max_renew == NULL) {
1363ca1c9b0cSelric 	    ret = ENOMEM;
1364ca1c9b0cSelric 	    krb5_set_error_message(context, ret, "malloc: out of memory");
1365ca1c9b0cSelric 	    goto out;
1366ca1c9b0cSelric 	}
1367ca1c9b0cSelric 	ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", &max_renew);
1368ca1c9b0cSelric 	if (ret) {
1369ca1c9b0cSelric 	    free(ent->entry.max_renew);
1370ca1c9b0cSelric 	    ent->entry.max_renew = NULL;
1371ca1c9b0cSelric 	} else
1372ca1c9b0cSelric 	    *ent->entry.max_renew = max_renew;
1373ca1c9b0cSelric     }
1374ca1c9b0cSelric 
1375ca1c9b0cSelric     ret = LDAP_get_integer_value(db, msg, "krb5KDCFlags", &tmp);
1376ca1c9b0cSelric     if (ret)
1377ca1c9b0cSelric 	tmp = 0;
1378ca1c9b0cSelric 
1379ca1c9b0cSelric     ent->entry.flags = int2HDBFlags(tmp);
1380ca1c9b0cSelric 
1381ca1c9b0cSelric     /* Try and find Samba flags to put into the mix */
1382ca1c9b0cSelric     ret = LDAP_get_string_value(db, msg, "sambaAcctFlags", &samba_acct_flags);
1383ca1c9b0cSelric     if (ret == 0) {
1384ca1c9b0cSelric 	/* parse the [UXW...] string:
1385ca1c9b0cSelric 
1386ca1c9b0cSelric 	   'N'    No password
1387ca1c9b0cSelric 	   'D'    Disabled
1388ca1c9b0cSelric 	   'H'    Homedir required
1389ca1c9b0cSelric 	   'T'    Temp account.
1390ca1c9b0cSelric 	   'U'    User account (normal)
1391ca1c9b0cSelric 	   'M'    MNS logon user account - what is this ?
1392ca1c9b0cSelric 	   'W'    Workstation account
1393ca1c9b0cSelric 	   'S'    Server account
1394ca1c9b0cSelric 	   'L'    Locked account
1395ca1c9b0cSelric 	   'X'    No Xpiry on password
1396ca1c9b0cSelric 	   'I'    Interdomain trust account
1397ca1c9b0cSelric 
1398ca1c9b0cSelric 	*/
1399ca1c9b0cSelric 
1400ca1c9b0cSelric 	int flags_len = strlen(samba_acct_flags);
1401ca1c9b0cSelric 
1402ca1c9b0cSelric 	if (flags_len < 2)
1403ca1c9b0cSelric 	    goto out2;
1404ca1c9b0cSelric 
1405ca1c9b0cSelric 	if (samba_acct_flags[0] != '['
1406ca1c9b0cSelric 	    || samba_acct_flags[flags_len - 1] != ']')
1407ca1c9b0cSelric 	    goto out2;
1408ca1c9b0cSelric 
1409ca1c9b0cSelric 	/* Allow forwarding */
1410ca1c9b0cSelric 	if (samba_forwardable)
1411ca1c9b0cSelric 	    ent->entry.flags.forwardable = TRUE;
1412ca1c9b0cSelric 
1413ca1c9b0cSelric 	for (i=0; i < flags_len; i++) {
1414ca1c9b0cSelric 	    switch (samba_acct_flags[i]) {
1415ca1c9b0cSelric 	    case ' ':
1416ca1c9b0cSelric 	    case '[':
1417ca1c9b0cSelric 	    case ']':
1418ca1c9b0cSelric 		break;
1419ca1c9b0cSelric 	    case 'N':
1420ca1c9b0cSelric 		/* how to handle no password in kerberos? */
1421ca1c9b0cSelric 		break;
1422ca1c9b0cSelric 	    case 'D':
1423ca1c9b0cSelric 		ent->entry.flags.invalid = TRUE;
1424ca1c9b0cSelric 		break;
1425ca1c9b0cSelric 	    case 'H':
1426ca1c9b0cSelric 		break;
1427ca1c9b0cSelric 	    case 'T':
1428ca1c9b0cSelric 		/* temp duplicate */
1429ca1c9b0cSelric 		ent->entry.flags.invalid = TRUE;
1430ca1c9b0cSelric 		break;
1431ca1c9b0cSelric 	    case 'U':
1432ca1c9b0cSelric 		ent->entry.flags.client = TRUE;
1433ca1c9b0cSelric 		break;
1434ca1c9b0cSelric 	    case 'M':
1435ca1c9b0cSelric 		break;
1436ca1c9b0cSelric 	    case 'W':
1437ca1c9b0cSelric 	    case 'S':
1438ca1c9b0cSelric 		ent->entry.flags.server = TRUE;
1439ca1c9b0cSelric 		ent->entry.flags.client = TRUE;
1440ca1c9b0cSelric 		break;
1441ca1c9b0cSelric 	    case 'L':
1442ca1c9b0cSelric 		ent->entry.flags.invalid = TRUE;
1443ca1c9b0cSelric 		break;
1444ca1c9b0cSelric 	    case 'X':
1445ca1c9b0cSelric 		if (ent->entry.pw_end) {
1446ca1c9b0cSelric 		    free(ent->entry.pw_end);
1447ca1c9b0cSelric 		    ent->entry.pw_end = NULL;
1448ca1c9b0cSelric 		}
1449ca1c9b0cSelric 		break;
1450ca1c9b0cSelric 	    case 'I':
1451ca1c9b0cSelric 		ent->entry.flags.server = TRUE;
1452ca1c9b0cSelric 		ent->entry.flags.client = TRUE;
1453ca1c9b0cSelric 		break;
1454ca1c9b0cSelric 	    }
1455ca1c9b0cSelric 	}
1456ca1c9b0cSelric     out2:
1457ca1c9b0cSelric 	free(samba_acct_flags);
1458ca1c9b0cSelric     }
1459ca1c9b0cSelric 
1460ca1c9b0cSelric     ret = 0;
1461ca1c9b0cSelric 
1462ca1c9b0cSelric out:
1463ca1c9b0cSelric     free(unparsed_name);
1464b9d004c6Schristos     free(ntPasswordIN);
1465ca1c9b0cSelric 
1466ca1c9b0cSelric     if (ret)
1467ca1c9b0cSelric 	hdb_free_entry(context, ent);
1468ca1c9b0cSelric 
1469ca1c9b0cSelric     return ret;
1470ca1c9b0cSelric }
1471ca1c9b0cSelric 
1472ca1c9b0cSelric static krb5_error_code
LDAP_close(krb5_context context,HDB * db)1473ca1c9b0cSelric LDAP_close(krb5_context context, HDB * db)
1474ca1c9b0cSelric {
1475ca1c9b0cSelric     if (HDB2LDAP(db)) {
1476ca1c9b0cSelric 	ldap_unbind_ext(HDB2LDAP(db), NULL, NULL);
1477ca1c9b0cSelric 	((struct hdbldapdb *)db->hdb_db)->h_lp = NULL;
1478ca1c9b0cSelric     }
1479ca1c9b0cSelric 
1480ca1c9b0cSelric     return 0;
1481ca1c9b0cSelric }
1482ca1c9b0cSelric 
1483ca1c9b0cSelric static krb5_error_code
LDAP_lock(krb5_context context,HDB * db,int operation)1484ca1c9b0cSelric LDAP_lock(krb5_context context, HDB * db, int operation)
1485ca1c9b0cSelric {
1486ca1c9b0cSelric     return 0;
1487ca1c9b0cSelric }
1488ca1c9b0cSelric 
1489ca1c9b0cSelric static krb5_error_code
LDAP_unlock(krb5_context context,HDB * db)1490ca1c9b0cSelric LDAP_unlock(krb5_context context, HDB * db)
1491ca1c9b0cSelric {
1492ca1c9b0cSelric     return 0;
1493ca1c9b0cSelric }
1494ca1c9b0cSelric 
1495ca1c9b0cSelric static krb5_error_code
LDAP_seq(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)1496ca1c9b0cSelric LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry)
1497ca1c9b0cSelric {
1498ca1c9b0cSelric     int msgid, rc, parserc;
1499ca1c9b0cSelric     krb5_error_code ret;
1500ca1c9b0cSelric     LDAPMessage *e;
1501ca1c9b0cSelric 
1502ca1c9b0cSelric     msgid = HDB2MSGID(db);
1503ca1c9b0cSelric     if (msgid < 0)
1504ca1c9b0cSelric 	return HDB_ERR_NOENTRY;
1505ca1c9b0cSelric 
1506ca1c9b0cSelric     do {
1507ca1c9b0cSelric 	rc = ldap_result(HDB2LDAP(db), msgid, LDAP_MSG_ONE, NULL, &e);
1508ca1c9b0cSelric 	switch (rc) {
1509ca1c9b0cSelric 	case LDAP_RES_SEARCH_REFERENCE:
1510ca1c9b0cSelric 	    ldap_msgfree(e);
1511ca1c9b0cSelric 	    ret = 0;
1512ca1c9b0cSelric 	    break;
1513ca1c9b0cSelric 	case LDAP_RES_SEARCH_ENTRY:
1514ca1c9b0cSelric 	    /* We have an entry. Parse it. */
1515ca1c9b0cSelric 	    ret = LDAP_message2entry(context, db, e, flags, entry);
1516ca1c9b0cSelric 	    ldap_msgfree(e);
1517ca1c9b0cSelric 	    break;
1518ca1c9b0cSelric 	case LDAP_RES_SEARCH_RESULT:
1519ca1c9b0cSelric 	    /* We're probably at the end of the results. If not, abandon. */
1520ca1c9b0cSelric 	    parserc =
1521ca1c9b0cSelric 		ldap_parse_result(HDB2LDAP(db), e, NULL, NULL, NULL,
1522ca1c9b0cSelric 				  NULL, NULL, 1);
1523ca1c9b0cSelric 	    ret = HDB_ERR_NOENTRY;
1524ca1c9b0cSelric 	    if (parserc != LDAP_SUCCESS
1525ca1c9b0cSelric 		&& parserc != LDAP_MORE_RESULTS_TO_RETURN) {
1526ca1c9b0cSelric 	        krb5_set_error_message(context, ret, "ldap_parse_result: %s",
1527ca1c9b0cSelric 				       ldap_err2string(parserc));
1528ca1c9b0cSelric 		ldap_abandon_ext(HDB2LDAP(db), msgid, NULL, NULL);
1529ca1c9b0cSelric 	    }
1530ca1c9b0cSelric 	    HDBSETMSGID(db, -1);
1531ca1c9b0cSelric 	    break;
1532ca1c9b0cSelric 	case LDAP_SERVER_DOWN:
1533ca1c9b0cSelric 	    ldap_msgfree(e);
1534ca1c9b0cSelric 	    LDAP_close(context, db);
1535ca1c9b0cSelric 	    HDBSETMSGID(db, -1);
1536ca1c9b0cSelric 	    ret = ENETDOWN;
1537ca1c9b0cSelric 	    break;
1538ca1c9b0cSelric 	default:
1539ca1c9b0cSelric 	    /* Some unspecified error (timeout?). Abandon. */
1540ca1c9b0cSelric 	    ldap_msgfree(e);
1541ca1c9b0cSelric 	    ldap_abandon_ext(HDB2LDAP(db), msgid, NULL, NULL);
1542ca1c9b0cSelric 	    ret = HDB_ERR_NOENTRY;
1543ca1c9b0cSelric 	    HDBSETMSGID(db, -1);
1544ca1c9b0cSelric 	    break;
1545ca1c9b0cSelric 	}
1546ca1c9b0cSelric     } while (rc == LDAP_RES_SEARCH_REFERENCE);
1547ca1c9b0cSelric 
1548ca1c9b0cSelric     if (ret == 0) {
1549ca1c9b0cSelric 	if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
1550ca1c9b0cSelric 	    ret = hdb_unseal_keys(context, db, &entry->entry);
1551ca1c9b0cSelric 	    if (ret)
1552ca1c9b0cSelric 		hdb_free_entry(context, entry);
1553ca1c9b0cSelric 	}
1554ca1c9b0cSelric     }
1555ca1c9b0cSelric 
1556ca1c9b0cSelric     return ret;
1557ca1c9b0cSelric }
1558ca1c9b0cSelric 
1559ca1c9b0cSelric static krb5_error_code
LDAP_firstkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)1560ca1c9b0cSelric LDAP_firstkey(krb5_context context, HDB *db, unsigned flags,
1561ca1c9b0cSelric 	      hdb_entry_ex *entry)
1562ca1c9b0cSelric {
1563ca1c9b0cSelric     krb5_error_code ret;
1564ca1c9b0cSelric     int msgid;
1565ca1c9b0cSelric 
1566ca1c9b0cSelric     ret = LDAP__connect(context, db);
1567ca1c9b0cSelric     if (ret)
1568ca1c9b0cSelric 	return ret;
1569ca1c9b0cSelric 
1570ca1c9b0cSelric     ret = LDAP_no_size_limit(context, HDB2LDAP(db));
1571ca1c9b0cSelric     if (ret)
1572ca1c9b0cSelric 	return ret;
1573ca1c9b0cSelric 
1574ca1c9b0cSelric     ret = ldap_search_ext(HDB2LDAP(db), HDB2BASE(db),
1575ca1c9b0cSelric 			LDAP_SCOPE_SUBTREE,
1576ca1c9b0cSelric 			"(|(objectClass=krb5Principal)(objectClass=sambaSamAccount))",
1577ca1c9b0cSelric 			krb5kdcentry_attrs, 0,
1578ca1c9b0cSelric 			NULL, NULL, NULL, 0, &msgid);
1579b9d004c6Schristos     if (ret != LDAP_SUCCESS || msgid < 0)
1580ca1c9b0cSelric 	return HDB_ERR_NOENTRY;
1581ca1c9b0cSelric 
1582ca1c9b0cSelric     HDBSETMSGID(db, msgid);
1583ca1c9b0cSelric 
1584ca1c9b0cSelric     return LDAP_seq(context, db, flags, entry);
1585ca1c9b0cSelric }
1586ca1c9b0cSelric 
1587ca1c9b0cSelric static krb5_error_code
LDAP_nextkey(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)1588ca1c9b0cSelric LDAP_nextkey(krb5_context context, HDB * db, unsigned flags,
1589ca1c9b0cSelric 	     hdb_entry_ex * entry)
1590ca1c9b0cSelric {
1591ca1c9b0cSelric     return LDAP_seq(context, db, flags, entry);
1592ca1c9b0cSelric }
1593ca1c9b0cSelric 
1594ca1c9b0cSelric static krb5_error_code
LDAP__connect(krb5_context context,HDB * db)1595ca1c9b0cSelric LDAP__connect(krb5_context context, HDB * db)
1596ca1c9b0cSelric {
1597ca1c9b0cSelric     int rc, version = LDAP_VERSION3;
1598ca1c9b0cSelric     /*
1599ca1c9b0cSelric      * Empty credentials to do a SASL bind with LDAP. Note that empty
1600ca1c9b0cSelric      * different from NULL credentials. If you provide NULL
1601ca1c9b0cSelric      * credentials instead of empty credentials you will get a SASL
1602ca1c9b0cSelric      * bind in progress message.
1603ca1c9b0cSelric      */
1604ca1c9b0cSelric     struct berval bv = { 0, "" };
1605b9d004c6Schristos     const char *sasl_method = "EXTERNAL";
1606b9d004c6Schristos     const char *bind_dn = NULL;
1607b9d004c6Schristos 
1608b9d004c6Schristos     if (HDB2BINDDN(db) != NULL && HDB2BINDPW(db) != NULL) {
1609b9d004c6Schristos 	/* A bind DN was specified; use SASL SIMPLE */
1610b9d004c6Schristos 	bind_dn = HDB2BINDDN(db);
1611b9d004c6Schristos 	sasl_method = LDAP_SASL_SIMPLE;
1612b9d004c6Schristos 	bv.bv_val = HDB2BINDPW(db);
1613b9d004c6Schristos 	bv.bv_len = strlen(bv.bv_val);
1614b9d004c6Schristos     }
1615ca1c9b0cSelric 
1616ca1c9b0cSelric     if (HDB2LDAP(db)) {
1617ca1c9b0cSelric 	/* connection has been opened. ping server. */
1618ca1c9b0cSelric 	struct sockaddr_un addr;
1619ca1c9b0cSelric 	socklen_t len = sizeof(addr);
1620ca1c9b0cSelric 	int sd;
1621ca1c9b0cSelric 
1622ca1c9b0cSelric 	if (ldap_get_option(HDB2LDAP(db), LDAP_OPT_DESC, &sd) == 0 &&
1623ca1c9b0cSelric 	    getpeername(sd, (struct sockaddr *) &addr, &len) < 0) {
1624ca1c9b0cSelric 	    /* the other end has died. reopen. */
1625ca1c9b0cSelric 	    LDAP_close(context, db);
1626ca1c9b0cSelric 	}
1627ca1c9b0cSelric     }
1628ca1c9b0cSelric 
1629ca1c9b0cSelric     if (HDB2LDAP(db) != NULL) /* server is UP */
1630ca1c9b0cSelric 	return 0;
1631ca1c9b0cSelric 
1632ca1c9b0cSelric     rc = ldap_initialize(&((struct hdbldapdb *)db->hdb_db)->h_lp, HDB2URL(db));
1633ca1c9b0cSelric     if (rc != LDAP_SUCCESS) {
1634ca1c9b0cSelric 	krb5_set_error_message(context, HDB_ERR_NOENTRY, "ldap_initialize: %s",
1635ca1c9b0cSelric 			       ldap_err2string(rc));
1636ca1c9b0cSelric 	return HDB_ERR_NOENTRY;
1637ca1c9b0cSelric     }
1638ca1c9b0cSelric 
1639ca1c9b0cSelric     rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_PROTOCOL_VERSION,
1640ca1c9b0cSelric 			 (const void *)&version);
1641ca1c9b0cSelric     if (rc != LDAP_SUCCESS) {
1642ca1c9b0cSelric 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
1643ca1c9b0cSelric 			       "ldap_set_option: %s", ldap_err2string(rc));
1644ca1c9b0cSelric 	LDAP_close(context, db);
1645ca1c9b0cSelric 	return HDB_ERR_BADVERSION;
1646ca1c9b0cSelric     }
1647ca1c9b0cSelric 
1648b9d004c6Schristos     if (((struct hdbldapdb *)db->hdb_db)->h_start_tls) {
1649b9d004c6Schristos 	rc = ldap_start_tls_s(HDB2LDAP(db), NULL, NULL);
1650b9d004c6Schristos 
1651b9d004c6Schristos 	if (rc != LDAP_SUCCESS) {
1652b9d004c6Schristos 	    krb5_set_error_message(context, HDB_ERR_BADVERSION,
1653b9d004c6Schristos 				   "ldap_start_tls_s: %s", ldap_err2string(rc));
1654b9d004c6Schristos 	    LDAP_close(context, db);
1655b9d004c6Schristos 	    return HDB_ERR_BADVERSION;
1656b9d004c6Schristos 	}
1657b9d004c6Schristos     }
1658b9d004c6Schristos 
1659b9d004c6Schristos     rc = ldap_sasl_bind_s(HDB2LDAP(db), bind_dn, sasl_method, &bv,
1660ca1c9b0cSelric 			  NULL, NULL, NULL);
1661ca1c9b0cSelric     if (rc != LDAP_SUCCESS) {
1662ca1c9b0cSelric 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
1663ca1c9b0cSelric 			      "ldap_sasl_bind_s: %s", ldap_err2string(rc));
1664ca1c9b0cSelric 	LDAP_close(context, db);
1665ca1c9b0cSelric 	return HDB_ERR_BADVERSION;
1666ca1c9b0cSelric     }
1667ca1c9b0cSelric 
1668ca1c9b0cSelric     return 0;
1669ca1c9b0cSelric }
1670ca1c9b0cSelric 
1671ca1c9b0cSelric static krb5_error_code
LDAP_open(krb5_context context,HDB * db,int flags,mode_t mode)1672ca1c9b0cSelric LDAP_open(krb5_context context, HDB * db, int flags, mode_t mode)
1673ca1c9b0cSelric {
1674ca1c9b0cSelric     /* Not the right place for this. */
1675ca1c9b0cSelric #ifdef HAVE_SIGACTION
1676ca1c9b0cSelric     struct sigaction sa;
1677ca1c9b0cSelric 
1678ca1c9b0cSelric     sa.sa_flags = 0;
1679ca1c9b0cSelric     sa.sa_handler = SIG_IGN;
1680ca1c9b0cSelric     sigemptyset(&sa.sa_mask);
1681ca1c9b0cSelric 
1682ca1c9b0cSelric     sigaction(SIGPIPE, &sa, NULL);
1683ca1c9b0cSelric #else
1684ca1c9b0cSelric     signal(SIGPIPE, SIG_IGN);
1685ca1c9b0cSelric #endif /* HAVE_SIGACTION */
1686ca1c9b0cSelric 
1687ca1c9b0cSelric     return LDAP__connect(context, db);
1688ca1c9b0cSelric }
1689ca1c9b0cSelric 
1690ca1c9b0cSelric static krb5_error_code
LDAP_fetch_kvno(krb5_context context,HDB * db,krb5_const_principal principal,unsigned flags,krb5_kvno kvno,hdb_entry_ex * entry)1691ca1c9b0cSelric LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal,
1692ca1c9b0cSelric 		unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry)
1693ca1c9b0cSelric {
1694ca1c9b0cSelric     LDAPMessage *msg, *e;
1695ca1c9b0cSelric     krb5_error_code ret;
1696ca1c9b0cSelric 
1697ca1c9b0cSelric     ret = LDAP_principal2message(context, db, principal, &msg);
1698ca1c9b0cSelric     if (ret)
1699ca1c9b0cSelric 	return ret;
1700ca1c9b0cSelric 
1701ca1c9b0cSelric     e = ldap_first_entry(HDB2LDAP(db), msg);
1702ca1c9b0cSelric     if (e == NULL) {
1703ca1c9b0cSelric 	ret = HDB_ERR_NOENTRY;
1704ca1c9b0cSelric 	goto out;
1705ca1c9b0cSelric     }
1706ca1c9b0cSelric 
1707ca1c9b0cSelric     ret = LDAP_message2entry(context, db, e, flags, entry);
1708ca1c9b0cSelric     if (ret == 0) {
1709ca1c9b0cSelric 	if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) {
1710ca1c9b0cSelric 	    ret = hdb_unseal_keys(context, db, &entry->entry);
1711ca1c9b0cSelric 	    if (ret)
1712ca1c9b0cSelric 		hdb_free_entry(context, entry);
1713ca1c9b0cSelric 	}
1714ca1c9b0cSelric     }
1715ca1c9b0cSelric 
1716ca1c9b0cSelric   out:
1717ca1c9b0cSelric     ldap_msgfree(msg);
1718ca1c9b0cSelric 
1719ca1c9b0cSelric     return ret;
1720ca1c9b0cSelric }
1721ca1c9b0cSelric 
1722b9d004c6Schristos #if 0
1723ca1c9b0cSelric static krb5_error_code
1724ca1c9b0cSelric LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal,
1725ca1c9b0cSelric 	   unsigned flags, hdb_entry_ex * entry)
1726ca1c9b0cSelric {
1727ca1c9b0cSelric     return LDAP_fetch_kvno(context, db, principal,
1728ca1c9b0cSelric 			   flags & (~HDB_F_KVNO_SPECIFIED), 0, entry);
1729ca1c9b0cSelric }
1730b9d004c6Schristos #endif
1731ca1c9b0cSelric 
1732ca1c9b0cSelric static krb5_error_code
LDAP_store(krb5_context context,HDB * db,unsigned flags,hdb_entry_ex * entry)1733ca1c9b0cSelric LDAP_store(krb5_context context, HDB * db, unsigned flags,
1734ca1c9b0cSelric 	   hdb_entry_ex * entry)
1735ca1c9b0cSelric {
1736ca1c9b0cSelric     LDAPMod **mods = NULL;
1737ca1c9b0cSelric     krb5_error_code ret;
1738ca1c9b0cSelric     const char *errfn;
1739ca1c9b0cSelric     int rc;
1740ca1c9b0cSelric     LDAPMessage *msg = NULL, *e = NULL;
1741ca1c9b0cSelric     char *dn = NULL, *name = NULL;
1742ca1c9b0cSelric 
1743b9d004c6Schristos     if ((flags & HDB_F_PRECHECK))
1744b9d004c6Schristos         return 0; /* we can't guarantee whether we'll be able to perform it */
1745b9d004c6Schristos 
1746ca1c9b0cSelric     ret = LDAP_principal2message(context, db, entry->entry.principal, &msg);
1747ca1c9b0cSelric     if (ret == 0)
1748ca1c9b0cSelric 	e = ldap_first_entry(HDB2LDAP(db), msg);
1749ca1c9b0cSelric 
1750ca1c9b0cSelric     ret = krb5_unparse_name(context, entry->entry.principal, &name);
1751ca1c9b0cSelric     if (ret) {
1752ca1c9b0cSelric 	free(name);
1753ca1c9b0cSelric 	return ret;
1754ca1c9b0cSelric     }
1755ca1c9b0cSelric 
1756ca1c9b0cSelric     ret = hdb_seal_keys(context, db, &entry->entry);
1757ca1c9b0cSelric     if (ret)
1758ca1c9b0cSelric 	goto out;
1759ca1c9b0cSelric 
1760ca1c9b0cSelric     /* turn new entry into LDAPMod array */
1761ca1c9b0cSelric     ret = LDAP_entry2mods(context, db, entry, e, &mods);
1762ca1c9b0cSelric     if (ret)
1763ca1c9b0cSelric 	goto out;
1764ca1c9b0cSelric 
1765ca1c9b0cSelric     if (e == NULL) {
1766ca1c9b0cSelric 	ret = asprintf(&dn, "krb5PrincipalName=%s,%s", name, HDB2CREATE(db));
1767ca1c9b0cSelric 	if (ret < 0) {
1768ca1c9b0cSelric 	    ret = ENOMEM;
1769ca1c9b0cSelric 	    krb5_set_error_message(context, ret, "asprintf: out of memory");
1770ca1c9b0cSelric 	    goto out;
1771ca1c9b0cSelric 	}
1772ca1c9b0cSelric     } else if (flags & HDB_F_REPLACE) {
1773ca1c9b0cSelric 	/* Entry exists, and we're allowed to replace it. */
1774ca1c9b0cSelric 	dn = ldap_get_dn(HDB2LDAP(db), e);
1775ca1c9b0cSelric     } else {
1776ca1c9b0cSelric 	/* Entry exists, but we're not allowed to replace it. Bail. */
1777ca1c9b0cSelric 	ret = HDB_ERR_EXISTS;
1778ca1c9b0cSelric 	goto out;
1779ca1c9b0cSelric     }
1780ca1c9b0cSelric 
1781ca1c9b0cSelric     /* write entry into directory */
1782ca1c9b0cSelric     if (e == NULL) {
1783ca1c9b0cSelric 	/* didn't exist before */
1784ca1c9b0cSelric 	rc = ldap_add_ext_s(HDB2LDAP(db), dn, mods, NULL, NULL );
1785ca1c9b0cSelric 	errfn = "ldap_add_ext_s";
1786ca1c9b0cSelric     } else {
1787ca1c9b0cSelric 	/* already existed, send deltas only */
1788ca1c9b0cSelric 	rc = ldap_modify_ext_s(HDB2LDAP(db), dn, mods, NULL, NULL );
1789ca1c9b0cSelric 	errfn = "ldap_modify_ext_s";
1790ca1c9b0cSelric     }
1791ca1c9b0cSelric 
1792ca1c9b0cSelric     if (check_ldap(context, db, rc)) {
1793ca1c9b0cSelric 	char *ld_error = NULL;
1794ca1c9b0cSelric 	ldap_get_option(HDB2LDAP(db), LDAP_OPT_ERROR_STRING,
1795ca1c9b0cSelric 			&ld_error);
1796ca1c9b0cSelric 	ret = HDB_ERR_CANT_LOCK_DB;
1797ca1c9b0cSelric 	krb5_set_error_message(context, ret, "%s: %s (DN=%s) %s: %s",
1798ca1c9b0cSelric 			      errfn, name, dn, ldap_err2string(rc), ld_error);
1799ca1c9b0cSelric     } else
1800ca1c9b0cSelric 	ret = 0;
1801ca1c9b0cSelric 
1802ca1c9b0cSelric   out:
1803ca1c9b0cSelric     /* free stuff */
1804ca1c9b0cSelric     if (dn)
1805ca1c9b0cSelric 	free(dn);
1806ca1c9b0cSelric     if (msg)
1807ca1c9b0cSelric 	ldap_msgfree(msg);
1808ca1c9b0cSelric     if (mods)
1809ca1c9b0cSelric 	ldap_mods_free(mods, 1);
1810ca1c9b0cSelric     if (name)
1811ca1c9b0cSelric 	free(name);
1812ca1c9b0cSelric 
1813ca1c9b0cSelric     return ret;
1814ca1c9b0cSelric }
1815ca1c9b0cSelric 
1816ca1c9b0cSelric static krb5_error_code
LDAP_remove(krb5_context context,HDB * db,unsigned flags,krb5_const_principal principal)1817b9d004c6Schristos LDAP_remove(krb5_context context, HDB *db,
1818b9d004c6Schristos             unsigned flags, krb5_const_principal principal)
1819ca1c9b0cSelric {
1820ca1c9b0cSelric     krb5_error_code ret;
1821ca1c9b0cSelric     LDAPMessage *msg, *e;
1822ca1c9b0cSelric     char *dn = NULL;
1823ca1c9b0cSelric     int rc, limit = LDAP_NO_LIMIT;
1824ca1c9b0cSelric 
1825b9d004c6Schristos     if ((flags & HDB_F_PRECHECK))
1826b9d004c6Schristos         return 0; /* we can't guarantee whether we'll be able to perform it */
1827b9d004c6Schristos 
1828ca1c9b0cSelric     ret = LDAP_principal2message(context, db, principal, &msg);
1829ca1c9b0cSelric     if (ret)
1830ca1c9b0cSelric 	goto out;
1831ca1c9b0cSelric 
1832ca1c9b0cSelric     e = ldap_first_entry(HDB2LDAP(db), msg);
1833ca1c9b0cSelric     if (e == NULL) {
1834ca1c9b0cSelric 	ret = HDB_ERR_NOENTRY;
1835ca1c9b0cSelric 	goto out;
1836ca1c9b0cSelric     }
1837ca1c9b0cSelric 
1838ca1c9b0cSelric     dn = ldap_get_dn(HDB2LDAP(db), e);
1839ca1c9b0cSelric     if (dn == NULL) {
1840ca1c9b0cSelric 	ret = HDB_ERR_NOENTRY;
1841ca1c9b0cSelric 	goto out;
1842ca1c9b0cSelric     }
1843ca1c9b0cSelric 
1844ca1c9b0cSelric     rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_SIZELIMIT, (const void *)&limit);
1845ca1c9b0cSelric     if (rc != LDAP_SUCCESS) {
1846ca1c9b0cSelric 	ret = HDB_ERR_BADVERSION;
1847ca1c9b0cSelric 	krb5_set_error_message(context, ret, "ldap_set_option: %s",
1848ca1c9b0cSelric 			      ldap_err2string(rc));
1849ca1c9b0cSelric 	goto out;
1850ca1c9b0cSelric     }
1851ca1c9b0cSelric 
1852ca1c9b0cSelric     rc = ldap_delete_ext_s(HDB2LDAP(db), dn, NULL, NULL );
1853ca1c9b0cSelric     if (check_ldap(context, db, rc)) {
1854ca1c9b0cSelric 	ret = HDB_ERR_CANT_LOCK_DB;
1855ca1c9b0cSelric 	krb5_set_error_message(context, ret, "ldap_delete_ext_s: %s",
1856ca1c9b0cSelric 			       ldap_err2string(rc));
1857ca1c9b0cSelric     } else
1858ca1c9b0cSelric 	ret = 0;
1859ca1c9b0cSelric 
1860ca1c9b0cSelric   out:
1861ca1c9b0cSelric     if (dn != NULL)
1862ca1c9b0cSelric 	free(dn);
1863ca1c9b0cSelric     if (msg != NULL)
1864ca1c9b0cSelric 	ldap_msgfree(msg);
1865ca1c9b0cSelric 
1866ca1c9b0cSelric     return ret;
1867ca1c9b0cSelric }
1868ca1c9b0cSelric 
1869ca1c9b0cSelric static krb5_error_code
LDAP_destroy(krb5_context context,HDB * db)1870ca1c9b0cSelric LDAP_destroy(krb5_context context, HDB * db)
1871ca1c9b0cSelric {
1872ca1c9b0cSelric     krb5_error_code ret;
1873ca1c9b0cSelric 
1874ca1c9b0cSelric     LDAP_close(context, db);
1875ca1c9b0cSelric 
1876ca1c9b0cSelric     ret = hdb_clear_master_key(context, db);
1877ca1c9b0cSelric     if (HDB2BASE(db))
1878ca1c9b0cSelric 	free(HDB2BASE(db));
1879ca1c9b0cSelric     if (HDB2CREATE(db))
1880ca1c9b0cSelric 	free(HDB2CREATE(db));
1881ca1c9b0cSelric     if (HDB2URL(db))
1882ca1c9b0cSelric 	free(HDB2URL(db));
1883ca1c9b0cSelric     if (db->hdb_name)
1884ca1c9b0cSelric 	free(db->hdb_name);
1885ca1c9b0cSelric     free(db->hdb_db);
1886ca1c9b0cSelric     free(db);
1887ca1c9b0cSelric 
1888ca1c9b0cSelric     return ret;
1889ca1c9b0cSelric }
1890ca1c9b0cSelric 
1891ca1c9b0cSelric static krb5_error_code
LDAP_set_sync(krb5_context context,HDB * db,int on)1892*241bea01Schristos LDAP_set_sync(krb5_context context, HDB * db, int on)
1893*241bea01Schristos {
1894*241bea01Schristos     (void)on;
1895*241bea01Schristos     return 0;
1896*241bea01Schristos }
1897*241bea01Schristos 
1898*241bea01Schristos static krb5_error_code
hdb_ldap_common(krb5_context context,HDB ** db,const char * search_base,const char * url)1899ca1c9b0cSelric hdb_ldap_common(krb5_context context,
1900ca1c9b0cSelric 		HDB ** db,
1901ca1c9b0cSelric 		const char *search_base,
1902ca1c9b0cSelric 		const char *url)
1903ca1c9b0cSelric {
1904ca1c9b0cSelric     struct hdbldapdb *h;
1905ca1c9b0cSelric     const char *create_base = NULL;
1906b9d004c6Schristos     const char *ldap_secret_file = NULL;
1907ca1c9b0cSelric 
1908b9d004c6Schristos     if (url == NULL || url[0] == '\0') {
1909b9d004c6Schristos 	const char *p;
1910b9d004c6Schristos 	p = krb5_config_get_string(context, NULL, "kdc",
1911b9d004c6Schristos 				   "hdb-ldap-url", NULL);
1912b9d004c6Schristos 	if (p == NULL)
1913b9d004c6Schristos 		p = default_ldap_url;
1914b9d004c6Schristos 
1915b9d004c6Schristos 	url = p;
1916b9d004c6Schristos     }
1917b9d004c6Schristos 
1918b9d004c6Schristos     if (search_base == NULL || search_base[0] == '\0') {
1919ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "ldap search base not configured");
1920ca1c9b0cSelric 	return ENOMEM; /* XXX */
1921ca1c9b0cSelric     }
1922ca1c9b0cSelric 
1923ca1c9b0cSelric     if (structural_object == NULL) {
1924ca1c9b0cSelric 	const char *p;
1925ca1c9b0cSelric 
1926ca1c9b0cSelric 	p = krb5_config_get_string(context, NULL, "kdc",
1927ca1c9b0cSelric 				   "hdb-ldap-structural-object", NULL);
1928ca1c9b0cSelric 	if (p == NULL)
1929ca1c9b0cSelric 	    p = default_structural_object;
1930ca1c9b0cSelric 	structural_object = strdup(p);
1931ca1c9b0cSelric 	if (structural_object == NULL) {
1932ca1c9b0cSelric 	    krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1933ca1c9b0cSelric 	    return ENOMEM;
1934ca1c9b0cSelric 	}
1935ca1c9b0cSelric     }
1936ca1c9b0cSelric 
1937ca1c9b0cSelric     samba_forwardable =
1938ca1c9b0cSelric 	krb5_config_get_bool_default(context, NULL, TRUE,
1939ca1c9b0cSelric 				     "kdc", "hdb-samba-forwardable", NULL);
1940ca1c9b0cSelric 
1941ca1c9b0cSelric     *db = calloc(1, sizeof(**db));
1942ca1c9b0cSelric     if (*db == NULL) {
1943ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1944ca1c9b0cSelric 	return ENOMEM;
1945ca1c9b0cSelric     }
1946ca1c9b0cSelric     memset(*db, 0, sizeof(**db));
1947ca1c9b0cSelric 
1948ca1c9b0cSelric     h = calloc(1, sizeof(*h));
1949ca1c9b0cSelric     if (h == NULL) {
1950ca1c9b0cSelric 	free(*db);
1951ca1c9b0cSelric 	*db = NULL;
1952ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
1953ca1c9b0cSelric 	return ENOMEM;
1954ca1c9b0cSelric     }
1955ca1c9b0cSelric     (*db)->hdb_db = h;
1956ca1c9b0cSelric 
1957ca1c9b0cSelric     /* XXX */
1958ca1c9b0cSelric     if (asprintf(&(*db)->hdb_name, "ldap:%s", search_base) == -1) {
1959ca1c9b0cSelric 	LDAP_destroy(context, *db);
1960ca1c9b0cSelric 	*db = NULL;
1961ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "strdup: out of memory");
1962ca1c9b0cSelric 	return ENOMEM;
1963ca1c9b0cSelric     }
1964ca1c9b0cSelric 
1965ca1c9b0cSelric     h->h_url = strdup(url);
1966ca1c9b0cSelric     h->h_base = strdup(search_base);
1967ca1c9b0cSelric     if (h->h_url == NULL || h->h_base == NULL) {
1968ca1c9b0cSelric 	LDAP_destroy(context, *db);
1969ca1c9b0cSelric 	*db = NULL;
1970ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "strdup: out of memory");
1971ca1c9b0cSelric 	return ENOMEM;
1972ca1c9b0cSelric     }
1973ca1c9b0cSelric 
1974b9d004c6Schristos     ldap_secret_file = krb5_config_get_string(context, NULL, "kdc",
1975b9d004c6Schristos 					      "hdb-ldap-secret-file", NULL);
1976b9d004c6Schristos     if (ldap_secret_file != NULL) {
1977b9d004c6Schristos 	krb5_config_binding *tmp;
1978b9d004c6Schristos 	krb5_error_code ret;
1979b9d004c6Schristos 	const char *p;
1980b9d004c6Schristos 
1981b9d004c6Schristos 	ret = krb5_config_parse_file(context, ldap_secret_file, &tmp);
1982b9d004c6Schristos 	if (ret)
1983b9d004c6Schristos 	    return ret;
1984b9d004c6Schristos 
1985b9d004c6Schristos 	p = krb5_config_get_string(context, tmp, "kdc",
1986b9d004c6Schristos 				   "hdb-ldap-bind-dn", NULL);
1987b9d004c6Schristos 	if (p != NULL)
1988b9d004c6Schristos 	    h->h_bind_dn = strdup(p);
1989b9d004c6Schristos 
1990b9d004c6Schristos 	p = krb5_config_get_string(context, tmp, "kdc",
1991b9d004c6Schristos 				   "hdb-ldap-bind-password", NULL);
1992b9d004c6Schristos 	if (p != NULL)
1993b9d004c6Schristos 	    h->h_bind_password = strdup(p);
1994b9d004c6Schristos 
1995b9d004c6Schristos 	krb5_config_file_free(context, tmp);
1996b9d004c6Schristos     }
1997b9d004c6Schristos 
1998b9d004c6Schristos     h->h_start_tls =
1999b9d004c6Schristos 	krb5_config_get_bool_default(context, NULL, FALSE,
2000b9d004c6Schristos 				     "kdc", "hdb-ldap-start-tls", NULL);
2001b9d004c6Schristos 
2002ca1c9b0cSelric     create_base = krb5_config_get_string(context, NULL, "kdc",
2003ca1c9b0cSelric 					 "hdb-ldap-create-base", NULL);
2004ca1c9b0cSelric     if (create_base == NULL)
2005ca1c9b0cSelric 	create_base = h->h_base;
2006ca1c9b0cSelric 
2007ca1c9b0cSelric     h->h_createbase = strdup(create_base);
2008ca1c9b0cSelric     if (h->h_createbase == NULL) {
2009ca1c9b0cSelric 	LDAP_destroy(context, *db);
2010ca1c9b0cSelric 	*db = NULL;
2011ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "strdup: out of memory");
2012ca1c9b0cSelric 	return ENOMEM;
2013ca1c9b0cSelric     }
2014ca1c9b0cSelric 
2015ca1c9b0cSelric     (*db)->hdb_master_key_set = 0;
2016ca1c9b0cSelric     (*db)->hdb_openp = 0;
2017b9d004c6Schristos     (*db)->hdb_capability_flags = HDB_CAP_F_SHARED_DIRECTORY;
2018ca1c9b0cSelric     (*db)->hdb_open = LDAP_open;
2019ca1c9b0cSelric     (*db)->hdb_close = LDAP_close;
2020ca1c9b0cSelric     (*db)->hdb_fetch_kvno = LDAP_fetch_kvno;
2021ca1c9b0cSelric     (*db)->hdb_store = LDAP_store;
2022ca1c9b0cSelric     (*db)->hdb_remove = LDAP_remove;
2023ca1c9b0cSelric     (*db)->hdb_firstkey = LDAP_firstkey;
2024ca1c9b0cSelric     (*db)->hdb_nextkey = LDAP_nextkey;
2025ca1c9b0cSelric     (*db)->hdb_lock = LDAP_lock;
2026ca1c9b0cSelric     (*db)->hdb_unlock = LDAP_unlock;
2027ca1c9b0cSelric     (*db)->hdb_rename = NULL;
2028ca1c9b0cSelric     (*db)->hdb__get = NULL;
2029ca1c9b0cSelric     (*db)->hdb__put = NULL;
2030ca1c9b0cSelric     (*db)->hdb__del = NULL;
2031ca1c9b0cSelric     (*db)->hdb_destroy = LDAP_destroy;
2032*241bea01Schristos     (*db)->hdb_set_sync = LDAP_set_sync;
2033ca1c9b0cSelric 
2034ca1c9b0cSelric     return 0;
2035ca1c9b0cSelric }
2036ca1c9b0cSelric 
2037b9d004c6Schristos #ifdef OPENLDAP_MODULE
2038b9d004c6Schristos static
2039b9d004c6Schristos #endif
2040b9d004c6Schristos 
2041ca1c9b0cSelric krb5_error_code
hdb_ldap_create(krb5_context context,HDB ** db,const char * arg)2042ca1c9b0cSelric hdb_ldap_create(krb5_context context, HDB ** db, const char *arg)
2043ca1c9b0cSelric {
2044b9d004c6Schristos     return hdb_ldap_common(context, db, arg, NULL);
2045ca1c9b0cSelric }
2046ca1c9b0cSelric 
2047b9d004c6Schristos #ifdef OPENLDAP_MODULE
2048b9d004c6Schristos static
2049b9d004c6Schristos #endif
2050b9d004c6Schristos 
2051ca1c9b0cSelric krb5_error_code
hdb_ldapi_create(krb5_context context,HDB ** db,const char * arg)2052ca1c9b0cSelric hdb_ldapi_create(krb5_context context, HDB ** db, const char *arg)
2053ca1c9b0cSelric {
2054ca1c9b0cSelric     krb5_error_code ret;
2055ca1c9b0cSelric     char *search_base, *p;
2056ca1c9b0cSelric 
2057b9d004c6Schristos     if (asprintf(&p, "ldapi:%s", arg) == -1 || p == NULL) {
2058ca1c9b0cSelric 	*db = NULL;
2059ca1c9b0cSelric 	krb5_set_error_message(context, ENOMEM, "out of memory");
2060ca1c9b0cSelric 	return ENOMEM;
2061ca1c9b0cSelric     }
2062ca1c9b0cSelric     search_base = strchr(p + strlen("ldapi://"), ':');
2063ca1c9b0cSelric     if (search_base == NULL) {
2064ca1c9b0cSelric 	*db = NULL;
2065ca1c9b0cSelric 	krb5_set_error_message(context, HDB_ERR_BADVERSION,
2066ca1c9b0cSelric 			       "search base missing");
2067ca1c9b0cSelric 	return HDB_ERR_BADVERSION;
2068ca1c9b0cSelric     }
2069ca1c9b0cSelric     *search_base = '\0';
2070ca1c9b0cSelric     search_base++;
2071ca1c9b0cSelric 
2072ca1c9b0cSelric     ret = hdb_ldap_common(context, db, search_base, p);
2073ca1c9b0cSelric     free(p);
2074ca1c9b0cSelric     return ret;
2075ca1c9b0cSelric }
2076ca1c9b0cSelric 
2077ca1c9b0cSelric #ifdef OPENLDAP_MODULE
2078b9d004c6Schristos static krb5_error_code
init(krb5_context context,void ** ctx)2079b9d004c6Schristos init(krb5_context context, void **ctx)
2080b9d004c6Schristos {
2081b9d004c6Schristos     *ctx = NULL;
2082b9d004c6Schristos     return 0;
2083b9d004c6Schristos }
2084ca1c9b0cSelric 
2085b9d004c6Schristos static void
fini(void * ctx)2086b9d004c6Schristos fini(void *ctx)
2087b9d004c6Schristos {
2088b9d004c6Schristos }
2089b9d004c6Schristos 
2090b9d004c6Schristos struct hdb_method hdb_ldap_interface = {
2091ca1c9b0cSelric     HDB_INTERFACE_VERSION,
2092b9d004c6Schristos     init,
2093b9d004c6Schristos     fini,
2094ca1c9b0cSelric     "ldap",
2095ca1c9b0cSelric     hdb_ldap_create
2096ca1c9b0cSelric };
2097ca1c9b0cSelric 
2098b9d004c6Schristos struct hdb_method hdb_ldapi_interface = {
2099ca1c9b0cSelric     HDB_INTERFACE_VERSION,
2100b9d004c6Schristos     init,
2101b9d004c6Schristos     fini,
2102ca1c9b0cSelric     "ldapi",
2103ca1c9b0cSelric     hdb_ldapi_create
2104ca1c9b0cSelric };
2105ca1c9b0cSelric #endif
2106ca1c9b0cSelric 
2107ca1c9b0cSelric #endif				/* OPENLDAP */
2108