2 Unix SMB/CIFS implementation.
4 Database Glue between Samba and the KDC
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 Copyright (C) Simo Sorce <idra@samba.org> 2010
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "libcli/security/security.h"
26 #include "auth/auth.h"
27 #include "auth/auth_sam.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "dsdb/common/util.h"
30 #include "librpc/gen_ndr/ndr_drsblobs.h"
31 #include "param/param.h"
32 #include "../lib/crypto/md4.h"
33 #include "system/kerberos.h"
34 #include "auth/kerberos/kerberos.h"
36 #include "kdc/samba_kdc.h"
37 #include "kdc/kdc-glue.h"
38 #include "kdc/kdc-policy.h"
39 #include "kdc/db-glue.h"
41 #define SAMBA_KVNO_GET_KRBTGT(kvno) \
42 ((uint16_t)(((uint32_t)kvno) >> 16))
44 #define SAMBA_KVNO_AND_KRBTGT(kvno, krbtgt) \
45 ((krb5_kvno)((((uint32_t)kvno) & 0xFFFF) | \
46 ((((uint32_t)krbtgt) << 16) & 0xFFFF0000)))
48 enum samba_kdc_ent_type
49 { SAMBA_KDC_ENT_TYPE_CLIENT, SAMBA_KDC_ENT_TYPE_SERVER,
50 SAMBA_KDC_ENT_TYPE_KRBTGT, SAMBA_KDC_ENT_TYPE_TRUST, SAMBA_KDC_ENT_TYPE_ANY };
52 enum trust_direction {
54 INBOUND = LSA_TRUST_DIRECTION_INBOUND,
55 OUTBOUND = LSA_TRUST_DIRECTION_OUTBOUND
58 static const char *trust_attrs[] = {
63 "msDS-SupportedEncryptionTypes",
70 static KerberosTime ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const char *attr, KerberosTime default_val)
76 gentime = ldb_msg_find_attr_as_string(msg, attr, NULL);
80 tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm);
88 static HDBFlags uf2HDBFlags(krb5_context context, uint32_t userAccountControl, enum samba_kdc_ent_type ent_type)
90 HDBFlags flags = int2HDBFlags(0);
92 /* we don't allow kadmin deletes */
95 /* mark the principal as invalid to start with */
100 /* All accounts are servers, but this may be disabled again in the caller */
103 /* Account types - clear the invalid bit if it turns out to be valid */
104 if (userAccountControl & UF_NORMAL_ACCOUNT) {
105 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
111 if (userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
112 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
117 if (userAccountControl & UF_WORKSTATION_TRUST_ACCOUNT) {
118 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
123 if (userAccountControl & UF_SERVER_TRUST_ACCOUNT) {
124 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
130 /* Not permitted to act as a client if disabled */
131 if (userAccountControl & UF_ACCOUNTDISABLE) {
134 if (userAccountControl & UF_LOCKOUT) {
138 if (userAccountControl & UF_PASSWORD_NOTREQD) {
143 UF_PASSWORD_CANT_CHANGE and UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED are irrelevent
145 if (userAccountControl & UF_TEMP_DUPLICATE_ACCOUNT) {
149 /* UF_DONT_EXPIRE_PASSWD and UF_USE_DES_KEY_ONLY handled in samba_kdc_message2entry() */
152 if (userAccountControl & UF_MNS_LOGON_ACCOUNT) {
156 if (userAccountControl & UF_SMARTCARD_REQUIRED) {
157 flags.require_hwauth = 1;
159 if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) {
160 flags.ok_as_delegate = 1;
162 if (userAccountControl & UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) {
164 * this is confusing...
166 * UF_TRUSTED_FOR_DELEGATION
171 * UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
172 * => trusted_for_delegation
174 flags.trusted_for_delegation = 1;
176 if (!(userAccountControl & UF_NOT_DELEGATED)) {
177 flags.forwardable = 1;
181 if (userAccountControl & UF_DONT_REQUIRE_PREAUTH) {
182 flags.require_preauth = 0;
184 flags.require_preauth = 1;
190 static int samba_kdc_entry_destructor(struct samba_kdc_entry *p)
192 hdb_entry_ex *entry_ex = p->entry_ex;
193 free_hdb_entry(&entry_ex->entry);
197 static void samba_kdc_free_entry(krb5_context context, hdb_entry_ex *entry_ex)
199 /* this function is called only from hdb_free_entry().
200 * Make sure we neutralize the destructor or we will
201 * get a double free later when hdb_free_entry() will
202 * try to call free_hdb_entry() */
203 talloc_set_destructor(entry_ex->ctx, NULL);
205 /* now proceed to free the talloc part */
206 talloc_free(entry_ex->ctx);
209 static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
210 struct samba_kdc_db_context *kdc_db_ctx,
212 struct ldb_message *msg,
215 uint32_t userAccountControl,
216 enum samba_kdc_ent_type ent_type,
217 hdb_entry_ex *entry_ex)
219 krb5_error_code ret = 0;
220 enum ndr_err_code ndr_err;
221 struct samr_Password *hash;
222 const struct ldb_val *sc_val;
223 struct supplementalCredentialsBlob scb;
224 struct supplementalCredentialsPackage *scpk = NULL;
225 bool newer_keys = false;
226 struct package_PrimaryKerberosBlob _pkb;
227 struct package_PrimaryKerberosCtr3 *pkb3 = NULL;
228 struct package_PrimaryKerberosCtr4 *pkb4 = NULL;
230 uint16_t allocated_keys = 0;
231 int rodc_krbtgt_number = 0;
233 uint32_t supported_enctypes
234 = ldb_msg_find_attr_as_uint(msg,
235 "msDS-SupportedEncryptionTypes",
238 if (rid == DOMAIN_RID_KRBTGT || is_rodc) {
239 /* KDCs (and KDCs on RODCs) use AES */
240 supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
241 } else if (userAccountControl & (UF_PARTIAL_SECRETS_ACCOUNT|UF_SERVER_TRUST_ACCOUNT)) {
242 /* DCs and RODCs comptuer accounts use AES */
243 supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
244 } else if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT ||
245 (ent_type == SAMBA_KDC_ENT_TYPE_ANY)) {
246 /* for AS-REQ the client chooses the enc types it
247 * supports, and this will vary between computers a
250 * likewise for 'any' return as much as is supported,
251 * to export into a keytab */
252 supported_enctypes = ENC_ALL_TYPES;
255 /* If UF_USE_DES_KEY_ONLY has been set, then don't allow use of the newer enc types */
256 if (userAccountControl & UF_USE_DES_KEY_ONLY) {
257 supported_enctypes = ENC_CRC32|ENC_RSA_MD5;
259 /* Otherwise, add in the default enc types */
260 supported_enctypes |= ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
263 /* Is this the krbtgt or a RODC krbtgt */
265 rodc_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
267 if (rodc_krbtgt_number == -1) {
272 entry_ex->entry.keys.val = NULL;
273 entry_ex->entry.keys.len = 0;
275 kvno = ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0);
277 kvno = SAMBA_KVNO_AND_KRBTGT(kvno, rodc_krbtgt_number);
279 entry_ex->entry.kvno = kvno;
281 /* Get keys from the db */
283 hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
284 sc_val = ldb_msg_find_ldb_val(msg, "supplementalCredentials");
286 /* unicodePwd for enctype 0x17 (23) if present */
291 /* supplementalCredentials if present */
293 ndr_err = ndr_pull_struct_blob_all(sc_val, mem_ctx, &scb,
294 (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
295 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
296 dump_data(0, sc_val->data, sc_val->length);
301 if (scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
302 NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
307 for (i=0; i < scb.sub.num_packages; i++) {
308 if (strcmp("Primary:Kerberos-Newer-Keys", scb.sub.packages[i].name) == 0) {
309 scpk = &scb.sub.packages[i];
310 if (!scpk->data || !scpk->data[0]) {
316 } else if (strcmp("Primary:Kerberos", scb.sub.packages[i].name) == 0) {
317 scpk = &scb.sub.packages[i];
318 if (!scpk->data || !scpk->data[0]) {
322 * we don't break here in hope to find
323 * a Kerberos-Newer-Keys package
329 * Primary:Kerberos-Newer-Keys or Primary:Kerberos element
330 * of supplementalCredentials
335 blob = strhex_to_data_blob(mem_ctx, scpk->data);
341 /* we cannot use ndr_pull_struct_blob_all() here, as w2k and w2k3 add padding bytes */
342 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &_pkb,
343 (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
344 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
346 krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: could not parse package_PrimaryKerberosBlob");
347 krb5_warnx(context, "samba_kdc_message2entry_keys: could not parse package_PrimaryKerberosBlob");
351 if (newer_keys && _pkb.version != 4) {
353 krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4");
354 krb5_warnx(context, "samba_kdc_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4");
358 if (!newer_keys && _pkb.version != 3) {
360 krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: could not parse Primary:Kerberos not version 3");
361 krb5_warnx(context, "samba_kdc_message2entry_keys: could not parse Primary:Kerberos not version 3");
365 if (_pkb.version == 4) {
366 pkb4 = &_pkb.ctr.ctr4;
367 allocated_keys += pkb4->num_keys;
368 } else if (_pkb.version == 3) {
369 pkb3 = &_pkb.ctr.ctr3;
370 allocated_keys += pkb3->num_keys;
374 if (allocated_keys == 0) {
375 if (kdc_db_ctx->rodc) {
376 /* We are on an RODC, but don't have keys for this account. Signal this to the caller */
377 return HDB_ERR_NOT_FOUND_HERE;
380 /* oh, no password. Apparently (comment in
381 * hdb-ldap.c) this violates the ASN.1, but this
382 * allows an entry with no keys (yet). */
386 /* allocate space to decode into */
387 entry_ex->entry.keys.len = 0;
388 entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(Key));
389 if (entry_ex->entry.keys.val == NULL) {
394 if (hash && (supported_enctypes & ENC_RC4_HMAC_MD5)) {
398 key.salt = NULL; /* No salt for this enc type */
400 ret = krb5_keyblock_init(context,
401 ENCTYPE_ARCFOUR_HMAC,
402 hash->hash, sizeof(hash->hash),
408 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
409 entry_ex->entry.keys.len++;
413 for (i=0; i < pkb4->num_keys; i++) {
416 if (!pkb4->keys[i].value) continue;
418 if (!(kerberos_enctype_to_bitmap(pkb4->keys[i].keytype) & supported_enctypes)) {
425 if (pkb4->salt.string) {
428 salt = data_blob_string_const(pkb4->salt.string);
430 key.salt = calloc(1, sizeof(*key.salt));
431 if (key.salt == NULL) {
436 key.salt->type = hdb_pw_salt;
438 ret = krb5_data_copy(&key.salt->salt, salt.data, salt.length);
446 /* TODO: maybe pass the iteration_count somehow... */
448 ret = krb5_keyblock_init(context,
449 pkb4->keys[i].keytype,
450 pkb4->keys[i].value->data,
451 pkb4->keys[i].value->length,
453 if (ret == KRB5_PROG_ETYPE_NOSUPP) {
454 DEBUG(2,("Unsupported keytype ignored - type %u\n",
455 pkb4->keys[i].keytype));
468 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
469 entry_ex->entry.keys.len++;
472 for (i=0; i < pkb3->num_keys; i++) {
475 if (!pkb3->keys[i].value) continue;
477 if (!(kerberos_enctype_to_bitmap(pkb3->keys[i].keytype) & supported_enctypes)) {
484 if (pkb3->salt.string) {
487 salt = data_blob_string_const(pkb3->salt.string);
489 key.salt = calloc(1, sizeof(*key.salt));
490 if (key.salt == NULL) {
495 key.salt->type = hdb_pw_salt;
497 ret = krb5_data_copy(&key.salt->salt, salt.data, salt.length);
505 ret = krb5_keyblock_init(context,
506 pkb3->keys[i].keytype,
507 pkb3->keys[i].value->data,
508 pkb3->keys[i].value->length,
519 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
520 entry_ex->entry.keys.len++;
526 entry_ex->entry.keys.len = 0;
528 if (entry_ex->entry.keys.len == 0 && entry_ex->entry.keys.val) {
529 free(entry_ex->entry.keys.val);
530 entry_ex->entry.keys.val = NULL;
536 * Construct an hdb_entry from a directory entry.
538 static krb5_error_code samba_kdc_message2entry(krb5_context context,
539 struct samba_kdc_db_context *kdc_db_ctx,
540 TALLOC_CTX *mem_ctx, krb5_const_principal principal,
541 enum samba_kdc_ent_type ent_type,
543 struct ldb_dn *realm_dn,
544 struct ldb_message *msg,
545 hdb_entry_ex *entry_ex)
547 struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
548 uint32_t userAccountControl;
550 krb5_error_code ret = 0;
551 krb5_boolean is_computer = FALSE;
553 struct samba_kdc_entry *p;
558 bool is_rodc = false;
559 struct ldb_message_element *objectclasses;
560 struct ldb_val computer_val;
561 const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
562 computer_val.data = discard_const_p(uint8_t,"computer");
563 computer_val.length = strlen((const char *)computer_val.data);
565 if (ldb_msg_find_element(msg, "msDS-SecondaryKrbTgtNumber")) {
569 if (!samAccountName) {
571 krb5_set_error_message(context, ret, "samba_kdc_message2entry: no samAccountName present");
575 objectclasses = ldb_msg_find_element(msg, "objectClass");
577 if (objectclasses && ldb_msg_find_val(objectclasses, &computer_val)) {
581 memset(entry_ex, 0, sizeof(*entry_ex));
583 p = talloc(mem_ctx, struct samba_kdc_entry);
589 p->kdc_db_ctx = kdc_db_ctx;
590 p->entry_ex = entry_ex;
591 p->realm_dn = talloc_reference(p, realm_dn);
597 talloc_set_destructor(p, samba_kdc_entry_destructor);
599 /* make sure we do not have bogus data in there */
600 memset(&entry_ex->entry, 0, sizeof(hdb_entry));
603 entry_ex->free_entry = samba_kdc_free_entry;
605 userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
608 entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal)));
609 if (ent_type == SAMBA_KDC_ENT_TYPE_ANY && principal == NULL) {
610 krb5_make_principal(context, &entry_ex->entry.principal, lpcfg_realm(lp_ctx), samAccountName, NULL);
612 ret = copy_Principal(principal, entry_ex->entry.principal);
614 krb5_clear_error_message(context);
618 /* While we have copied the client principal, tests
619 * show that Win2k3 returns the 'corrected' realm, not
620 * the client-specified realm. This code attempts to
621 * replace the client principal's realm with the one
622 * we determine from our records */
624 /* this has to be with malloc() */
625 krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
628 /* First try and figure out the flags based on the userAccountControl */
629 entry_ex->entry.flags = uf2HDBFlags(context, userAccountControl, ent_type);
631 /* Windows 2008 seems to enforce this (very sensible) rule by
632 * default - don't allow offline attacks on a user's password
633 * by asking for a ticket to them as a service (encrypted with
634 * their probably patheticly insecure password) */
636 if (entry_ex->entry.flags.server
637 && lpcfg_parm_bool(lp_ctx, NULL, "kdc", "require spn for service", true)) {
638 if (!is_computer && !ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL)) {
639 entry_ex->entry.flags.server = 0;
643 if (flags & HDB_F_ADMIN_DATA) {
644 /* These (created_by, modified_by) parts of the entry are not relevant for Samba4's use
645 * of the Heimdal KDC. They are stored in a the traditional
646 * DB for audit purposes, and still form part of the structure
649 /* use 'whenCreated' */
650 entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
651 /* use 'kadmin' for now (needed by mit_samba) */
652 krb5_make_principal(context,
653 &entry_ex->entry.created_by.principal,
654 lpcfg_realm(lp_ctx), "kadmin", NULL);
656 entry_ex->entry.modified_by = (Event *) malloc(sizeof(Event));
657 if (entry_ex->entry.modified_by == NULL) {
659 krb5_set_error_message(context, ret, "malloc: out of memory");
663 /* use 'whenChanged' */
664 entry_ex->entry.modified_by->time = ldb_msg_find_krb5time_ldap_time(msg, "whenChanged", 0);
665 /* use 'kadmin' for now (needed by mit_samba) */
666 krb5_make_principal(context,
667 &entry_ex->entry.modified_by->principal,
668 lpcfg_realm(lp_ctx), "kadmin", NULL);
672 /* The lack of password controls etc applies to krbtgt by
673 * virtue of being that particular RID */
674 status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, msg, "objectSid"), NULL, &rid);
676 if (!NT_STATUS_IS_OK(status)) {
681 if (rid == DOMAIN_RID_KRBTGT) {
682 entry_ex->entry.valid_end = NULL;
683 entry_ex->entry.pw_end = NULL;
685 entry_ex->entry.flags.invalid = 0;
686 entry_ex->entry.flags.server = 1;
688 /* Don't mark all requests for the krbtgt/realm as
689 * 'change password', as otherwise we could get into
690 * trouble, and not enforce the password expirty.
691 * Instead, only do it when request is for the kpasswd service */
692 if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER
693 && principal->name.name_string.len == 2
694 && (strcmp(principal->name.name_string.val[0], "kadmin") == 0)
695 && (strcmp(principal->name.name_string.val[1], "changepw") == 0)
696 && lpcfg_is_my_domain_or_realm(lp_ctx, principal->realm)) {
697 entry_ex->entry.flags.change_pw = 1;
699 entry_ex->entry.flags.client = 0;
700 entry_ex->entry.flags.forwardable = 1;
701 entry_ex->entry.flags.ok_as_delegate = 1;
702 } else if (is_rodc) {
703 /* The RODC krbtgt account is like the main krbtgt,
704 * but it does not have a changepw or kadmin
707 entry_ex->entry.valid_end = NULL;
708 entry_ex->entry.pw_end = NULL;
710 /* Also don't allow the RODC krbtgt to be a client (it should not be needed) */
711 entry_ex->entry.flags.client = 0;
712 entry_ex->entry.flags.invalid = 0;
713 entry_ex->entry.flags.server = 1;
715 entry_ex->entry.flags.client = 0;
716 entry_ex->entry.flags.forwardable = 1;
717 entry_ex->entry.flags.ok_as_delegate = 0;
718 } else if (entry_ex->entry.flags.server && ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
719 /* The account/password expiry only applies when the account is used as a
720 * client (ie password login), not when used as a server */
722 /* Make very well sure we don't use this for a client,
723 * it could bypass the password restrictions */
724 entry_ex->entry.flags.client = 0;
726 entry_ex->entry.valid_end = NULL;
727 entry_ex->entry.pw_end = NULL;
730 NTTIME must_change_time
731 = samdb_result_force_password_change(kdc_db_ctx->samdb, mem_ctx,
733 if (must_change_time == 0x7FFFFFFFFFFFFFFFULL) {
734 entry_ex->entry.pw_end = NULL;
736 entry_ex->entry.pw_end = malloc(sizeof(*entry_ex->entry.pw_end));
737 if (entry_ex->entry.pw_end == NULL) {
741 *entry_ex->entry.pw_end = nt_time_to_unix(must_change_time);
744 acct_expiry = samdb_result_account_expires(msg);
745 if (acct_expiry == 0x7FFFFFFFFFFFFFFFULL) {
746 entry_ex->entry.valid_end = NULL;
748 entry_ex->entry.valid_end = malloc(sizeof(*entry_ex->entry.valid_end));
749 if (entry_ex->entry.valid_end == NULL) {
753 *entry_ex->entry.valid_end = nt_time_to_unix(acct_expiry);
757 entry_ex->entry.valid_start = NULL;
759 entry_ex->entry.max_life = malloc(sizeof(*entry_ex->entry.max_life));
760 if (entry_ex->entry.max_life == NULL) {
765 if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
766 *entry_ex->entry.max_life = nt_time_to_unix(kdc_db_ctx->policy.service_tkt_lifetime);
767 } else if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT || ent_type == SAMBA_KDC_ENT_TYPE_CLIENT) {
768 *entry_ex->entry.max_life = nt_time_to_unix(kdc_db_ctx->policy.user_tkt_lifetime);
770 *entry_ex->entry.max_life = MIN(nt_time_to_unix(kdc_db_ctx->policy.service_tkt_lifetime),
771 nt_time_to_unix(kdc_db_ctx->policy.user_tkt_lifetime));
774 entry_ex->entry.max_renew = malloc(sizeof(*entry_ex->entry.max_life));
775 if (entry_ex->entry.max_renew == NULL) {
780 *entry_ex->entry.max_renew = nt_time_to_unix(kdc_db_ctx->policy.user_tkt_renewaltime);
782 entry_ex->entry.generation = NULL;
784 /* Get keys from the db */
785 ret = samba_kdc_message2entry_keys(context, kdc_db_ctx, p, msg,
786 rid, is_rodc, userAccountControl,
789 /* Could be bougus data in the entry, or out of memory */
793 entry_ex->entry.etypes = malloc(sizeof(*(entry_ex->entry.etypes)));
794 if (entry_ex->entry.etypes == NULL) {
795 krb5_clear_error_message(context);
799 entry_ex->entry.etypes->len = entry_ex->entry.keys.len;
800 entry_ex->entry.etypes->val = calloc(entry_ex->entry.etypes->len, sizeof(int));
801 if (entry_ex->entry.etypes->val == NULL) {
802 krb5_clear_error_message(context);
806 for (i=0; i < entry_ex->entry.etypes->len; i++) {
807 entry_ex->entry.etypes->val[i] = entry_ex->entry.keys.val[i].key.keytype;
811 p->msg = talloc_steal(p, msg);
815 /* This doesn't free ent itself, that is for the eventual caller to do */
816 hdb_free_entry(context, entry_ex);
818 talloc_steal(kdc_db_ctx, entry_ex->ctx);
825 * Construct an hdb_entry from a directory entry.
827 static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
828 struct samba_kdc_db_context *kdc_db_ctx,
829 TALLOC_CTX *mem_ctx, krb5_const_principal principal,
830 enum trust_direction direction,
831 struct ldb_dn *realm_dn,
832 struct ldb_message *msg,
833 hdb_entry_ex *entry_ex)
835 struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
836 const char *dnsdomain;
837 const char *realm = lpcfg_realm(lp_ctx);
838 DATA_BLOB password_utf16;
839 struct samr_Password password_hash;
840 const struct ldb_val *password_val;
841 struct trustAuthInOutBlob password_blob;
842 struct samba_kdc_entry *p;
844 enum ndr_err_code ndr_err;
845 int ret, trust_direction_flags;
848 p = talloc(mem_ctx, struct samba_kdc_entry);
854 p->kdc_db_ctx = kdc_db_ctx;
855 p->entry_ex = entry_ex;
856 p->realm_dn = realm_dn;
858 talloc_set_destructor(p, samba_kdc_entry_destructor);
860 /* make sure we do not have bogus data in there */
861 memset(&entry_ex->entry, 0, sizeof(hdb_entry));
864 entry_ex->free_entry = samba_kdc_free_entry;
866 /* use 'whenCreated' */
867 entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
868 /* use 'kadmin' for now (needed by mit_samba) */
869 krb5_make_principal(context,
870 &entry_ex->entry.created_by.principal,
871 realm, "kadmin", NULL);
873 entry_ex->entry.valid_start = NULL;
875 trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
877 if (direction == INBOUND) {
878 password_val = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
880 } else { /* OUTBOUND */
881 dnsdomain = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
883 realm = strupper_talloc(mem_ctx, dnsdomain);
884 password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
887 if (!password_val || !(trust_direction_flags & direction)) {
892 ndr_err = ndr_pull_struct_blob(password_val, mem_ctx, &password_blob,
893 (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
894 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
899 entry_ex->entry.kvno = 0;
901 we usually don't have a TRUST_AUTH_TYPE_VERSION field, as
902 windows doesn't create one, so we rely on the fact that both
903 windows and Samba don't actually check the kvno and instead
904 just check against the latest password blob. If we do have a
905 TRUST_AUTH_TYPE_VERSION field then we do use it, otherwise
908 for (i=0; i < password_blob.count; i++) {
909 if (password_blob.current.array[i].AuthType == TRUST_AUTH_TYPE_VERSION) {
910 entry_ex->entry.kvno = password_blob.current.array[i].AuthInfo.version.version;
914 for (i=0; i < password_blob.count; i++) {
915 if (password_blob.current.array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
916 password_utf16 = data_blob_const(password_blob.current.array[i].AuthInfo.clear.password,
917 password_blob.current.array[i].AuthInfo.clear.size);
918 /* In the future, generate all sorts of
919 * hashes, but for now we can't safely convert
920 * the random strings windows uses into
923 /* but as it is utf16 already, we can get the NT password/arcfour-hmac-md5 key */
924 mdfour(password_hash.hash, password_utf16.data, password_utf16.length);
926 } else if (password_blob.current.array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
927 password_hash = password_blob.current.array[i].AuthInfo.nt4owf.password;
932 if (i < password_blob.count) {
934 /* Must have found a cleartext or MD4 password */
935 entry_ex->entry.keys.val = calloc(1, sizeof(Key));
938 key.salt = NULL; /* No salt for this enc type */
940 if (entry_ex->entry.keys.val == NULL) {
945 ret = krb5_keyblock_init(context,
946 ENCTYPE_ARCFOUR_HMAC,
947 password_hash.hash, sizeof(password_hash.hash),
950 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
951 entry_ex->entry.keys.len++;
954 entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal)));
956 ret = copy_Principal(principal, entry_ex->entry.principal);
958 krb5_clear_error_message(context);
962 /* While we have copied the client principal, tests
963 * show that Win2k3 returns the 'corrected' realm, not
964 * the client-specified realm. This code attempts to
965 * replace the client principal's realm with the one
966 * we determine from our records */
968 krb5_principal_set_realm(context, entry_ex->entry.principal, realm);
969 entry_ex->entry.flags = int2HDBFlags(0);
970 entry_ex->entry.flags.immutable = 1;
971 entry_ex->entry.flags.invalid = 0;
972 entry_ex->entry.flags.server = 1;
973 entry_ex->entry.flags.require_preauth = 1;
975 entry_ex->entry.pw_end = NULL;
977 entry_ex->entry.max_life = NULL;
979 entry_ex->entry.max_renew = NULL;
981 entry_ex->entry.generation = NULL;
983 entry_ex->entry.etypes = malloc(sizeof(*(entry_ex->entry.etypes)));
984 if (entry_ex->entry.etypes == NULL) {
985 krb5_clear_error_message(context);
989 entry_ex->entry.etypes->len = entry_ex->entry.keys.len;
990 entry_ex->entry.etypes->val = calloc(entry_ex->entry.etypes->len, sizeof(int));
991 if (entry_ex->entry.etypes->val == NULL) {
992 krb5_clear_error_message(context);
996 for (i=0; i < entry_ex->entry.etypes->len; i++) {
997 entry_ex->entry.etypes->val[i] = entry_ex->entry.keys.val[i].key.keytype;
1001 p->msg = talloc_steal(p, msg);
1005 /* This doesn't free ent itself, that is for the eventual caller to do */
1006 hdb_free_entry(context, entry_ex);
1008 talloc_steal(kdc_db_ctx, entry_ex->ctx);
1015 static krb5_error_code samba_kdc_lookup_trust(krb5_context context, struct ldb_context *ldb_ctx,
1016 TALLOC_CTX *mem_ctx,
1018 struct ldb_dn *realm_dn,
1019 struct ldb_message **pmsg)
1022 krb5_error_code ret;
1023 char *filter = NULL;
1024 const char * const *attrs = trust_attrs;
1026 struct ldb_result *res = NULL;
1027 char *realm_encoded = ldb_binary_encode_string(mem_ctx, realm);
1028 if (!realm_encoded) {
1031 krb5_set_error_message(context, ret, "talloc_asprintf: out of memory");
1035 filter = talloc_asprintf(mem_ctx, "(&(objectClass=trustedDomain)(|(flatname=%s)(trustPartner=%s)))",
1036 realm_encoded, realm_encoded);
1039 talloc_free(realm_encoded);
1041 krb5_set_error_message(context, ret, "talloc_asprintf: out of memory");
1045 lret = ldb_search(ldb_ctx, mem_ctx, &res,
1046 ldb_get_default_basedn(ldb_ctx),
1047 LDB_SCOPE_SUBTREE, attrs, "%s", filter);
1048 if (lret != LDB_SUCCESS) {
1049 DEBUG(3, ("Failed to search for %s: %s\n", filter, ldb_errstring(ldb_ctx)));
1050 return HDB_ERR_NOENTRY;
1051 } else if (res->count == 0 || res->count > 1) {
1052 DEBUG(3, ("Failed find a single entry for %s: got %d\n", filter, res->count));
1054 return HDB_ERR_NOENTRY;
1056 talloc_steal(mem_ctx, res->msgs);
1057 *pmsg = res->msgs[0];
1062 static krb5_error_code samba_kdc_lookup_client(krb5_context context,
1063 struct samba_kdc_db_context *kdc_db_ctx,
1064 TALLOC_CTX *mem_ctx,
1065 krb5_const_principal principal,
1067 struct ldb_dn **realm_dn,
1068 struct ldb_message **msg) {
1070 char *principal_string;
1071 krb5_error_code ret;
1073 ret = krb5_unparse_name(context, principal, &principal_string);
1079 nt_status = sam_get_results_principal(kdc_db_ctx->samdb,
1080 mem_ctx, principal_string, attrs,
1082 free(principal_string);
1083 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
1084 return HDB_ERR_NOENTRY;
1085 } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
1087 } else if (!NT_STATUS_IS_OK(nt_status)) {
1094 static krb5_error_code samba_kdc_fetch_client(krb5_context context,
1095 struct samba_kdc_db_context *kdc_db_ctx,
1096 TALLOC_CTX *mem_ctx,
1097 krb5_const_principal principal,
1099 hdb_entry_ex *entry_ex) {
1100 struct ldb_dn *realm_dn;
1101 krb5_error_code ret;
1102 struct ldb_message *msg = NULL;
1104 ret = samba_kdc_lookup_client(context, kdc_db_ctx,
1105 mem_ctx, principal, user_attrs,
1111 ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1112 principal, SAMBA_KDC_ENT_TYPE_CLIENT,
1114 realm_dn, msg, entry_ex);
1118 static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
1119 struct samba_kdc_db_context *kdc_db_ctx,
1120 TALLOC_CTX *mem_ctx,
1121 krb5_const_principal principal,
1123 uint32_t krbtgt_number,
1124 hdb_entry_ex *entry_ex)
1126 struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
1127 krb5_error_code ret;
1128 struct ldb_message *msg = NULL;
1129 struct ldb_dn *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
1131 krb5_principal alloc_principal = NULL;
1132 if (principal->name.name_string.len != 2
1133 || (strcmp(principal->name.name_string.val[0], KRB5_TGS_NAME) != 0)) {
1135 return HDB_ERR_NOENTRY;
1138 /* krbtgt case. Either us or a trusted realm */
1140 if (lpcfg_is_my_domain_or_realm(lp_ctx, principal->realm)
1141 && lpcfg_is_my_domain_or_realm(lp_ctx, principal->name.name_string.val[1])) {
1142 /* us, or someone quite like us */
1143 /* Cludge, cludge cludge. If the realm part of krbtgt/realm,
1144 * is in our db, then direct the caller at our primary
1149 if (krbtgt_number == kdc_db_ctx->my_krbtgt_number) {
1150 lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx,
1151 &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
1153 "(objectClass=user)");
1155 /* We need to look up an RODC krbtgt (perhaps
1156 * ours, if we are an RODC, perhaps another
1157 * RODC if we are a read-write DC */
1158 lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx,
1159 &msg, realm_dn, LDB_SCOPE_SUBTREE,
1161 DSDB_SEARCH_SHOW_EXTENDED_DN,
1162 "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=%u))", (unsigned)(krbtgt_number));
1165 if (lret == LDB_ERR_NO_SUCH_OBJECT) {
1166 krb5_warnx(context, "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1167 (unsigned)(krbtgt_number));
1168 krb5_set_error_message(context, HDB_ERR_NOENTRY,
1169 "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1170 (unsigned)(krbtgt_number));
1171 return HDB_ERR_NOENTRY;
1172 } else if (lret != LDB_SUCCESS) {
1173 krb5_warnx(context, "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1174 (unsigned)(krbtgt_number));
1175 krb5_set_error_message(context, HDB_ERR_NOENTRY,
1176 "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1177 (unsigned)(krbtgt_number));
1178 return HDB_ERR_NOENTRY;
1182 * Windows seems to canonicalize the principal
1183 * in a TGS REP even if the client did not specify
1184 * the canonicalize flag.
1186 if (flags & (HDB_F_CANON|HDB_F_FOR_TGS_REQ)) {
1187 ret = krb5_copy_principal(context, principal, &alloc_principal);
1192 /* When requested to do so, ensure that the
1193 * both realm values in the principal are set
1194 * to the upper case, canonical realm */
1195 free(alloc_principal->name.name_string.val[1]);
1196 alloc_principal->name.name_string.val[1] = strdup(lpcfg_realm(lp_ctx));
1197 if (!alloc_principal->name.name_string.val[1]) {
1199 krb5_set_error_message(context, ret, "samba_kdc_fetch: strdup() failed!");
1202 principal = alloc_principal;
1205 ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1206 principal, SAMBA_KDC_ENT_TYPE_KRBTGT,
1207 flags, realm_dn, msg, entry_ex);
1208 if (alloc_principal) {
1209 /* This is again copied in the message2entry call */
1210 krb5_free_principal(context, alloc_principal);
1213 krb5_warnx(context, "samba_kdc_fetch: self krbtgt message2entry failed");
1218 enum trust_direction direction = UNKNOWN;
1219 const char *realm = NULL;
1221 /* Either an inbound or outbound trust */
1223 if (strcasecmp(lpcfg_realm(lp_ctx), principal->realm) == 0) {
1224 /* look for inbound trust */
1225 direction = INBOUND;
1226 realm = principal->name.name_string.val[1];
1227 } else if (strcasecmp(lpcfg_realm(lp_ctx), principal->name.name_string.val[1]) == 0) {
1228 /* look for outbound trust */
1229 direction = OUTBOUND;
1230 realm = principal->realm;
1232 krb5_warnx(context, "samba_kdc_fetch: not our realm for trusts ('%s', '%s')",
1233 principal->realm, principal->name.name_string.val[1]);
1234 krb5_set_error_message(context, HDB_ERR_NOENTRY, "samba_kdc_fetch: not our realm for trusts ('%s', '%s')",
1235 principal->realm, principal->name.name_string.val[1]);
1236 return HDB_ERR_NOENTRY;
1239 /* Trusted domains are under CN=system */
1241 ret = samba_kdc_lookup_trust(context, kdc_db_ctx->samdb,
1243 realm, realm_dn, &msg);
1246 krb5_warnx(context, "samba_kdc_fetch: could not find principal in DB");
1247 krb5_set_error_message(context, ret, "samba_kdc_fetch: could not find principal in DB");
1251 ret = samba_kdc_trust_message2entry(context, kdc_db_ctx, mem_ctx,
1252 principal, direction,
1253 realm_dn, msg, entry_ex);
1255 krb5_warnx(context, "samba_kdc_fetch: trust_message2entry failed");
1262 static krb5_error_code samba_kdc_lookup_server(krb5_context context,
1263 struct samba_kdc_db_context *kdc_db_ctx,
1264 TALLOC_CTX *mem_ctx,
1265 krb5_const_principal principal,
1267 struct ldb_dn **realm_dn,
1268 struct ldb_message **msg)
1270 krb5_error_code ret;
1271 if (principal->name.name_string.len >= 2) {
1272 /* 'normal server' case */
1275 struct ldb_dn *user_dn;
1276 char *principal_string;
1278 ret = krb5_unparse_name_flags(context, principal,
1279 KRB5_PRINCIPAL_UNPARSE_NO_REALM,
1285 /* At this point we may find the host is known to be
1286 * in a different realm, so we should generate a
1287 * referral instead */
1288 nt_status = crack_service_principal_name(kdc_db_ctx->samdb,
1289 mem_ctx, principal_string,
1290 &user_dn, realm_dn);
1291 free(principal_string);
1293 if (!NT_STATUS_IS_OK(nt_status)) {
1294 return HDB_ERR_NOENTRY;
1297 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb,
1299 msg, user_dn, LDB_SCOPE_BASE,
1301 DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
1303 if (ldb_ret != LDB_SUCCESS) {
1304 return HDB_ERR_NOENTRY;
1309 char *filter = NULL;
1312 /* server as client principal case, but we must not lookup userPrincipalNames */
1313 *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
1314 realm = krb5_principal_get_realm(context, principal);
1316 /* TODO: Check if it is our realm, otherwise give referral */
1318 ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &short_princ);
1321 krb5_set_error_message(context, ret, "samba_kdc_lookup_principal: could not parse principal");
1322 krb5_warnx(context, "samba_kdc_lookup_principal: could not parse principal");
1326 lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx, msg,
1327 *realm_dn, LDB_SCOPE_SUBTREE,
1329 DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
1330 "(&(objectClass=user)(samAccountName=%s))",
1331 ldb_binary_encode_string(mem_ctx, short_princ));
1333 if (lret == LDB_ERR_NO_SUCH_OBJECT) {
1334 DEBUG(3, ("Failed find a entry for %s\n", filter));
1335 return HDB_ERR_NOENTRY;
1337 if (lret != LDB_SUCCESS) {
1338 DEBUG(3, ("Failed single search for for %s - %s\n",
1339 filter, ldb_errstring(kdc_db_ctx->samdb)));
1340 return HDB_ERR_NOENTRY;
1347 static krb5_error_code samba_kdc_fetch_server(krb5_context context,
1348 struct samba_kdc_db_context *kdc_db_ctx,
1349 TALLOC_CTX *mem_ctx,
1350 krb5_const_principal principal,
1352 hdb_entry_ex *entry_ex)
1354 krb5_error_code ret;
1355 struct ldb_dn *realm_dn;
1356 struct ldb_message *msg;
1358 ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, principal,
1359 server_attrs, &realm_dn, &msg);
1364 ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1365 principal, SAMBA_KDC_ENT_TYPE_SERVER,
1367 realm_dn, msg, entry_ex);
1369 krb5_warnx(context, "samba_kdc_fetch: message2entry failed");
1375 krb5_error_code samba_kdc_fetch(krb5_context context,
1376 struct samba_kdc_db_context *kdc_db_ctx,
1377 krb5_const_principal principal,
1380 hdb_entry_ex *entry_ex)
1382 krb5_error_code ret = HDB_ERR_NOENTRY;
1383 TALLOC_CTX *mem_ctx;
1384 unsigned int krbtgt_number;
1385 /* w2k8r2 sometimes gives us a kvno of 255 for inter-domain
1386 trust tickets. We don't yet know what this means, but we do
1387 seem to need to treat it as unspecified */
1388 if ((flags & HDB_F_KVNO_SPECIFIED) && kvno != 255) {
1389 krbtgt_number = SAMBA_KVNO_GET_KRBTGT(kvno);
1390 if (kdc_db_ctx->rodc) {
1391 if (krbtgt_number != kdc_db_ctx->my_krbtgt_number) {
1392 return HDB_ERR_NOT_FOUND_HERE;
1396 krbtgt_number = kdc_db_ctx->my_krbtgt_number;
1399 mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
1402 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1406 if (flags & HDB_F_GET_CLIENT) {
1407 ret = samba_kdc_fetch_client(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
1408 if (ret != HDB_ERR_NOENTRY) goto done;
1410 if (flags & HDB_F_GET_SERVER) {
1411 /* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
1412 ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, krbtgt_number, entry_ex);
1413 if (ret != HDB_ERR_NOENTRY) goto done;
1415 /* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
1416 ret = samba_kdc_fetch_server(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
1417 if (ret != HDB_ERR_NOENTRY) goto done;
1419 if (flags & HDB_F_GET_KRBTGT) {
1420 ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, krbtgt_number, entry_ex);
1421 if (ret != HDB_ERR_NOENTRY) goto done;
1425 talloc_free(mem_ctx);
1429 struct samba_kdc_seq {
1432 struct ldb_message **msgs;
1433 struct ldb_dn *realm_dn;
1436 static krb5_error_code samba_kdc_seq(krb5_context context,
1437 struct samba_kdc_db_context *kdc_db_ctx,
1438 hdb_entry_ex *entry)
1440 krb5_error_code ret;
1441 struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
1442 TALLOC_CTX *mem_ctx;
1443 hdb_entry_ex entry_ex;
1444 memset(&entry_ex, '\0', sizeof(entry_ex));
1447 return HDB_ERR_NOENTRY;
1450 mem_ctx = talloc_named(priv, 0, "samba_kdc_seq context");
1454 krb5_set_error_message(context, ret, "samba_kdc_seq: talloc_named() failed!");
1458 if (priv->index < priv->count) {
1459 ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1460 NULL, SAMBA_KDC_ENT_TYPE_ANY,
1461 HDB_F_ADMIN_DATA|HDB_F_GET_ANY,
1462 priv->realm_dn, priv->msgs[priv->index++], entry);
1464 ret = HDB_ERR_NOENTRY;
1469 kdc_db_ctx->seq_ctx = NULL;
1471 talloc_free(mem_ctx);
1477 krb5_error_code samba_kdc_firstkey(krb5_context context,
1478 struct samba_kdc_db_context *kdc_db_ctx,
1479 hdb_entry_ex *entry)
1481 struct ldb_context *ldb_ctx = kdc_db_ctx->samdb;
1482 struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
1484 struct ldb_result *res = NULL;
1485 krb5_error_code ret;
1486 TALLOC_CTX *mem_ctx;
1491 kdc_db_ctx->seq_ctx = NULL;
1494 priv = (struct samba_kdc_seq *) talloc(kdc_db_ctx, struct samba_kdc_seq);
1497 krb5_set_error_message(context, ret, "talloc: out of memory");
1503 priv->realm_dn = ldb_get_default_basedn(ldb_ctx);
1506 mem_ctx = talloc_named(priv, 0, "samba_kdc_firstkey context");
1510 krb5_set_error_message(context, ret, "samba_kdc_firstkey: talloc_named() failed!");
1514 ret = krb5_get_default_realm(context, &realm);
1520 lret = ldb_search(ldb_ctx, priv, &res,
1521 priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs,
1522 "(objectClass=user)");
1524 if (lret != LDB_SUCCESS) {
1526 return HDB_ERR_NOENTRY;
1529 priv->count = res->count;
1530 priv->msgs = talloc_steal(priv, res->msgs);
1533 kdc_db_ctx->seq_ctx = priv;
1535 ret = samba_kdc_seq(context, kdc_db_ctx, entry);
1539 kdc_db_ctx->seq_ctx = NULL;
1541 talloc_free(mem_ctx);
1546 krb5_error_code samba_kdc_nextkey(krb5_context context,
1547 struct samba_kdc_db_context *kdc_db_ctx,
1548 hdb_entry_ex *entry)
1550 return samba_kdc_seq(context, kdc_db_ctx, entry);
1553 /* Check if a given entry may delegate or do s4u2self to this target principal
1555 * This is currently a very nasty hack - allowing only delegation to itself.
1558 samba_kdc_check_s4u2self(krb5_context context,
1559 struct samba_kdc_db_context *kdc_db_ctx,
1560 hdb_entry_ex *entry,
1561 krb5_const_principal target_principal)
1563 krb5_error_code ret;
1564 krb5_principal enterprise_prinicpal = NULL;
1565 struct ldb_dn *realm_dn;
1566 struct ldb_message *msg;
1567 struct dom_sid *orig_sid;
1568 struct dom_sid *target_sid;
1569 struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1570 const char *delegation_check_attrs[] = {
1574 TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2self");
1578 krb5_set_error_message(context, ret, "samba_kdc_check_s4u2self: talloc_named() failed!");
1582 if (target_principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
1583 /* Need to reparse the enterprise principal to find the real target */
1584 if (target_principal->name.name_string.len != 1) {
1585 ret = KRB5_PARSE_MALFORMED;
1586 krb5_set_error_message(context, ret, "samba_kdc_check_s4u2self: request for delegation to enterprise principal with wrong (%d) number of components",
1587 target_principal->name.name_string.len);
1588 talloc_free(mem_ctx);
1591 ret = krb5_parse_name(context, target_principal->name.name_string.val[0],
1592 &enterprise_prinicpal);
1594 talloc_free(mem_ctx);
1597 target_principal = enterprise_prinicpal;
1600 ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, target_principal,
1601 delegation_check_attrs, &realm_dn, &msg);
1603 krb5_free_principal(context, enterprise_prinicpal);
1606 talloc_free(mem_ctx);
1610 orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
1611 target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
1613 /* Allow delegation to the same principal, even if by a different
1614 * name. The easy and safe way to prove this is by SID
1616 if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
1617 talloc_free(mem_ctx);
1618 return KRB5KDC_ERR_BADOPTION;
1621 talloc_free(mem_ctx);
1625 /* Certificates printed by a the Certificate Authority might have a
1626 * slightly different form of the user principal name to that in the
1627 * database. Allow a mismatch where they both refer to the same
1631 samba_kdc_check_pkinit_ms_upn_match(krb5_context context,
1632 struct samba_kdc_db_context *kdc_db_ctx,
1633 hdb_entry_ex *entry,
1634 krb5_const_principal certificate_principal)
1636 krb5_error_code ret;
1637 struct ldb_dn *realm_dn;
1638 struct ldb_message *msg;
1639 struct dom_sid *orig_sid;
1640 struct dom_sid *target_sid;
1641 struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1642 const char *ms_upn_check_attrs[] = {
1646 TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_pkinit_ms_upn_match");
1650 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1654 ret = samba_kdc_lookup_client(context, kdc_db_ctx,
1655 mem_ctx, certificate_principal,
1656 ms_upn_check_attrs, &realm_dn, &msg);
1659 talloc_free(mem_ctx);
1663 orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
1664 target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
1666 /* Consider these to be the same principal, even if by a different
1667 * name. The easy and safe way to prove this is by SID
1669 if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
1670 talloc_free(mem_ctx);
1671 return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1674 talloc_free(mem_ctx);
1679 * Check if a given entry may delegate to this target principal
1683 samba_kdc_check_s4u2proxy(krb5_context context,
1684 struct samba_kdc_db_context *kdc_db_ctx,
1685 hdb_entry_ex *entry,
1686 krb5_const_principal target_principal)
1688 krb5_error_code ret;
1690 const char *client_dn = NULL;
1691 const char *target_principal_name = NULL;
1692 struct ldb_message_element *el;
1696 struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1698 TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2proxy");
1702 krb5_set_error_message(context, ret,
1703 "samba_kdc_check_s4u2proxy:"
1704 " talloc_named() failed!");
1708 client_dn = ldb_dn_get_linearized(p->msg->dn);
1714 krb5_set_error_message(context, ret,
1715 "samba_kdc_check_s4u2proxy:"
1716 " ldb_dn_get_linearized() failed!");
1721 * The main heimdal code already checked that the target_principal
1722 * belongs to the same realm as the client.
1724 * So we just need the principal without the realm,
1725 * as that is what is configured in the "msDS-AllowedToDelegateTo"
1728 ret = krb5_unparse_name_flags(context, target_principal,
1729 KRB5_PRINCIPAL_UNPARSE_NO_REALM, &tmp);
1731 talloc_free(mem_ctx);
1732 krb5_set_error_message(context, ret,
1733 "samba_kdc_check_s4u2proxy:"
1734 " krb5_unparse_name() failed!");
1737 DEBUG(10,("samba_kdc_check_s4u2proxy: client[%s] for target[%s]\n",
1740 target_principal_name = talloc_strdup(mem_ctx, tmp);
1742 if (target_principal_name == NULL) {
1744 krb5_set_error_message(context, ret,
1745 "samba_kdc_check_s4u2proxy:"
1746 " talloc_strdup() failed!");
1750 el = ldb_msg_find_element(p->msg, "msDS-AllowedToDelegateTo");
1755 val = data_blob_string_const(target_principal_name);
1757 for (i=0; i<el->num_values; i++) {
1758 struct ldb_val *val1 = &val;
1759 struct ldb_val *val2 = &el->values[i];
1762 if (val1->length != val2->length) {
1766 cmp = strncasecmp((const char *)val1->data,
1767 (const char *)val2->data,
1781 DEBUG(10,("samba_kdc_check_s4u2proxy: client[%s] allowed target[%s]\n",
1783 talloc_free(mem_ctx);
1787 krb5_set_error_message(context, ret,
1788 "samba_kdc_check_s4u2proxy: client[%s] "
1789 "not allowed for delegation to target[%s]",
1791 target_principal_name);
1792 talloc_free(mem_ctx);
1793 return KRB5KDC_ERR_BADOPTION;
1796 NTSTATUS samba_kdc_setup_db_ctx(TALLOC_CTX *mem_ctx, struct samba_kdc_base_context *base_ctx,
1797 struct samba_kdc_db_context **kdc_db_ctx_out)
1800 struct ldb_message *msg;
1801 struct auth_session_info *session_info;
1802 struct samba_kdc_db_context *kdc_db_ctx;
1803 /* The idea here is very simple. Using Kerberos to
1804 * authenticate the KDC to the LDAP server is higly likely to
1807 * In future we may set this up to use EXERNAL and SSL
1808 * certificates, for now it will almost certainly be NTLMSSP_SET_USERNAME
1811 kdc_db_ctx = talloc_zero(mem_ctx, struct samba_kdc_db_context);
1812 if (kdc_db_ctx == NULL) {
1813 return NT_STATUS_NO_MEMORY;
1815 kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
1816 kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
1818 kdc_get_policy(base_ctx->lp_ctx, NULL, &kdc_db_ctx->policy);
1820 session_info = system_session(kdc_db_ctx->lp_ctx);
1821 if (session_info == NULL) {
1822 return NT_STATUS_INTERNAL_ERROR;
1825 /* Setup the link to LDB */
1826 kdc_db_ctx->samdb = samdb_connect(kdc_db_ctx, base_ctx->ev_ctx,
1827 base_ctx->lp_ctx, session_info, 0);
1828 if (kdc_db_ctx->samdb == NULL) {
1829 DEBUG(1, ("hdb_samba4_create: Cannot open samdb for KDC backend!"));
1830 talloc_free(kdc_db_ctx);
1831 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1834 /* Find out our own krbtgt kvno */
1835 ldb_ret = samdb_rodc(kdc_db_ctx->samdb, &kdc_db_ctx->rodc);
1836 if (ldb_ret != LDB_SUCCESS) {
1837 DEBUG(1, ("hdb_samba4_create: Cannot determine if we are an RODC in KDC backend: %s\n",
1838 ldb_errstring(kdc_db_ctx->samdb)));
1839 talloc_free(kdc_db_ctx);
1840 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1842 if (kdc_db_ctx->rodc) {
1843 int my_krbtgt_number;
1844 const char *secondary_keytab[] = { "msDS-SecondaryKrbTgtNumber", NULL };
1845 struct ldb_dn *account_dn;
1846 struct ldb_dn *server_dn = samdb_server_dn(kdc_db_ctx->samdb, kdc_db_ctx);
1848 DEBUG(1, ("hdb_samba4_create: Cannot determine server DN in KDC backend: %s\n",
1849 ldb_errstring(kdc_db_ctx->samdb)));
1850 talloc_free(kdc_db_ctx);
1851 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1854 ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, server_dn,
1855 "serverReference", &account_dn);
1856 if (ldb_ret != LDB_SUCCESS) {
1857 DEBUG(1, ("hdb_samba4_create: Cannot determine server account in KDC backend: %s\n",
1858 ldb_errstring(kdc_db_ctx->samdb)));
1859 talloc_free(kdc_db_ctx);
1860 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1863 ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, account_dn,
1864 "msDS-KrbTgtLink", &kdc_db_ctx->krbtgt_dn);
1865 talloc_free(account_dn);
1866 if (ldb_ret != LDB_SUCCESS) {
1867 DEBUG(1, ("hdb_samba4_create: Cannot determine RODC krbtgt account in KDC backend: %s\n",
1868 ldb_errstring(kdc_db_ctx->samdb)));
1869 talloc_free(kdc_db_ctx);
1870 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1873 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
1874 &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
1877 "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=*))");
1878 if (ldb_ret != LDB_SUCCESS) {
1879 DEBUG(1, ("hdb_samba4_create: Cannot read krbtgt account %s in KDC backend to get msDS-SecondaryKrbTgtNumber: %s: %s\n",
1880 ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
1881 ldb_errstring(kdc_db_ctx->samdb),
1882 ldb_strerror(ldb_ret)));
1883 talloc_free(kdc_db_ctx);
1884 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1886 my_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
1887 if (my_krbtgt_number == -1) {
1888 DEBUG(1, ("hdb_samba4_create: Cannot read msDS-SecondaryKrbTgtNumber from krbtgt account %s in KDC backend: got %d\n",
1889 ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
1891 talloc_free(kdc_db_ctx);
1892 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1894 kdc_db_ctx->my_krbtgt_number = my_krbtgt_number;
1897 kdc_db_ctx->my_krbtgt_number = 0;
1898 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
1900 ldb_get_default_basedn(kdc_db_ctx->samdb),
1904 "(&(objectClass=user)(samAccountName=krbtgt))");
1906 if (ldb_ret != LDB_SUCCESS) {
1907 DEBUG(1, ("samba_kdc_fetch: could not find own KRBTGT in DB: %s\n", ldb_errstring(kdc_db_ctx->samdb)));
1908 talloc_free(kdc_db_ctx);
1909 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1911 kdc_db_ctx->krbtgt_dn = talloc_steal(kdc_db_ctx, msg->dn);
1912 kdc_db_ctx->my_krbtgt_number = 0;
1915 *kdc_db_ctx_out = kdc_db_ctx;
1916 return NT_STATUS_OK;