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,
1300 attrs, DSDB_SEARCH_SHOW_EXTENDED_DN, "(objectClass=*)");
1301 if (ldb_ret != LDB_SUCCESS) {
1302 return HDB_ERR_NOENTRY;
1307 char *filter = NULL;
1310 /* server as client principal case, but we must not lookup userPrincipalNames */
1311 *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
1312 realm = krb5_principal_get_realm(context, principal);
1314 /* TODO: Check if it is our realm, otherwise give referall */
1316 ret = krb5_unparse_name_flags(context, principal, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &short_princ);
1319 krb5_set_error_message(context, ret, "samba_kdc_lookup_principal: could not parse principal");
1320 krb5_warnx(context, "samba_kdc_lookup_principal: could not parse principal");
1324 lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx, msg,
1325 *realm_dn, LDB_SCOPE_SUBTREE,
1327 DSDB_SEARCH_SHOW_EXTENDED_DN,
1328 "(&(objectClass=user)(samAccountName=%s))",
1329 ldb_binary_encode_string(mem_ctx, short_princ));
1331 if (lret == LDB_ERR_NO_SUCH_OBJECT) {
1332 DEBUG(3, ("Failed find a entry for %s\n", filter));
1333 return HDB_ERR_NOENTRY;
1335 if (lret != LDB_SUCCESS) {
1336 DEBUG(3, ("Failed single search for for %s - %s\n",
1337 filter, ldb_errstring(kdc_db_ctx->samdb)));
1338 return HDB_ERR_NOENTRY;
1345 static krb5_error_code samba_kdc_fetch_server(krb5_context context,
1346 struct samba_kdc_db_context *kdc_db_ctx,
1347 TALLOC_CTX *mem_ctx,
1348 krb5_const_principal principal,
1350 hdb_entry_ex *entry_ex)
1352 krb5_error_code ret;
1353 struct ldb_dn *realm_dn;
1354 struct ldb_message *msg;
1356 ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, principal,
1357 server_attrs, &realm_dn, &msg);
1362 ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1363 principal, SAMBA_KDC_ENT_TYPE_SERVER,
1365 realm_dn, msg, entry_ex);
1367 krb5_warnx(context, "samba_kdc_fetch: message2entry failed");
1373 krb5_error_code samba_kdc_fetch(krb5_context context,
1374 struct samba_kdc_db_context *kdc_db_ctx,
1375 krb5_const_principal principal,
1378 hdb_entry_ex *entry_ex)
1380 krb5_error_code ret = HDB_ERR_NOENTRY;
1381 TALLOC_CTX *mem_ctx;
1382 unsigned int krbtgt_number;
1383 if (flags & HDB_F_KVNO_SPECIFIED) {
1384 krbtgt_number = SAMBA_KVNO_GET_KRBTGT(kvno);
1385 if (kdc_db_ctx->rodc) {
1386 if (krbtgt_number != kdc_db_ctx->my_krbtgt_number) {
1387 return HDB_ERR_NOT_FOUND_HERE;
1391 krbtgt_number = kdc_db_ctx->my_krbtgt_number;
1394 mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
1397 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1401 if (flags & HDB_F_GET_CLIENT) {
1402 ret = samba_kdc_fetch_client(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
1403 if (ret != HDB_ERR_NOENTRY) goto done;
1405 if (flags & HDB_F_GET_SERVER) {
1406 /* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
1407 ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, krbtgt_number, entry_ex);
1408 if (ret != HDB_ERR_NOENTRY) goto done;
1410 /* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
1411 ret = samba_kdc_fetch_server(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
1412 if (ret != HDB_ERR_NOENTRY) goto done;
1414 if (flags & HDB_F_GET_KRBTGT) {
1415 ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, krbtgt_number, entry_ex);
1416 if (ret != HDB_ERR_NOENTRY) goto done;
1420 talloc_free(mem_ctx);
1424 struct samba_kdc_seq {
1427 struct ldb_message **msgs;
1428 struct ldb_dn *realm_dn;
1431 static krb5_error_code samba_kdc_seq(krb5_context context,
1432 struct samba_kdc_db_context *kdc_db_ctx,
1433 hdb_entry_ex *entry)
1435 krb5_error_code ret;
1436 struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
1437 TALLOC_CTX *mem_ctx;
1438 hdb_entry_ex entry_ex;
1439 memset(&entry_ex, '\0', sizeof(entry_ex));
1442 return HDB_ERR_NOENTRY;
1445 mem_ctx = talloc_named(priv, 0, "samba_kdc_seq context");
1449 krb5_set_error_message(context, ret, "samba_kdc_seq: talloc_named() failed!");
1453 if (priv->index < priv->count) {
1454 ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1455 NULL, SAMBA_KDC_ENT_TYPE_ANY,
1456 HDB_F_ADMIN_DATA|HDB_F_GET_ANY,
1457 priv->realm_dn, priv->msgs[priv->index++], entry);
1459 ret = HDB_ERR_NOENTRY;
1464 kdc_db_ctx->seq_ctx = NULL;
1466 talloc_free(mem_ctx);
1472 krb5_error_code samba_kdc_firstkey(krb5_context context,
1473 struct samba_kdc_db_context *kdc_db_ctx,
1474 hdb_entry_ex *entry)
1476 struct ldb_context *ldb_ctx = kdc_db_ctx->samdb;
1477 struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
1479 struct ldb_result *res = NULL;
1480 krb5_error_code ret;
1481 TALLOC_CTX *mem_ctx;
1486 kdc_db_ctx->seq_ctx = NULL;
1489 priv = (struct samba_kdc_seq *) talloc(kdc_db_ctx, struct samba_kdc_seq);
1492 krb5_set_error_message(context, ret, "talloc: out of memory");
1498 priv->realm_dn = ldb_get_default_basedn(ldb_ctx);
1501 mem_ctx = talloc_named(priv, 0, "samba_kdc_firstkey context");
1505 krb5_set_error_message(context, ret, "samba_kdc_firstkey: talloc_named() failed!");
1509 ret = krb5_get_default_realm(context, &realm);
1515 lret = ldb_search(ldb_ctx, priv, &res,
1516 priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs,
1517 "(objectClass=user)");
1519 if (lret != LDB_SUCCESS) {
1521 return HDB_ERR_NOENTRY;
1524 priv->count = res->count;
1525 priv->msgs = talloc_steal(priv, res->msgs);
1528 kdc_db_ctx->seq_ctx = priv;
1530 ret = samba_kdc_seq(context, kdc_db_ctx, entry);
1534 kdc_db_ctx->seq_ctx = NULL;
1536 talloc_free(mem_ctx);
1541 krb5_error_code samba_kdc_nextkey(krb5_context context,
1542 struct samba_kdc_db_context *kdc_db_ctx,
1543 hdb_entry_ex *entry)
1545 return samba_kdc_seq(context, kdc_db_ctx, entry);
1548 /* Check if a given entry may delegate or do s4u2self to this target principal
1550 * This is currently a very nasty hack - allowing only delegation to itself.
1553 samba_kdc_check_s4u2self(krb5_context context,
1554 struct samba_kdc_db_context *kdc_db_ctx,
1555 hdb_entry_ex *entry,
1556 krb5_const_principal target_principal)
1558 krb5_error_code ret;
1559 krb5_principal enterprise_prinicpal = NULL;
1560 struct ldb_dn *realm_dn;
1561 struct ldb_message *msg;
1562 struct dom_sid *orig_sid;
1563 struct dom_sid *target_sid;
1564 struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1565 const char *delegation_check_attrs[] = {
1569 TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2self");
1573 krb5_set_error_message(context, ret, "samba_kdc_check_s4u2self: talloc_named() failed!");
1577 if (target_principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
1578 /* Need to reparse the enterprise principal to find the real target */
1579 if (target_principal->name.name_string.len != 1) {
1580 ret = KRB5_PARSE_MALFORMED;
1581 krb5_set_error_message(context, ret, "samba_kdc_check_s4u2self: request for delegation to enterprise principal with wrong (%d) number of components",
1582 target_principal->name.name_string.len);
1583 talloc_free(mem_ctx);
1586 ret = krb5_parse_name(context, target_principal->name.name_string.val[0],
1587 &enterprise_prinicpal);
1589 talloc_free(mem_ctx);
1592 target_principal = enterprise_prinicpal;
1595 ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, target_principal,
1596 delegation_check_attrs, &realm_dn, &msg);
1598 krb5_free_principal(context, enterprise_prinicpal);
1601 talloc_free(mem_ctx);
1605 orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
1606 target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
1608 /* Allow delegation to the same principal, even if by a different
1609 * name. The easy and safe way to prove this is by SID
1611 if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
1612 talloc_free(mem_ctx);
1613 return KRB5KDC_ERR_BADOPTION;
1616 talloc_free(mem_ctx);
1620 /* Certificates printed by a the Certificate Authority might have a
1621 * slightly different form of the user principal name to that in the
1622 * database. Allow a mismatch where they both refer to the same
1626 samba_kdc_check_pkinit_ms_upn_match(krb5_context context,
1627 struct samba_kdc_db_context *kdc_db_ctx,
1628 hdb_entry_ex *entry,
1629 krb5_const_principal certificate_principal)
1631 krb5_error_code ret;
1632 struct ldb_dn *realm_dn;
1633 struct ldb_message *msg;
1634 struct dom_sid *orig_sid;
1635 struct dom_sid *target_sid;
1636 struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1637 const char *ms_upn_check_attrs[] = {
1641 TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_pkinit_ms_upn_match");
1645 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1649 ret = samba_kdc_lookup_client(context, kdc_db_ctx,
1650 mem_ctx, certificate_principal,
1651 ms_upn_check_attrs, &realm_dn, &msg);
1654 talloc_free(mem_ctx);
1658 orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
1659 target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
1661 /* Consider these to be the same principal, even if by a different
1662 * name. The easy and safe way to prove this is by SID
1664 if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
1665 talloc_free(mem_ctx);
1666 return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1669 talloc_free(mem_ctx);
1674 * Check if a given entry may delegate to this target principal
1678 samba_kdc_check_s4u2proxy(krb5_context context,
1679 struct samba_kdc_db_context *kdc_db_ctx,
1680 hdb_entry_ex *entry,
1681 krb5_const_principal target_principal)
1683 krb5_error_code ret;
1685 const char *client_dn = NULL;
1686 const char *target_principal_name = NULL;
1687 struct ldb_message_element *el;
1691 struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1693 TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2proxy");
1697 krb5_set_error_message(context, ret,
1698 "samba_kdc_check_s4u2proxy:"
1699 " talloc_named() failed!");
1703 client_dn = ldb_dn_get_linearized(p->msg->dn);
1709 krb5_set_error_message(context, ret,
1710 "samba_kdc_check_s4u2proxy:"
1711 " ldb_dn_get_linearized() failed!");
1716 * The main heimdal code already checked that the target_principal
1717 * belongs to the same realm as the client.
1719 * So we just need the principal without the realm,
1720 * as that is what is configured in the "msDS-AllowedToDelegateTo"
1723 ret = krb5_unparse_name_flags(context, target_principal,
1724 KRB5_PRINCIPAL_UNPARSE_NO_REALM, &tmp);
1726 talloc_free(mem_ctx);
1727 krb5_set_error_message(context, ret,
1728 "samba_kdc_check_s4u2proxy:"
1729 " krb5_unparse_name() failed!");
1732 DEBUG(10,("samba_kdc_check_s4u2proxy: client[%s] for target[%s]\n",
1735 target_principal_name = talloc_strdup(mem_ctx, tmp);
1737 if (target_principal_name == NULL) {
1739 krb5_set_error_message(context, ret,
1740 "samba_kdc_check_s4u2proxy:"
1741 " talloc_strdup() failed!");
1745 el = ldb_msg_find_element(p->msg, "msDS-AllowedToDelegateTo");
1750 val = data_blob_string_const(target_principal_name);
1752 for (i=0; i<el->num_values; i++) {
1753 struct ldb_val *val1 = &val;
1754 struct ldb_val *val2 = &el->values[i];
1757 if (val1->length != val2->length) {
1761 cmp = strncasecmp((const char *)val1->data,
1762 (const char *)val2->data,
1776 DEBUG(10,("samba_kdc_check_s4u2proxy: client[%s] allowed target[%s]\n",
1778 talloc_free(mem_ctx);
1782 krb5_set_error_message(context, ret,
1783 "samba_kdc_check_s4u2proxy: client[%s] "
1784 "not allowed for delegation to target[%s]",
1786 target_principal_name);
1787 talloc_free(mem_ctx);
1788 return KRB5KDC_ERR_BADOPTION;
1791 NTSTATUS samba_kdc_setup_db_ctx(TALLOC_CTX *mem_ctx, struct samba_kdc_base_context *base_ctx,
1792 struct samba_kdc_db_context **kdc_db_ctx_out)
1795 struct ldb_message *msg;
1796 struct auth_session_info *session_info;
1797 struct samba_kdc_db_context *kdc_db_ctx;
1798 /* The idea here is very simple. Using Kerberos to
1799 * authenticate the KDC to the LDAP server is higly likely to
1802 * In future we may set this up to use EXERNAL and SSL
1803 * certificates, for now it will almost certainly be NTLMSSP_SET_USERNAME
1806 kdc_db_ctx = talloc_zero(mem_ctx, struct samba_kdc_db_context);
1807 if (kdc_db_ctx == NULL) {
1808 return NT_STATUS_NO_MEMORY;
1810 kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
1811 kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
1813 kdc_get_policy(base_ctx->lp_ctx, NULL, &kdc_db_ctx->policy);
1815 session_info = system_session(kdc_db_ctx->lp_ctx);
1816 if (session_info == NULL) {
1817 return NT_STATUS_INTERNAL_ERROR;
1820 /* Setup the link to LDB */
1821 kdc_db_ctx->samdb = samdb_connect(kdc_db_ctx, base_ctx->ev_ctx,
1822 base_ctx->lp_ctx, session_info, 0);
1823 if (kdc_db_ctx->samdb == NULL) {
1824 DEBUG(1, ("hdb_samba4_create: Cannot open samdb for KDC backend!"));
1825 talloc_free(kdc_db_ctx);
1826 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1829 /* Find out our own krbtgt kvno */
1830 ldb_ret = samdb_rodc(kdc_db_ctx->samdb, &kdc_db_ctx->rodc);
1831 if (ldb_ret != LDB_SUCCESS) {
1832 DEBUG(1, ("hdb_samba4_create: Cannot determine if we are an RODC in KDC backend: %s\n",
1833 ldb_errstring(kdc_db_ctx->samdb)));
1834 talloc_free(kdc_db_ctx);
1835 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1837 if (kdc_db_ctx->rodc) {
1838 int my_krbtgt_number;
1839 const char *secondary_keytab[] = { "msDS-SecondaryKrbTgtNumber", NULL };
1840 struct ldb_dn *account_dn;
1841 struct ldb_dn *server_dn = samdb_server_dn(kdc_db_ctx->samdb, kdc_db_ctx);
1843 DEBUG(1, ("hdb_samba4_create: Cannot determine server DN in KDC backend: %s\n",
1844 ldb_errstring(kdc_db_ctx->samdb)));
1845 talloc_free(kdc_db_ctx);
1846 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1849 ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, server_dn,
1850 "serverReference", &account_dn);
1851 if (ldb_ret != LDB_SUCCESS) {
1852 DEBUG(1, ("hdb_samba4_create: Cannot determine server account in KDC backend: %s\n",
1853 ldb_errstring(kdc_db_ctx->samdb)));
1854 talloc_free(kdc_db_ctx);
1855 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1858 ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, account_dn,
1859 "msDS-KrbTgtLink", &kdc_db_ctx->krbtgt_dn);
1860 talloc_free(account_dn);
1861 if (ldb_ret != LDB_SUCCESS) {
1862 DEBUG(1, ("hdb_samba4_create: Cannot determine RODC krbtgt account in KDC backend: %s\n",
1863 ldb_errstring(kdc_db_ctx->samdb)));
1864 talloc_free(kdc_db_ctx);
1865 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1868 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
1869 &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
1872 "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=*))");
1873 if (ldb_ret != LDB_SUCCESS) {
1874 DEBUG(1, ("hdb_samba4_create: Cannot read krbtgt account %s in KDC backend to get msDS-SecondaryKrbTgtNumber: %s: %s\n",
1875 ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
1876 ldb_errstring(kdc_db_ctx->samdb),
1877 ldb_strerror(ldb_ret)));
1878 talloc_free(kdc_db_ctx);
1879 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1881 my_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
1882 if (my_krbtgt_number == -1) {
1883 DEBUG(1, ("hdb_samba4_create: Cannot read msDS-SecondaryKrbTgtNumber from krbtgt account %s in KDC backend: got %d\n",
1884 ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
1886 talloc_free(kdc_db_ctx);
1887 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1889 kdc_db_ctx->my_krbtgt_number = my_krbtgt_number;
1892 kdc_db_ctx->my_krbtgt_number = 0;
1893 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
1895 ldb_get_default_basedn(kdc_db_ctx->samdb),
1899 "(&(objectClass=user)(samAccountName=krbtgt))");
1901 if (ldb_ret != LDB_SUCCESS) {
1902 DEBUG(1, ("samba_kdc_fetch: could not find own KRBTGT in DB: %s\n", ldb_errstring(kdc_db_ctx->samdb)));
1903 talloc_free(kdc_db_ctx);
1904 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1906 kdc_db_ctx->krbtgt_dn = talloc_steal(kdc_db_ctx, msg->dn);
1907 kdc_db_ctx->my_krbtgt_number = 0;
1910 *kdc_db_ctx_out = kdc_db_ctx;
1911 return NT_STATUS_OK;