2 * Copyright (c) 1999-2001, 2003, PADL Software Pty Ltd.
3 * Copyright (c) 2004, Andrew Bartlett <abartlet@samba.org>.
4 * Copyright (c) 2004, Stefan Metzmacher <metze@samba.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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.
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.
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
39 #include "lib/ldb/include/ldb.h"
40 #include "system/iconv.h"
43 { HDB_LDB_ENT_TYPE_CLIENT
, HDB_LDB_ENT_TYPE_SERVER
, HDB_LDB_ENT_TYPE_KRBTGT
, HDB_LDB_ENT_TYPE_ANY
};
45 static const char * const krb5_attrs
[] = {
52 "servicePrincipalName",
78 "msDS-KeyVersionNumber",
82 static KerberosTime
ldb_msg_find_krb5time_ldap_time(struct ldb_message
*msg
, const char *attr
, KerberosTime default_val
)
88 gentime
= ldb_msg_find_string(msg
, attr
, NULL
);
92 tmp
= strptime(gentime
, "%Y%m%d%H%M%SZ", &tm
);
100 static HDBFlags
uf2HDBFlags(krb5_context context
, int userAccountControl
, enum hdb_ldb_ent_type ent_type
)
102 HDBFlags flags
= int2HDBFlags(0);
104 krb5_warnx(context
, "uf2HDBFlags: userAccountControl: %08x\n", userAccountControl
);
106 /* we don't allow kadmin deletes */
109 /* mark the principal as invalid to start with */
114 /* Account types - clear the invalid bit if it turns out to be valid */
115 if (userAccountControl
& UF_NORMAL_ACCOUNT
) {
116 if (ent_type
== HDB_LDB_ENT_TYPE_CLIENT
|| ent_type
== HDB_LDB_ENT_TYPE_ANY
) {
122 if (userAccountControl
& UF_INTERDOMAIN_TRUST_ACCOUNT
) {
123 if (ent_type
== HDB_LDB_ENT_TYPE_CLIENT
|| ent_type
== HDB_LDB_ENT_TYPE_ANY
) {
128 if (userAccountControl
& UF_WORKSTATION_TRUST_ACCOUNT
) {
129 if (ent_type
== HDB_LDB_ENT_TYPE_CLIENT
|| ent_type
== HDB_LDB_ENT_TYPE_ANY
) {
132 if (ent_type
== HDB_LDB_ENT_TYPE_SERVER
|| ent_type
== HDB_LDB_ENT_TYPE_ANY
) {
137 if (userAccountControl
& UF_SERVER_TRUST_ACCOUNT
) {
138 if (ent_type
== HDB_LDB_ENT_TYPE_CLIENT
|| ent_type
== HDB_LDB_ENT_TYPE_ANY
) {
141 if (ent_type
== HDB_LDB_ENT_TYPE_SERVER
|| ent_type
== HDB_LDB_ENT_TYPE_ANY
) {
147 if (userAccountControl
& UF_ACCOUNTDISABLE
) {
150 if (userAccountControl
& UF_LOCKOUT
) {
154 if (userAccountControl & UF_PASSWORD_NOTREQD) {
159 if (userAccountControl & UF_PASSWORD_CANT_CHANGE) {
164 if (userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED) {
168 if (userAccountControl
& UF_TEMP_DUPLICATE_ACCOUNT
) {
172 /* UF_DONT_EXPIRE_PASSWD handled in LDB_message2entry() */
175 if (userAccountControl & UF_MNS_LOGON_ACCOUNT) {
179 if (userAccountControl
& UF_SMARTCARD_REQUIRED
) {
180 flags
.require_hwauth
= 1;
182 if (flags
.server
&& (userAccountControl
& UF_TRUSTED_FOR_DELEGATION
)) {
183 flags
.forwardable
= 1;
185 } else if (flags
.client
&& (userAccountControl
& UF_NOT_DELEGATED
)) {
186 flags
.forwardable
= 0;
189 flags
.forwardable
= 1;
194 if (userAccountControl & UF_SMARTCARD_USE_DES_KEY_ONLY) {
198 if (userAccountControl
& UF_DONT_REQUIRE_PREAUTH
) {
199 flags
.require_preauth
= 0;
201 flags
.require_preauth
= 1;
205 krb5_warnx(context
, "uf2HDBFlags: HDBFlags: %08x\n", HDBFlags2int(flags
));
211 * Construct an hdb_entry from a directory entry.
213 static krb5_error_code
LDB_message2entry(krb5_context context
, HDB
*db
,
214 TALLOC_CTX
*mem_ctx
, krb5_const_principal principal
,
215 enum hdb_ldb_ent_type ent_type
, struct ldb_message
*realm_msg
,
216 struct ldb_message
*msg
,
219 const char *unicodePwd
;
220 int userAccountControl
;
222 krb5_error_code ret
= 0;
223 const char *dnsdomain
= ldb_msg_find_string(realm_msg
, "dnsDomain", NULL
);
224 char *realm
= strupper_talloc(mem_ctx
, dnsdomain
);
227 krb5_set_error_string(context
, "talloc_strdup: out of memory");
232 krb5_warnx(context
, "LDB_message2entry:\n");
234 memset(ent
, 0, sizeof(*ent
));
236 userAccountControl
= ldb_msg_find_int(msg
, "userAccountControl", 0);
238 ent
->principal
= malloc(sizeof(*(ent
->principal
)));
239 if (ent_type
== HDB_LDB_ENT_TYPE_ANY
&& principal
== NULL
) {
240 const char *samAccountName
= ldb_msg_find_string(msg
, "samAccountName", NULL
);
241 if (!samAccountName
) {
242 krb5_set_error_string(context
, "LDB_message2entry: no samAccountName present");
246 samAccountName
= ldb_msg_find_string(msg
, "samAccountName", NULL
);
247 krb5_make_principal(context
, &ent
->principal
, realm
, samAccountName
, NULL
);
250 ret
= copy_Principal(principal
, ent
->principal
);
252 krb5_clear_error_string(context
);
256 /* While we have copied the client principal, tests
257 * show that Win2k3 returns the 'corrected' realm, not
258 * the client-specified realm. This code attempts to
259 * replace the client principal's realm with the one
260 * we determine from our records */
263 free(*krb5_princ_realm(context
, ent
->principal
));
265 /* this has to be with malloc() */
266 strdup_realm
= strdup(realm
);
269 krb5_clear_error_string(context
);
272 krb5_princ_set_realm(context
, ent
->principal
, &strdup_realm
);
275 ent
->kvno
= ldb_msg_find_int(msg
, "msDS-KeyVersionNumber", 0);
277 ent
->flags
= uf2HDBFlags(context
, userAccountControl
, ent_type
);
279 if (ent_type
== HDB_LDB_ENT_TYPE_KRBTGT
) {
280 ent
->flags
.invalid
= 0;
281 ent
->flags
.server
= 1;
284 /* use 'whenCreated' */
285 ent
->created_by
.time
= ldb_msg_find_krb5time_ldap_time(msg
, "whenCreated", 0);
287 ent
->created_by
.principal
= NULL
;
289 ent
->modified_by
= (Event
*) malloc(sizeof(Event
));
290 if (ent
->modified_by
== NULL
) {
291 krb5_set_error_string(context
, "malloc: out of memory");
296 /* use 'whenChanged' */
297 ent
->modified_by
->time
= ldb_msg_find_krb5time_ldap_time(msg
, "whenChanged", 0);
299 ent
->modified_by
->principal
= NULL
;
301 ent
->valid_start
= NULL
;
303 ent
->valid_end
= NULL
;
306 ent
->max_life
= NULL
;
308 ent
->max_renew
= NULL
;
310 ent
->generation
= NULL
;
312 /* create the keys and enctypes */
313 unicodePwd
= ldb_msg_find_string(msg
, "unicodePwd", NULL
);
315 /* Many, many thanks to lukeh@padl.com for this
316 * algorithm, described in his Nov 10 2004 mail to
317 * samba-technical@samba.org */
319 Principal
*salt_principal
;
320 const char *user_principal_name
= ldb_msg_find_string(msg
, "userPrincipalName", NULL
);
321 struct ldb_message_element
*objectclasses
;
322 struct ldb_val computer_val
;
323 computer_val
.data
= "computer";
324 computer_val
.length
= strlen(computer_val
.data
);
326 objectclasses
= ldb_msg_find_element(msg
, "objectClass");
328 if (objectclasses
&& ldb_msg_find_val(objectclasses
, &computer_val
)) {
329 /* Determine a salting principal */
330 char *samAccountName
= talloc_strdup(mem_ctx
, ldb_msg_find_string(msg
, "samAccountName", NULL
));
332 if (!samAccountName
) {
333 krb5_set_error_string(context
, "LDB_message2entry: no samAccountName present");
337 if (samAccountName
[strlen(samAccountName
)-1] == '$') {
338 samAccountName
[strlen(samAccountName
)-1] = '\0';
340 saltbody
= talloc_asprintf(mem_ctx
, "%s.%s", samAccountName
, dnsdomain
);
342 ret
= krb5_make_principal(context
, &salt_principal
, realm
, "host", saltbody
, NULL
);
343 } else if (user_principal_name
) {
345 user_principal_name
= talloc_strdup(mem_ctx
, user_principal_name
);
346 if (!user_principal_name
) {
350 p
= strchr(user_principal_name
, '@');
354 ret
= krb5_make_principal(context
, &salt_principal
, realm
, user_principal_name
, NULL
);
357 const char *samAccountName
= ldb_msg_find_string(msg
, "samAccountName", NULL
);
358 ret
= krb5_make_principal(context
, &salt_principal
, realm
, samAccountName
, NULL
);
363 * create keys from unicodePwd
365 ret
= hdb_generate_key_set_password(context
, salt_principal
,
367 &ent
->keys
.val
, &ent
->keys
.len
);
368 krb5_free_principal(context
, salt_principal
);
372 krb5_warnx(context
, "could not generate keys from unicodePwd\n");
373 ent
->keys
.val
= NULL
;
378 const struct ldb_val
*val
;
381 val
= ldb_msg_find_ldb_val(msg
, "ntPwdHash");
383 krb5_warnx(context
, "neither type of key available for this account\n");
384 ent
->keys
.val
= NULL
;
386 } else if (val
->length
< 16) {
387 ent
->keys
.val
= NULL
;
389 krb5_warnx(context
, "ntPwdHash has invalid length: %d\n",val
->length
);
391 ret
= krb5_data_alloc (&keyvalue
, 16);
393 krb5_set_error_string(context
, "malloc: out of memory");
398 memcpy(keyvalue
.data
, val
->data
, 16);
400 ent
->keys
.val
= malloc(sizeof(ent
->keys
.val
[0]));
401 if (ent
->keys
.val
== NULL
) {
402 krb5_data_free(&keyvalue
);
403 krb5_set_error_string(context
, "malloc: out of memory");
408 memset(&ent
->keys
.val
[0], 0, sizeof(Key
));
409 ent
->keys
.val
[0].key
.keytype
= ETYPE_ARCFOUR_HMAC_MD5
;
410 ent
->keys
.val
[0].key
.keyvalue
= keyvalue
;
417 ent
->etypes
= malloc(sizeof(*(ent
->etypes
)));
418 if (ent
->etypes
== NULL
) {
419 krb5_set_error_string(context
, "malloc: out of memory");
423 ent
->etypes
->len
= ent
->keys
.len
;
424 ent
->etypes
->val
= calloc(ent
->etypes
->len
, sizeof(int));
425 if (ent
->etypes
->val
== NULL
) {
426 krb5_set_error_string(context
, "malloc: out of memory");
430 for (i
=0; i
< ent
->etypes
->len
; i
++) {
431 ent
->etypes
->val
[i
] = ent
->keys
.val
[i
].key
.keytype
;
436 /* I don't think this frees ent itself. */
437 hdb_free_entry(context
, ent
);
443 static krb5_error_code
LDB_lookup_principal(krb5_context context
, struct ldb_context
*ldb_ctx
,
445 krb5_const_principal principal
,
446 enum hdb_ldb_ent_type ent_type
,
447 const char *realm_dn
,
448 struct ldb_message
***pmsg
)
453 const char * const *princ_attrs
= krb5_attrs
;
457 char *princ_str_talloc
;
460 struct ldb_message
**msg
;
462 ret
= krb5_unparse_name(context
, principal
, &princ_str
);
465 krb5_set_error_string(context
, "LDB_lookup_principal: could not parse principal");
466 krb5_warnx(context
, "LDB_lookup_principal: could not parse principal");
470 princ_str_talloc
= talloc_strdup(mem_ctx
, princ_str
);
471 short_princ
= talloc_strdup(mem_ctx
, princ_str
);
473 if (!short_princ
|| !princ_str_talloc
) {
474 krb5_set_error_string(context
, "LDB_lookup_principal: talloc_strdup() failed!");
478 p
= strchr(short_princ
, '@');
485 case HDB_LDB_ENT_TYPE_KRBTGT
:
486 filter
= talloc_asprintf(mem_ctx
, "(&(objectClass=user)(samAccountName=%s))",
489 case HDB_LDB_ENT_TYPE_CLIENT
:
490 filter
= talloc_asprintf(mem_ctx
, "(&(objectClass=user)(|(samAccountName=%s)(userPrincipalName=%s)))",
491 short_princ
, princ_str_talloc
);
493 case HDB_LDB_ENT_TYPE_SERVER
:
494 filter
= talloc_asprintf(mem_ctx
, "(&(objectClass=user)(|(samAccountName=%s)(servicePrincipalName=%s)))",
495 short_princ
, short_princ
);
497 case HDB_LDB_ENT_TYPE_ANY
:
498 filter
= talloc_asprintf(mem_ctx
, "(&(objectClass=user)(|(|(samAccountName=%s)(servicePrincipalName=%s))(userPrincipalName=%s)))",
499 short_princ
, short_princ
, princ_str_talloc
);
504 krb5_set_error_string(context
, "talloc_asprintf: out of memory");
508 count
= ldb_search(ldb_ctx
, realm_dn
, LDB_SCOPE_SUBTREE
, filter
,
511 *pmsg
= talloc_steal(mem_ctx
, msg
);
513 krb5_warnx(context
, "ldb_search: basedn: '%s' filter: '%s' failed: %d",
514 realm_dn
, filter
, count
);
515 krb5_set_error_string(context
, "ldb_search: basedn: '%s' filter: '%s' failed: %d",
516 realm_dn
, filter
, count
);
517 return HDB_ERR_NOENTRY
;
518 } else if (count
> 1) {
519 krb5_warnx(context
, "ldb_search: basedn: '%s' filter: '%s' more than 1 entry: %d",
520 realm_dn
, filter
, count
);
521 krb5_set_error_string(context
, "ldb_search: basedn: '%s' filter: '%s' more than 1 entry: %d",
522 realm_dn
, filter
, count
);
523 return HDB_ERR_NOENTRY
;
528 static krb5_error_code
LDB_lookup_realm(krb5_context context
, struct ldb_context
*ldb_ctx
,
531 struct ldb_message
***pmsg
)
534 const char *realm_dn
;
535 char *cross_ref_filter
;
536 struct ldb_message
**cross_ref_msg
;
537 struct ldb_message
**msg
;
539 const char *cross_ref_attrs
[] = {
544 const char *realm_attrs
[] = {
550 cross_ref_filter
= talloc_asprintf(mem_ctx
,
551 "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
553 if (!cross_ref_filter
) {
554 krb5_set_error_string(context
, "asprintf: out of memory");
558 count
= ldb_search(ldb_ctx
, NULL
, LDB_SCOPE_SUBTREE
, cross_ref_filter
,
559 cross_ref_attrs
, &cross_ref_msg
);
562 krb5_warnx(context
, "ldb_search: filter: '%s' failed: %d", cross_ref_filter
, count
);
563 krb5_set_error_string(context
, "ldb_search: filter: '%s' failed: %d", cross_ref_filter
, count
);
565 talloc_free(cross_ref_msg
);
566 return HDB_ERR_NOENTRY
;
567 } else if (count
> 1) {
568 krb5_warnx(context
, "ldb_search: filter: '%s' more than 1 entry: %d", cross_ref_filter
, count
);
569 krb5_set_error_string(context
, "ldb_search: filter: '%s' more than 1 entry: %d", cross_ref_filter
, count
);
571 talloc_free(cross_ref_msg
);
572 return HDB_ERR_NOENTRY
;
575 realm_dn
= ldb_msg_find_string(cross_ref_msg
[0], "nCName", NULL
);
577 count
= ldb_search(ldb_ctx
, realm_dn
, LDB_SCOPE_BASE
, "(objectClass=domain)",
580 *pmsg
= talloc_steal(mem_ctx
, msg
);
586 krb5_warnx(context
, "ldb_search: dn: %s not found: %d", realm_dn
, count
);
587 krb5_set_error_string(context
, "ldb_search: dn: %s not found: %d", realm_dn
, count
);
588 return HDB_ERR_NOENTRY
;
589 } else if (count
> 1) {
590 krb5_warnx(context
, "ldb_search: dn: '%s' more than 1 entry: %d", realm_dn
, count
);
591 krb5_set_error_string(context
, "ldb_search: dn: %s more than 1 entry: %d", realm_dn
, count
);
592 return HDB_ERR_NOENTRY
;
598 static krb5_error_code
LDB_lookup_spn_alias(krb5_context context
, struct ldb_context
*ldb_ctx
,
600 const char *realm_dn
,
601 const char *alias_from
,
606 struct ldb_message
**msg
;
607 struct ldb_message_element
*spnmappings
;
608 char *service_dn
= talloc_asprintf(mem_ctx
,
609 "CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration,%s",
611 const char *directory_attrs
[] = {
616 count
= ldb_search(ldb_ctx
, service_dn
, LDB_SCOPE_BASE
, "(objectClass=nTDSService)",
617 directory_attrs
, &msg
);
618 talloc_steal(mem_ctx
, msg
);
621 krb5_warnx(context
, "ldb_search: dn: %s not found: %d", service_dn
, count
);
622 krb5_set_error_string(context
, "ldb_search: dn: %s not found: %d", service_dn
, count
);
623 return HDB_ERR_NOENTRY
;
624 } else if (count
> 1) {
625 krb5_warnx(context
, "ldb_search: dn: %s found %d times!", service_dn
, count
);
626 krb5_set_error_string(context
, "ldb_search: dn: %s found %d times!", service_dn
, count
);
627 return HDB_ERR_NOENTRY
;
630 spnmappings
= ldb_msg_find_element(msg
[0], "sPNMappings");
631 if (!spnmappings
|| spnmappings
->num_values
== 0) {
632 krb5_warnx(context
, "ldb_search: dn: %s no sPNMappings attribute", service_dn
);
633 krb5_set_error_string(context
, "ldb_search: dn: %s no sPNMappings attribute", service_dn
);
636 for (i
= 0; i
< spnmappings
->num_values
; i
++) {
637 char *mapping
, *p
, *str
;
638 mapping
= talloc_strdup(mem_ctx
,
639 spnmappings
->values
[i
].data
);
641 krb5_warnx(context
, "LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping", service_dn
);
642 krb5_set_error_string(context
, "LDB_lookup_spn_alias: ldb_search: dn: %s did not have an sPNMapping", service_dn
);
643 return HDB_ERR_NOENTRY
;
646 /* C string manipulation sucks */
648 p
= strchr(mapping
, '=');
650 krb5_warnx(context
, "ldb_search: dn: %s sPNMapping malformed: %s",
651 service_dn
, mapping
);
652 krb5_set_error_string(context
, "ldb_search: dn: %s sPNMapping malformed: %s",
653 service_dn
, mapping
);
664 if (strcasecmp(str
, alias_from
) == 0) {
670 krb5_warnx(context
, "LDB_lookup_spn_alias: no alias for service %s applicable", alias_from
);
671 return HDB_ERR_NOENTRY
;
674 static krb5_error_code
LDB_open(krb5_context context
, HDB
*db
, int flags
, mode_t mode
)
676 if (db
->hdb_master_key_set
) {
677 krb5_warnx(context
, "LDB_open: use of a master key incompatible with LDB\n");
678 krb5_set_error_string(context
, "LDB_open: use of a master key incompatible with LDB\n");
679 return HDB_ERR_NOENTRY
;
685 static krb5_error_code
LDB_close(krb5_context context
, HDB
*db
)
690 static krb5_error_code
LDB_lock(krb5_context context
, HDB
*db
, int operation
)
695 static krb5_error_code
LDB_unlock(krb5_context context
, HDB
*db
)
700 static krb5_error_code
LDB_rename(krb5_context context
, HDB
*db
, const char *new_name
)
702 return HDB_ERR_DB_INUSE
;
705 static krb5_error_code
LDB_fetch(krb5_context context
, HDB
*db
, unsigned flags
,
706 krb5_const_principal principal
,
707 enum hdb_ent_type ent_type
,
710 struct ldb_message
**msg
= NULL
;
711 struct ldb_message
**realm_msg
= NULL
;
712 enum hdb_ldb_ent_type ldb_ent_type
;
716 const char *realm_dn
;
717 TALLOC_CTX
*mem_ctx
= talloc_named(NULL
, 0, "LDB_fetch context\n");
720 krb5_set_error_string(context
, "LDB_fetch: talloc_named() failed!");
724 realm
= krb5_principal_get_realm(context
, principal
);
726 ret
= LDB_lookup_realm(context
, (struct ldb_context
*)db
->hdb_db
,
727 mem_ctx
, realm
, &realm_msg
);
729 krb5_warnx(context
, "LDB_fetch: could not find realm\n");
730 talloc_free(mem_ctx
);
731 return HDB_ERR_NOENTRY
;
734 realm_dn
= realm_msg
[0]->dn
;
736 /* Cludge, cludge cludge. If the realm part of krbtgt/realm,
737 * is in our db, then direct the caller at our primary
741 case HDB_ENT_TYPE_SERVER
:
742 if (principal
->name
.name_string
.len
== 2
743 && (strcmp(principal
->name
.name_string
.val
[0], KRB5_TGS_NAME
) == 0)
744 && (LDB_lookup_realm(context
, (struct ldb_context
*)db
->hdb_db
,
745 mem_ctx
, principal
->name
.name_string
.val
[1], NULL
) == 0)) {
746 ldb_ent_type
= HDB_LDB_ENT_TYPE_KRBTGT
;
748 ldb_ent_type
= HDB_LDB_ENT_TYPE_SERVER
;
751 case HDB_ENT_TYPE_CLIENT
:
752 ldb_ent_type
= HDB_LDB_ENT_TYPE_CLIENT
;
754 case HDB_ENT_TYPE_ANY
:
755 ldb_ent_type
= HDB_LDB_ENT_TYPE_ANY
;
759 ret
= LDB_lookup_principal(context
, (struct ldb_context
*)db
->hdb_db
,
761 principal
, ldb_ent_type
, realm_dn
, &msg
);
764 char *alias_from
= principal
->name
.name_string
.val
[0];
766 Principal alias_principal
;
768 /* Try again with a servicePrincipal alias */
769 if (ent_type
!= HDB_LDB_ENT_TYPE_SERVER
&& ent_type
!= HDB_LDB_ENT_TYPE_ANY
) {
770 talloc_free(mem_ctx
);
773 if (principal
->name
.name_string
.len
< 2) {
774 krb5_warnx(context
, "LDB_fetch: could not find principal in DB, alias not applicable");
775 krb5_set_error_string(context
, "LDB_fetch: could not find principal in DB, alias not applicable");
776 talloc_free(mem_ctx
);
780 /* Look for the list of aliases */
781 ret
= LDB_lookup_spn_alias(context
,
782 (struct ldb_context
*)db
->hdb_db
, mem_ctx
,
783 realm_dn
, alias_from
,
786 talloc_free(mem_ctx
);
790 ret
= copy_Principal(principal
, &alias_principal
);
792 krb5_warnx(context
, "LDB_fetch: could not copy principal");
793 krb5_set_error_string(context
, "LDB_fetch: could not copy principal");
794 talloc_free(mem_ctx
);
798 /* ooh, very nasty playing around in the Principal... */
799 free(alias_principal
.name
.name_string
.val
[0]);
800 alias_principal
.name
.name_string
.val
[0] = strdup(alias_to
);
801 if (!alias_principal
.name
.name_string
.val
[0]) {
802 krb5_warnx(context
, "LDB_fetch: strdup() failed");
803 krb5_set_error_string(context
, "LDB_fetch: strdup() failed");
805 talloc_free(mem_ctx
);
806 free_Principal(&alias_principal
);
810 ret
= LDB_lookup_principal(context
, (struct ldb_context
*)db
->hdb_db
,
812 &alias_principal
, ent_type
, realm_dn
, &msg
);
813 free_Principal(&alias_principal
);
816 krb5_warnx(context
, "LDB_fetch: could not find alias principal in DB");
817 krb5_set_error_string(context
, "LDB_fetch: could not find alias principal in DB");
818 talloc_free(mem_ctx
);
824 ret
= LDB_message2entry(context
, db
, mem_ctx
,
825 principal
, ldb_ent_type
,
826 realm_msg
[0], msg
[0], entry
);
828 krb5_warnx(context
, "LDB_fetch: message2entry failed\n");
832 talloc_free(mem_ctx
);
836 static krb5_error_code
LDB_store(krb5_context context
, HDB
*db
, unsigned flags
, hdb_entry
*entry
)
838 return HDB_ERR_DB_INUSE
;
841 static krb5_error_code
LDB_remove(krb5_context context
, HDB
*db
, hdb_entry
*entry
)
843 return HDB_ERR_DB_INUSE
;
847 struct ldb_context
*ctx
;
850 struct ldb_message
**msgs
;
851 struct ldb_message
**realm_msgs
;
854 static krb5_error_code
LDB_seq(krb5_context context
, HDB
*db
, unsigned flags
, hdb_entry
*entry
)
857 struct hdb_ldb_seq
*priv
= (struct hdb_ldb_seq
*)db
->hdb_openp
;
860 return HDB_ERR_NOENTRY
;
863 mem_ctx
= talloc_named(priv
, 0, "LDB_seq context");
866 krb5_set_error_string(context
, "LDB_seq: talloc_named() failed!");
870 if (priv
->index
< priv
->count
) {
871 ret
= LDB_message2entry(context
, db
, mem_ctx
,
872 NULL
, HDB_LDB_ENT_TYPE_ANY
,
873 priv
->realm_msgs
[0], priv
->msgs
[priv
->index
++], entry
);
875 ret
= HDB_ERR_NOENTRY
;
880 db
->hdb_openp
= NULL
;
882 talloc_free(mem_ctx
);
888 static krb5_error_code
LDB_firstkey(krb5_context context
, HDB
*db
, unsigned flags
,
891 struct ldb_context
*ldb_ctx
= (struct ldb_context
*)db
->hdb_db
;
892 struct hdb_ldb_seq
*priv
= (struct hdb_ldb_seq
*)db
->hdb_openp
;
894 char *realm_dn
= NULL
;
895 struct ldb_message
**msgs
= NULL
;
896 struct ldb_message
**realm_msgs
= NULL
;
905 priv
= (struct hdb_ldb_seq
*) talloc(db
, struct hdb_ldb_seq
);
907 krb5_set_error_string(context
, "talloc: out of memory");
914 priv
->realm_msgs
= NULL
;
917 mem_ctx
= talloc_named(priv
, 0, "LDB_firstkey context");
920 krb5_set_error_string(context
, "LDB_firstkey: talloc_named() failed!");
924 ret
= krb5_get_default_realm(context
, &realm
);
930 ret
= LDB_lookup_realm(context
, (struct ldb_context
*)db
->hdb_db
,
931 mem_ctx
, realm
, &realm_msgs
);
937 krb5_warnx(context
, "LDB_fetch: could not find realm\n");
938 return HDB_ERR_NOENTRY
;
941 realm_dn
= realm_msgs
[0]->dn
;
943 priv
->realm_msgs
= talloc_steal(priv
, realm_msgs
);
945 krb5_warnx(context
, "LDB_lookup_principal: realm ok\n");
947 priv
->count
= ldb_search(ldb_ctx
, realm_dn
,
948 LDB_SCOPE_SUBTREE
, "(objectClass=user)",
951 priv
->msgs
= talloc_steal(priv
, msgs
);
953 if (priv
->count
<= 0) {
955 return HDB_ERR_NOENTRY
;
958 db
->hdb_openp
= priv
;
960 ret
= LDB_seq(context
, db
, flags
, entry
);
964 db
->hdb_openp
= NULL
;
966 talloc_free(mem_ctx
);
971 static krb5_error_code
LDB_nextkey(krb5_context context
, HDB
*db
, unsigned flags
,
974 return LDB_seq(context
, db
, flags
, entry
);
977 static krb5_error_code
LDB_destroy(krb5_context context
, HDB
*db
)
983 krb5_error_code
hdb_ldb_create(krb5_context context
, struct HDB
**db
, const char *arg
)
985 *db
= talloc(NULL
, HDB
);
987 krb5_set_error_string(context
, "malloc: out of memory");
991 (*db
)->hdb_master_key_set
= 0;
992 (*db
)->hdb_db
= NULL
;
993 /* in future, we could cache the connect here, but for now KISS */
995 (*db
)->hdb_db
= samdb_connect(db
);
996 if ((*db
)->hdb_db
== NULL
) {
997 krb5_warnx(context
, "hdb_ldb_create: samdb_connect failed!");
998 krb5_set_error_string(context
, "samdb_connect failed!");
1000 return HDB_ERR_NOENTRY
;
1003 (*db
)->hdb_openp
= 0;
1004 (*db
)->hdb_open
= LDB_open
;
1005 (*db
)->hdb_close
= LDB_close
;
1006 (*db
)->hdb_fetch
= LDB_fetch
;
1007 (*db
)->hdb_store
= LDB_store
;
1008 (*db
)->hdb_remove
= LDB_remove
;
1009 (*db
)->hdb_firstkey
= LDB_firstkey
;
1010 (*db
)->hdb_nextkey
= LDB_nextkey
;
1011 (*db
)->hdb_lock
= LDB_lock
;
1012 (*db
)->hdb_unlock
= LDB_unlock
;
1013 (*db
)->hdb_rename
= LDB_rename
;
1014 /* we don't implement these, as we are not a lockable database */
1015 (*db
)->hdb__get
= NULL
;
1016 (*db
)->hdb__put
= NULL
;
1017 /* kadmin should not be used for deletes - use other tools instead */
1018 (*db
)->hdb__del
= NULL
;
1019 (*db
)->hdb_destroy
= LDB_destroy
;