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, "e);
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, "e);
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