~ubuntu-branches/ubuntu/raring/heimdal/raring

« back to all changes in this revision

Viewing changes to .pc/034_includes/lib/hdb/hdb-ldap.c

  • Committer: Package Import Robot
  • Author(s): Jelmer Vernooij
  • Date: 2011-10-03 23:50:05 UTC
  • mfrom: (1.1.15) (2.2.23 sid)
  • Revision ID: package-import@ubuntu.com-20111003235005-0voibbgdhyqmtp6w
Tags: 1.5.dfsg.1-3
Add conflicts with kcc to heimdal-clients. Closes: #644138

Show diffs side-by-side

added added

removed removed

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