s4-kdc: default kvno for inter-domain trusts to zero
[rusty/samba.git] / source4 / kdc / db-glue.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Database Glue between Samba and the KDC
5
6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7    Copyright (C) Simo Sorce <idra@samba.org> 2010
8
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.
13
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.
18
19
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/>.
22 */
23
24 #include "includes.h"
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"
35 #include <hdb.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"
40
41 #define SAMBA_KVNO_GET_KRBTGT(kvno) \
42         ((uint16_t)(((uint32_t)kvno) >> 16))
43
44 #define SAMBA_KVNO_AND_KRBTGT(kvno, krbtgt) \
45         ((krb5_kvno)((((uint32_t)kvno) & 0xFFFF) | \
46          ((((uint32_t)krbtgt) << 16) & 0xFFFF0000)))
47
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 };
51
52 enum trust_direction {
53         UNKNOWN = 0,
54         INBOUND = LSA_TRUST_DIRECTION_INBOUND,
55         OUTBOUND = LSA_TRUST_DIRECTION_OUTBOUND
56 };
57
58 static const char *trust_attrs[] = {
59         "trustPartner",
60         "trustAuthIncoming",
61         "trustAuthOutgoing",
62         "whenCreated",
63         "msDS-SupportedEncryptionTypes",
64         "trustAttributes",
65         "trustDirection",
66         "trustType",
67         NULL
68 };
69
70 static KerberosTime ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const char *attr, KerberosTime default_val)
71 {
72     const char *tmp;
73     const char *gentime;
74     struct tm tm;
75
76     gentime = ldb_msg_find_attr_as_string(msg, attr, NULL);
77     if (!gentime)
78         return default_val;
79
80     tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm);
81     if (tmp == NULL) {
82             return default_val;
83     }
84
85     return timegm(&tm);
86 }
87
88 static HDBFlags uf2HDBFlags(krb5_context context, uint32_t userAccountControl, enum samba_kdc_ent_type ent_type)
89 {
90         HDBFlags flags = int2HDBFlags(0);
91
92         /* we don't allow kadmin deletes */
93         flags.immutable = 1;
94
95         /* mark the principal as invalid to start with */
96         flags.invalid = 1;
97
98         flags.renewable = 1;
99
100         /* All accounts are servers, but this may be disabled again in the caller */
101         flags.server = 1;
102
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) {
106                         flags.client = 1;
107                 }
108                 flags.invalid = 0;
109         }
110
111         if (userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
112                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
113                         flags.client = 1;
114                 }
115                 flags.invalid = 0;
116         }
117         if (userAccountControl & UF_WORKSTATION_TRUST_ACCOUNT) {
118                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
119                         flags.client = 1;
120                 }
121                 flags.invalid = 0;
122         }
123         if (userAccountControl & UF_SERVER_TRUST_ACCOUNT) {
124                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
125                         flags.client = 1;
126                 }
127                 flags.invalid = 0;
128         }
129
130         /* Not permitted to act as a client if disabled */
131         if (userAccountControl & UF_ACCOUNTDISABLE) {
132                 flags.client = 0;
133         }
134         if (userAccountControl & UF_LOCKOUT) {
135                 flags.invalid = 1;
136         }
137 /*
138         if (userAccountControl & UF_PASSWORD_NOTREQD) {
139                 flags.invalid = 1;
140         }
141 */
142 /*
143         UF_PASSWORD_CANT_CHANGE and UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED are irrelevent
144 */
145         if (userAccountControl & UF_TEMP_DUPLICATE_ACCOUNT) {
146                 flags.invalid = 1;
147         }
148
149 /* UF_DONT_EXPIRE_PASSWD and UF_USE_DES_KEY_ONLY handled in samba_kdc_message2entry() */
150
151 /*
152         if (userAccountControl & UF_MNS_LOGON_ACCOUNT) {
153                 flags.invalid = 1;
154         }
155 */
156         if (userAccountControl & UF_SMARTCARD_REQUIRED) {
157                 flags.require_hwauth = 1;
158         }
159         if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) {
160                 flags.ok_as_delegate = 1;
161         }
162         if (userAccountControl & UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) {
163                 /*
164                  * this is confusing...
165                  *
166                  * UF_TRUSTED_FOR_DELEGATION
167                  * => ok_as_delegate
168                  *
169                  * and
170                  *
171                  * UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
172                  * => trusted_for_delegation
173                  */
174                 flags.trusted_for_delegation = 1;
175         }
176         if (!(userAccountControl & UF_NOT_DELEGATED)) {
177                 flags.forwardable = 1;
178                 flags.proxiable = 1;
179         }
180
181         if (userAccountControl & UF_DONT_REQUIRE_PREAUTH) {
182                 flags.require_preauth = 0;
183         } else {
184                 flags.require_preauth = 1;
185
186         }
187         return flags;
188 }
189
190 static int samba_kdc_entry_destructor(struct samba_kdc_entry *p)
191 {
192     hdb_entry_ex *entry_ex = p->entry_ex;
193     free_hdb_entry(&entry_ex->entry);
194     return 0;
195 }
196
197 static void samba_kdc_free_entry(krb5_context context, hdb_entry_ex *entry_ex)
198 {
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);
204
205         /* now proceed to free the talloc part */
206         talloc_free(entry_ex->ctx);
207 }
208
209 static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
210                                                     struct samba_kdc_db_context *kdc_db_ctx,
211                                                     TALLOC_CTX *mem_ctx,
212                                                     struct ldb_message *msg,
213                                                     uint32_t rid,
214                                                     bool is_rodc,
215                                                     uint32_t userAccountControl,
216                                                     enum samba_kdc_ent_type ent_type,
217                                                     hdb_entry_ex *entry_ex)
218 {
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;
229         uint16_t i;
230         uint16_t allocated_keys = 0;
231         int rodc_krbtgt_number = 0;
232         int kvno = 0;
233         uint32_t supported_enctypes
234                 = ldb_msg_find_attr_as_uint(msg,
235                                             "msDS-SupportedEncryptionTypes",
236                                             0);
237
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
248                  * user logs in from.
249                  *
250                  * likewise for 'any' return as much as is supported,
251                  * to export into a keytab */
252                 supported_enctypes = ENC_ALL_TYPES;
253         }
254
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;
258         } else {
259                 /* Otherwise, add in the default enc types */
260                 supported_enctypes |= ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
261         }
262
263         /* Is this the krbtgt or a RODC krbtgt */
264         if (is_rodc) {
265                 rodc_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
266
267                 if (rodc_krbtgt_number == -1) {
268                         return EINVAL;
269                 }
270         }
271
272         entry_ex->entry.keys.val = NULL;
273         entry_ex->entry.keys.len = 0;
274
275         kvno = ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0);
276         if (is_rodc) {
277                 kvno = SAMBA_KVNO_AND_KRBTGT(kvno, rodc_krbtgt_number);
278         }
279         entry_ex->entry.kvno = kvno;
280
281         /* Get keys from the db */
282
283         hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
284         sc_val = ldb_msg_find_ldb_val(msg, "supplementalCredentials");
285
286         /* unicodePwd for enctype 0x17 (23) if present */
287         if (hash) {
288                 allocated_keys++;
289         }
290
291         /* supplementalCredentials if present */
292         if (sc_val) {
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);
297                         ret = EINVAL;
298                         goto out;
299                 }
300
301                 if (scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
302                         NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
303                         ret = EINVAL;
304                         goto out;
305                 }
306
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]) {
311                                         scpk = NULL;
312                                         continue;
313                                 }
314                                 newer_keys = true;
315                                 break;
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]) {
319                                         scpk = NULL;
320                                 }
321                                 /*
322                                  * we don't break here in hope to find
323                                  * a Kerberos-Newer-Keys package
324                                  */
325                         }
326                 }
327         }
328         /*
329          * Primary:Kerberos-Newer-Keys or Primary:Kerberos element
330          * of supplementalCredentials
331          */
332         if (scpk) {
333                 DATA_BLOB blob;
334
335                 blob = strhex_to_data_blob(mem_ctx, scpk->data);
336                 if (!blob.data) {
337                         ret = ENOMEM;
338                         goto out;
339                 }
340
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)) {
345                         ret = EINVAL;
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");
348                         goto out;
349                 }
350
351                 if (newer_keys && _pkb.version != 4) {
352                         ret = EINVAL;
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");
355                         goto out;
356                 }
357
358                 if (!newer_keys && _pkb.version != 3) {
359                         ret = EINVAL;
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");
362                         goto out;
363                 }
364
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;
371                 }
372         }
373
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;
378                 }
379
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). */
383                 return 0;
384         }
385
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) {
390                 ret = ENOMEM;
391                 goto out;
392         }
393
394         if (hash && (supported_enctypes & ENC_RC4_HMAC_MD5)) {
395                 Key key;
396
397                 key.mkvno = 0;
398                 key.salt = NULL; /* No salt for this enc type */
399
400                 ret = krb5_keyblock_init(context,
401                                          ENCTYPE_ARCFOUR_HMAC,
402                                          hash->hash, sizeof(hash->hash),
403                                          &key.key);
404                 if (ret) {
405                         goto out;
406                 }
407
408                 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
409                 entry_ex->entry.keys.len++;
410         }
411
412         if (pkb4) {
413                 for (i=0; i < pkb4->num_keys; i++) {
414                         Key key;
415
416                         if (!pkb4->keys[i].value) continue;
417
418                         if (!(kerberos_enctype_to_bitmap(pkb4->keys[i].keytype) & supported_enctypes)) {
419                                 continue;
420                         }
421
422                         key.mkvno = 0;
423                         key.salt = NULL;
424
425                         if (pkb4->salt.string) {
426                                 DATA_BLOB salt;
427
428                                 salt = data_blob_string_const(pkb4->salt.string);
429
430                                 key.salt = calloc(1, sizeof(*key.salt));
431                                 if (key.salt == NULL) {
432                                         ret = ENOMEM;
433                                         goto out;
434                                 }
435
436                                 key.salt->type = hdb_pw_salt;
437
438                                 ret = krb5_data_copy(&key.salt->salt, salt.data, salt.length);
439                                 if (ret) {
440                                         free(key.salt);
441                                         key.salt = NULL;
442                                         goto out;
443                                 }
444                         }
445
446                         /* TODO: maybe pass the iteration_count somehow... */
447
448                         ret = krb5_keyblock_init(context,
449                                                  pkb4->keys[i].keytype,
450                                                  pkb4->keys[i].value->data,
451                                                  pkb4->keys[i].value->length,
452                                                  &key.key);
453                         if (ret == KRB5_PROG_ETYPE_NOSUPP) {
454                                 DEBUG(2,("Unsupported keytype ignored - type %u\n",
455                                          pkb4->keys[i].keytype));
456                                 ret = 0;
457                                 continue;
458                         }
459                         if (ret) {
460                                 if (key.salt) {
461                                         free_Salt(key.salt);
462                                         free(key.salt);
463                                         key.salt = NULL;
464                                 }
465                                 goto out;
466                         }
467
468                         entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
469                         entry_ex->entry.keys.len++;
470                 }
471         } else if (pkb3) {
472                 for (i=0; i < pkb3->num_keys; i++) {
473                         Key key;
474
475                         if (!pkb3->keys[i].value) continue;
476
477                         if (!(kerberos_enctype_to_bitmap(pkb3->keys[i].keytype) & supported_enctypes)) {
478                                 continue;
479                         }
480
481                         key.mkvno = 0;
482                         key.salt = NULL;
483
484                         if (pkb3->salt.string) {
485                                 DATA_BLOB salt;
486
487                                 salt = data_blob_string_const(pkb3->salt.string);
488
489                                 key.salt = calloc(1, sizeof(*key.salt));
490                                 if (key.salt == NULL) {
491                                         ret = ENOMEM;
492                                         goto out;
493                                 }
494
495                                 key.salt->type = hdb_pw_salt;
496
497                                 ret = krb5_data_copy(&key.salt->salt, salt.data, salt.length);
498                                 if (ret) {
499                                         free(key.salt);
500                                         key.salt = NULL;
501                                         goto out;
502                                 }
503                         }
504
505                         ret = krb5_keyblock_init(context,
506                                                  pkb3->keys[i].keytype,
507                                                  pkb3->keys[i].value->data,
508                                                  pkb3->keys[i].value->length,
509                                                  &key.key);
510                         if (ret) {
511                                 if (key.salt) {
512                                         free_Salt(key.salt);
513                                         free(key.salt);
514                                         key.salt = NULL;
515                                 }
516                                 goto out;
517                         }
518
519                         entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
520                         entry_ex->entry.keys.len++;
521                 }
522         }
523
524 out:
525         if (ret != 0) {
526                 entry_ex->entry.keys.len = 0;
527         }
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;
531         }
532         return ret;
533 }
534
535 /*
536  * Construct an hdb_entry from a directory entry.
537  */
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,
542                                                unsigned flags,
543                                                struct ldb_dn *realm_dn,
544                                                struct ldb_message *msg,
545                                                hdb_entry_ex *entry_ex)
546 {
547         struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
548         uint32_t userAccountControl;
549         unsigned int i;
550         krb5_error_code ret = 0;
551         krb5_boolean is_computer = FALSE;
552
553         struct samba_kdc_entry *p;
554         NTTIME acct_expiry;
555         NTSTATUS status;
556
557         uint32_t rid;
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);
564
565         if (ldb_msg_find_element(msg, "msDS-SecondaryKrbTgtNumber")) {
566                 is_rodc = true;
567         }
568
569         if (!samAccountName) {
570                 ret = ENOENT;
571                 krb5_set_error_message(context, ret, "samba_kdc_message2entry: no samAccountName present");
572                 goto out;
573         }
574
575         objectclasses = ldb_msg_find_element(msg, "objectClass");
576
577         if (objectclasses && ldb_msg_find_val(objectclasses, &computer_val)) {
578                 is_computer = TRUE;
579         }
580
581         memset(entry_ex, 0, sizeof(*entry_ex));
582
583         p = talloc(mem_ctx, struct samba_kdc_entry);
584         if (!p) {
585                 ret = ENOMEM;
586                 goto out;
587         }
588
589         p->kdc_db_ctx = kdc_db_ctx;
590         p->entry_ex = entry_ex;
591         p->realm_dn = talloc_reference(p, realm_dn);
592         if (!p->realm_dn) {
593                 ret = ENOMEM;
594                 goto out;
595         }
596
597         talloc_set_destructor(p, samba_kdc_entry_destructor);
598
599         /* make sure we do not have bogus data in there */
600         memset(&entry_ex->entry, 0, sizeof(hdb_entry));
601
602         entry_ex->ctx = p;
603         entry_ex->free_entry = samba_kdc_free_entry;
604
605         userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
606
607
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);
611         } else {
612                 ret = copy_Principal(principal, entry_ex->entry.principal);
613                 if (ret) {
614                         krb5_clear_error_message(context);
615                         goto out;
616                 }
617
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 */
623
624                 /* this has to be with malloc() */
625                 krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
626         }
627
628         /* First try and figure out the flags based on the userAccountControl */
629         entry_ex->entry.flags = uf2HDBFlags(context, userAccountControl, ent_type);
630
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) */
635
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;
640                 }
641         }
642
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
647                  * we must return */
648
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);
655
656                 entry_ex->entry.modified_by = (Event *) malloc(sizeof(Event));
657                 if (entry_ex->entry.modified_by == NULL) {
658                         ret = ENOMEM;
659                         krb5_set_error_message(context, ret, "malloc: out of memory");
660                         goto out;
661                 }
662
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);
669         }
670
671
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);
675
676         if (!NT_STATUS_IS_OK(status)) {
677                 ret = EINVAL;
678                 goto out;
679         }
680
681         if (rid == DOMAIN_RID_KRBTGT) {
682                 entry_ex->entry.valid_end = NULL;
683                 entry_ex->entry.pw_end = NULL;
684
685                 entry_ex->entry.flags.invalid = 0;
686                 entry_ex->entry.flags.server = 1;
687
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;
698                 }
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
705                  * service */
706
707                 entry_ex->entry.valid_end = NULL;
708                 entry_ex->entry.pw_end = NULL;
709
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;
714
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 */
721
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;
725
726                 entry_ex->entry.valid_end = NULL;
727                 entry_ex->entry.pw_end = NULL;
728
729         } else {
730                 NTTIME must_change_time
731                         = samdb_result_force_password_change(kdc_db_ctx->samdb, mem_ctx,
732                                                              realm_dn, msg);
733                 if (must_change_time == 0x7FFFFFFFFFFFFFFFULL) {
734                         entry_ex->entry.pw_end = NULL;
735                 } else {
736                         entry_ex->entry.pw_end = malloc(sizeof(*entry_ex->entry.pw_end));
737                         if (entry_ex->entry.pw_end == NULL) {
738                                 ret = ENOMEM;
739                                 goto out;
740                         }
741                         *entry_ex->entry.pw_end = nt_time_to_unix(must_change_time);
742                 }
743
744                 acct_expiry = samdb_result_account_expires(msg);
745                 if (acct_expiry == 0x7FFFFFFFFFFFFFFFULL) {
746                         entry_ex->entry.valid_end = NULL;
747                 } else {
748                         entry_ex->entry.valid_end = malloc(sizeof(*entry_ex->entry.valid_end));
749                         if (entry_ex->entry.valid_end == NULL) {
750                                 ret = ENOMEM;
751                                 goto out;
752                         }
753                         *entry_ex->entry.valid_end = nt_time_to_unix(acct_expiry);
754                 }
755         }
756
757         entry_ex->entry.valid_start = NULL;
758
759         entry_ex->entry.max_life = malloc(sizeof(*entry_ex->entry.max_life));
760         if (entry_ex->entry.max_life == NULL) {
761                 ret = ENOMEM;
762                 goto out;
763         }
764
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);
769         } else {
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));
772         }
773
774         entry_ex->entry.max_renew = malloc(sizeof(*entry_ex->entry.max_life));
775         if (entry_ex->entry.max_renew == NULL) {
776                 ret = ENOMEM;
777                 goto out;
778         }
779
780         *entry_ex->entry.max_renew = nt_time_to_unix(kdc_db_ctx->policy.user_tkt_renewaltime);
781
782         entry_ex->entry.generation = NULL;
783
784         /* Get keys from the db */
785         ret = samba_kdc_message2entry_keys(context, kdc_db_ctx, p, msg,
786                                            rid, is_rodc, userAccountControl,
787                                            ent_type, entry_ex);
788         if (ret) {
789                 /* Could be bougus data in the entry, or out of memory */
790                 goto out;
791         }
792
793         entry_ex->entry.etypes = malloc(sizeof(*(entry_ex->entry.etypes)));
794         if (entry_ex->entry.etypes == NULL) {
795                 krb5_clear_error_message(context);
796                 ret = ENOMEM;
797                 goto out;
798         }
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);
803                 ret = ENOMEM;
804                 goto out;
805         }
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;
808         }
809
810
811         p->msg = talloc_steal(p, msg);
812
813 out:
814         if (ret != 0) {
815                 /* This doesn't free ent itself, that is for the eventual caller to do */
816                 hdb_free_entry(context, entry_ex);
817         } else {
818                 talloc_steal(kdc_db_ctx, entry_ex->ctx);
819         }
820
821         return ret;
822 }
823
824 /*
825  * Construct an hdb_entry from a directory entry.
826  */
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)
834 {
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;
843
844         enum ndr_err_code ndr_err;
845         int ret, trust_direction_flags;
846         unsigned int i;
847
848         p = talloc(mem_ctx, struct samba_kdc_entry);
849         if (!p) {
850                 ret = ENOMEM;
851                 goto out;
852         }
853
854         p->kdc_db_ctx = kdc_db_ctx;
855         p->entry_ex = entry_ex;
856         p->realm_dn = realm_dn;
857
858         talloc_set_destructor(p, samba_kdc_entry_destructor);
859
860         /* make sure we do not have bogus data in there */
861         memset(&entry_ex->entry, 0, sizeof(hdb_entry));
862
863         entry_ex->ctx = p;
864         entry_ex->free_entry = samba_kdc_free_entry;
865
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);
872
873         entry_ex->entry.valid_start = NULL;
874
875         trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
876
877         if (direction == INBOUND) {
878                 password_val = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
879
880         } else { /* OUTBOUND */
881                 dnsdomain = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
882                 /* replace realm */
883                 realm = strupper_talloc(mem_ctx, dnsdomain);
884                 password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
885         }
886
887         if (!password_val || !(trust_direction_flags & direction)) {
888                 ret = ENOENT;
889                 goto out;
890         }
891
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)) {
895                 ret = EINVAL;
896                 goto out;
897         }
898
899         entry_ex->entry.kvno = 0;
900         /*
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
906           we just use 0.
907          */
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;
911                 }
912         }
913
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
921                          * utf8 */
922
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);
925                         break;
926                 } else if (password_blob.current.array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
927                         password_hash = password_blob.current.array[i].AuthInfo.nt4owf.password;
928                         break;
929                 }
930         }
931
932         if (i < password_blob.count) {
933                 Key key;
934                 /* Must have found a cleartext or MD4 password */
935                 entry_ex->entry.keys.val = calloc(1, sizeof(Key));
936
937                 key.mkvno = 0;
938                 key.salt = NULL; /* No salt for this enc type */
939
940                 if (entry_ex->entry.keys.val == NULL) {
941                         ret = ENOMEM;
942                         goto out;
943                 }
944
945                 ret = krb5_keyblock_init(context,
946                                          ENCTYPE_ARCFOUR_HMAC,
947                                          password_hash.hash, sizeof(password_hash.hash),
948                                          &key.key);
949
950                 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
951                 entry_ex->entry.keys.len++;
952         }
953
954         entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal)));
955
956         ret = copy_Principal(principal, entry_ex->entry.principal);
957         if (ret) {
958                 krb5_clear_error_message(context);
959                 goto out;
960         }
961
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 */
967
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;
974
975         entry_ex->entry.pw_end = NULL;
976
977         entry_ex->entry.max_life = NULL;
978
979         entry_ex->entry.max_renew = NULL;
980
981         entry_ex->entry.generation = NULL;
982
983         entry_ex->entry.etypes = malloc(sizeof(*(entry_ex->entry.etypes)));
984         if (entry_ex->entry.etypes == NULL) {
985                 krb5_clear_error_message(context);
986                 ret = ENOMEM;
987                 goto out;
988         }
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);
993                 ret = ENOMEM;
994                 goto out;
995         }
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;
998         }
999
1000
1001         p->msg = talloc_steal(p, msg);
1002
1003 out:
1004         if (ret != 0) {
1005                 /* This doesn't free ent itself, that is for the eventual caller to do */
1006                 hdb_free_entry(context, entry_ex);
1007         } else {
1008                 talloc_steal(kdc_db_ctx, entry_ex->ctx);
1009         }
1010
1011         return ret;
1012
1013 }
1014
1015 static krb5_error_code samba_kdc_lookup_trust(krb5_context context, struct ldb_context *ldb_ctx,
1016                                         TALLOC_CTX *mem_ctx,
1017                                         const char *realm,
1018                                         struct ldb_dn *realm_dn,
1019                                         struct ldb_message **pmsg)
1020 {
1021         int lret;
1022         krb5_error_code ret;
1023         char *filter = NULL;
1024         const char * const *attrs = trust_attrs;
1025
1026         struct ldb_result *res = NULL;
1027         char *realm_encoded = ldb_binary_encode_string(mem_ctx, realm);
1028         if (!realm_encoded) {
1029                 if (!filter) {
1030                         ret = ENOMEM;
1031                         krb5_set_error_message(context, ret, "talloc_asprintf: out of memory");
1032                         return ret;
1033                 }
1034         }
1035         filter = talloc_asprintf(mem_ctx, "(&(objectClass=trustedDomain)(|(flatname=%s)(trustPartner=%s)))", 
1036                                  realm_encoded, realm_encoded);
1037
1038         if (!filter) {
1039                 talloc_free(realm_encoded);
1040                 ret = ENOMEM;
1041                 krb5_set_error_message(context, ret, "talloc_asprintf: out of memory");
1042                 return ret;
1043         }
1044
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));
1053                 talloc_free(res);
1054                 return HDB_ERR_NOENTRY;
1055         }
1056         talloc_steal(mem_ctx, res->msgs);
1057         *pmsg = res->msgs[0];
1058         talloc_free(res);
1059         return 0;
1060 }
1061
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,
1066                                                 const char **attrs,
1067                                                 struct ldb_dn **realm_dn,
1068                                                 struct ldb_message **msg) {
1069         NTSTATUS nt_status;
1070         char *principal_string;
1071         krb5_error_code ret;
1072
1073         ret = krb5_unparse_name(context, principal, &principal_string);
1074
1075         if (ret != 0) {
1076                 return ret;
1077         }
1078
1079         nt_status = sam_get_results_principal(kdc_db_ctx->samdb,
1080                                               mem_ctx, principal_string, attrs,
1081                                               realm_dn, msg);
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)) {
1086                 return ENOMEM;
1087         } else if (!NT_STATUS_IS_OK(nt_status)) {
1088                 return EINVAL;
1089         }
1090
1091         return ret;
1092 }
1093
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,
1098                                                unsigned flags,
1099                                                hdb_entry_ex *entry_ex) {
1100         struct ldb_dn *realm_dn;
1101         krb5_error_code ret;
1102         struct ldb_message *msg = NULL;
1103
1104         ret = samba_kdc_lookup_client(context, kdc_db_ctx,
1105                                        mem_ctx, principal, user_attrs,
1106                                        &realm_dn, &msg);
1107         if (ret != 0) {
1108                 return ret;
1109         }
1110
1111         ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1112                                       principal, SAMBA_KDC_ENT_TYPE_CLIENT,
1113                                       flags,
1114                                       realm_dn, msg, entry_ex);
1115         return ret;
1116 }
1117
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,
1122                                               unsigned flags,
1123                                               uint32_t krbtgt_number,
1124                                               hdb_entry_ex *entry_ex)
1125 {
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);
1130
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)) {
1134                 /* Not a krbtgt */
1135                 return HDB_ERR_NOENTRY;
1136         }
1137
1138         /* krbtgt case.  Either us or a trusted realm */
1139
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
1145                  * krbtgt */
1146
1147                 int lret;
1148
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,
1152                                                krbtgt_attrs, 0,
1153                                                "(objectClass=user)");
1154                 } else {
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,
1160                                                krbtgt_attrs,
1161                                                DSDB_SEARCH_SHOW_EXTENDED_DN,
1162                                                "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=%u))", (unsigned)(krbtgt_number));
1163                 }
1164
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;
1179                 }
1180
1181                 /*
1182                  * Windows seems to canonicalize the principal
1183                  * in a TGS REP even if the client did not specify
1184                  * the canonicalize flag.
1185                  */
1186                 if (flags & (HDB_F_CANON|HDB_F_FOR_TGS_REQ)) {
1187                         ret = krb5_copy_principal(context, principal, &alloc_principal);
1188                         if (ret) {
1189                                 return ret;
1190                         }
1191
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]) {
1198                                 ret = ENOMEM;
1199                                 krb5_set_error_message(context, ret, "samba_kdc_fetch: strdup() failed!");
1200                                 return ret;
1201                         }
1202                         principal = alloc_principal;
1203                 }
1204
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);
1211                 }
1212                 if (ret != 0) {
1213                         krb5_warnx(context, "samba_kdc_fetch: self krbtgt message2entry failed");
1214                 }
1215                 return ret;
1216
1217         } else {
1218                 enum trust_direction direction = UNKNOWN;
1219                 const char *realm = NULL;
1220
1221                 /* Either an inbound or outbound trust */
1222
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;
1231                 } else {
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;
1237                 }
1238
1239                 /* Trusted domains are under CN=system */
1240
1241                 ret = samba_kdc_lookup_trust(context, kdc_db_ctx->samdb,
1242                                        mem_ctx,
1243                                        realm, realm_dn, &msg);
1244
1245                 if (ret != 0) {
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");
1248                         return ret;
1249                 }
1250
1251                 ret = samba_kdc_trust_message2entry(context, kdc_db_ctx, mem_ctx,
1252                                               principal, direction,
1253                                               realm_dn, msg, entry_ex);
1254                 if (ret != 0) {
1255                         krb5_warnx(context, "samba_kdc_fetch: trust_message2entry failed");
1256                 }
1257                 return ret;
1258         }
1259
1260 }
1261
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,
1266                                                 const char **attrs,
1267                                                 struct ldb_dn **realm_dn,
1268                                                 struct ldb_message **msg)
1269 {
1270         krb5_error_code ret;
1271         if (principal->name.name_string.len >= 2) {
1272                 /* 'normal server' case */
1273                 int ldb_ret;
1274                 NTSTATUS nt_status;
1275                 struct ldb_dn *user_dn;
1276                 char *principal_string;
1277
1278                 ret = krb5_unparse_name_flags(context, principal,
1279                                               KRB5_PRINCIPAL_UNPARSE_NO_REALM,
1280                                               &principal_string);
1281                 if (ret != 0) {
1282                         return ret;
1283                 }
1284
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);
1292
1293                 if (!NT_STATUS_IS_OK(nt_status)) {
1294                         return HDB_ERR_NOENTRY;
1295                 }
1296
1297                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb,
1298                                           mem_ctx,
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;
1303                 }
1304
1305         } else {
1306                 int lret;
1307                 char *filter = NULL;
1308                 char *short_princ;
1309                 const char *realm;
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);
1313
1314                 /* TODO: Check if it is our realm, otherwise give referall */
1315
1316                 ret = krb5_unparse_name_flags(context, principal,  KRB5_PRINCIPAL_UNPARSE_NO_REALM, &short_princ);
1317
1318                 if (ret != 0) {
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");
1321                         return ret;
1322                 }
1323
1324                 lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx, msg,
1325                                        *realm_dn, LDB_SCOPE_SUBTREE,
1326                                        attrs,
1327                                        DSDB_SEARCH_SHOW_EXTENDED_DN,
1328                                        "(&(objectClass=user)(samAccountName=%s))",
1329                                        ldb_binary_encode_string(mem_ctx, short_princ));
1330                 free(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;
1334                 }
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;
1339                 }
1340         }
1341
1342         return 0;
1343 }
1344
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,
1349                                               unsigned flags,
1350                                               hdb_entry_ex *entry_ex)
1351 {
1352         krb5_error_code ret;
1353         struct ldb_dn *realm_dn;
1354         struct ldb_message *msg;
1355
1356         ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, principal,
1357                                        server_attrs, &realm_dn, &msg);
1358         if (ret != 0) {
1359                 return ret;
1360         }
1361
1362         ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1363                                       principal, SAMBA_KDC_ENT_TYPE_SERVER,
1364                                       flags,
1365                                       realm_dn, msg, entry_ex);
1366         if (ret != 0) {
1367                 krb5_warnx(context, "samba_kdc_fetch: message2entry failed");
1368         }
1369
1370         return ret;
1371 }
1372
1373 krb5_error_code samba_kdc_fetch(krb5_context context,
1374                                 struct samba_kdc_db_context *kdc_db_ctx,
1375                                 krb5_const_principal principal,
1376                                 unsigned flags,
1377                                 krb5_kvno kvno,
1378                                 hdb_entry_ex *entry_ex)
1379 {
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;
1388                         }
1389                 }
1390         } else {
1391                 krbtgt_number = kdc_db_ctx->my_krbtgt_number;
1392         }
1393
1394         mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
1395         if (!mem_ctx) {
1396                 ret = ENOMEM;
1397                 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1398                 return ret;
1399         }
1400
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;
1404         }
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;
1409
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;
1413         }
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;
1417         }
1418
1419 done:
1420         talloc_free(mem_ctx);
1421         return ret;
1422 }
1423
1424 struct samba_kdc_seq {
1425         unsigned int index;
1426         unsigned int count;
1427         struct ldb_message **msgs;
1428         struct ldb_dn *realm_dn;
1429 };
1430
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)
1434 {
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));
1440
1441         if (!priv) {
1442                 return HDB_ERR_NOENTRY;
1443         }
1444
1445         mem_ctx = talloc_named(priv, 0, "samba_kdc_seq context");
1446
1447         if (!mem_ctx) {
1448                 ret = ENOMEM;
1449                 krb5_set_error_message(context, ret, "samba_kdc_seq: talloc_named() failed!");
1450                 return ret;
1451         }
1452
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);
1458         } else {
1459                 ret = HDB_ERR_NOENTRY;
1460         }
1461
1462         if (ret != 0) {
1463                 TALLOC_FREE(priv);
1464                 kdc_db_ctx->seq_ctx = NULL;
1465         } else {
1466                 talloc_free(mem_ctx);
1467         }
1468
1469         return ret;
1470 }
1471
1472 krb5_error_code samba_kdc_firstkey(krb5_context context,
1473                                    struct samba_kdc_db_context *kdc_db_ctx,
1474                                    hdb_entry_ex *entry)
1475 {
1476         struct ldb_context *ldb_ctx = kdc_db_ctx->samdb;
1477         struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
1478         char *realm;
1479         struct ldb_result *res = NULL;
1480         krb5_error_code ret;
1481         TALLOC_CTX *mem_ctx;
1482         int lret;
1483
1484         if (priv) {
1485                 TALLOC_FREE(priv);
1486                 kdc_db_ctx->seq_ctx = NULL;
1487         }
1488
1489         priv = (struct samba_kdc_seq *) talloc(kdc_db_ctx, struct samba_kdc_seq);
1490         if (!priv) {
1491                 ret = ENOMEM;
1492                 krb5_set_error_message(context, ret, "talloc: out of memory");
1493                 return ret;
1494         }
1495
1496         priv->index = 0;
1497         priv->msgs = NULL;
1498         priv->realm_dn = ldb_get_default_basedn(ldb_ctx);
1499         priv->count = 0;
1500
1501         mem_ctx = talloc_named(priv, 0, "samba_kdc_firstkey context");
1502
1503         if (!mem_ctx) {
1504                 ret = ENOMEM;
1505                 krb5_set_error_message(context, ret, "samba_kdc_firstkey: talloc_named() failed!");
1506                 return ret;
1507         }
1508
1509         ret = krb5_get_default_realm(context, &realm);
1510         if (ret != 0) {
1511                 TALLOC_FREE(priv);
1512                 return ret;
1513         }
1514
1515         lret = ldb_search(ldb_ctx, priv, &res,
1516                           priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs,
1517                           "(objectClass=user)");
1518
1519         if (lret != LDB_SUCCESS) {
1520                 TALLOC_FREE(priv);
1521                 return HDB_ERR_NOENTRY;
1522         }
1523
1524         priv->count = res->count;
1525         priv->msgs = talloc_steal(priv, res->msgs);
1526         talloc_free(res);
1527
1528         kdc_db_ctx->seq_ctx = priv;
1529
1530         ret = samba_kdc_seq(context, kdc_db_ctx, entry);
1531
1532         if (ret != 0) {
1533                 TALLOC_FREE(priv);
1534                 kdc_db_ctx->seq_ctx = NULL;
1535         } else {
1536                 talloc_free(mem_ctx);
1537         }
1538         return ret;
1539 }
1540
1541 krb5_error_code samba_kdc_nextkey(krb5_context context,
1542                                   struct samba_kdc_db_context *kdc_db_ctx,
1543                                   hdb_entry_ex *entry)
1544 {
1545         return samba_kdc_seq(context, kdc_db_ctx, entry);
1546 }
1547
1548 /* Check if a given entry may delegate or do s4u2self to this target principal
1549  *
1550  * This is currently a very nasty hack - allowing only delegation to itself.
1551  */
1552 krb5_error_code
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)
1557 {
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[] = {
1566                 "objectSid", NULL
1567         };
1568
1569         TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2self");
1570
1571         if (!mem_ctx) {
1572                 ret = ENOMEM;
1573                 krb5_set_error_message(context, ret, "samba_kdc_check_s4u2self: talloc_named() failed!");
1574                 return ret;
1575         }
1576
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);
1584                         return ret;
1585                 }
1586                 ret = krb5_parse_name(context, target_principal->name.name_string.val[0],
1587                                       &enterprise_prinicpal);
1588                 if (ret) {
1589                         talloc_free(mem_ctx);
1590                         return ret;
1591                 }
1592                 target_principal = enterprise_prinicpal;
1593         }
1594
1595         ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, target_principal,
1596                                        delegation_check_attrs, &realm_dn, &msg);
1597
1598         krb5_free_principal(context, enterprise_prinicpal);
1599
1600         if (ret != 0) {
1601                 talloc_free(mem_ctx);
1602                 return ret;
1603         }
1604
1605         orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
1606         target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
1607
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
1610          * comparison */
1611         if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
1612                 talloc_free(mem_ctx);
1613                 return KRB5KDC_ERR_BADOPTION;
1614         }
1615
1616         talloc_free(mem_ctx);
1617         return ret;
1618 }
1619
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
1623  * SID */
1624
1625 krb5_error_code
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)
1630 {
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[] = {
1638                 "objectSid", NULL
1639         };
1640
1641         TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_pkinit_ms_upn_match");
1642
1643         if (!mem_ctx) {
1644                 ret = ENOMEM;
1645                 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1646                 return ret;
1647         }
1648
1649         ret = samba_kdc_lookup_client(context, kdc_db_ctx,
1650                                        mem_ctx, certificate_principal,
1651                                        ms_upn_check_attrs, &realm_dn, &msg);
1652
1653         if (ret != 0) {
1654                 talloc_free(mem_ctx);
1655                 return ret;
1656         }
1657
1658         orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
1659         target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
1660
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
1663          * comparison */
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;
1667         }
1668
1669         talloc_free(mem_ctx);
1670         return ret;
1671 }
1672
1673 /*
1674  * Check if a given entry may delegate to this target principal
1675  * with S4U2Proxy.
1676  */
1677 krb5_error_code
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)
1682 {
1683         krb5_error_code ret;
1684         char *tmp = NULL;
1685         const char *client_dn = NULL;
1686         const char *target_principal_name = NULL;
1687         struct ldb_message_element *el;
1688         struct ldb_val val;
1689         unsigned int i;
1690         bool found = false;
1691         struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1692
1693         TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2proxy");
1694
1695         if (!mem_ctx) {
1696                 ret = ENOMEM;
1697                 krb5_set_error_message(context, ret,
1698                                        "samba_kdc_check_s4u2proxy:"
1699                                        " talloc_named() failed!");
1700                 return ret;
1701         }
1702
1703         client_dn = ldb_dn_get_linearized(p->msg->dn);
1704         if (!client_dn) {
1705                 if (errno == 0) {
1706                         errno = ENOMEM;
1707                 }
1708                 ret = errno;
1709                 krb5_set_error_message(context, ret,
1710                                        "samba_kdc_check_s4u2proxy:"
1711                                        " ldb_dn_get_linearized() failed!");
1712                 return ret;
1713         }
1714
1715         /*
1716          * The main heimdal code already checked that the target_principal
1717          * belongs to the same realm as the client.
1718          *
1719          * So we just need the principal without the realm,
1720          * as that is what is configured in the "msDS-AllowedToDelegateTo"
1721          * attribute.
1722          */
1723         ret = krb5_unparse_name_flags(context, target_principal,
1724                                       KRB5_PRINCIPAL_UNPARSE_NO_REALM, &tmp);
1725         if (ret) {
1726                 talloc_free(mem_ctx);
1727                 krb5_set_error_message(context, ret,
1728                                        "samba_kdc_check_s4u2proxy:"
1729                                        " krb5_unparse_name() failed!");
1730                 return ret;
1731         }
1732         DEBUG(10,("samba_kdc_check_s4u2proxy: client[%s] for target[%s]\n",
1733                  client_dn, tmp));
1734
1735         target_principal_name = talloc_strdup(mem_ctx, tmp);
1736         SAFE_FREE(tmp);
1737         if (target_principal_name == NULL) {
1738                 ret = ENOMEM;
1739                 krb5_set_error_message(context, ret,
1740                                        "samba_kdc_check_s4u2proxy:"
1741                                        " talloc_strdup() failed!");
1742                 return ret;
1743         }
1744
1745         el = ldb_msg_find_element(p->msg, "msDS-AllowedToDelegateTo");
1746         if (el == NULL) {
1747                 goto bad_option;
1748         }
1749
1750         val = data_blob_string_const(target_principal_name);
1751
1752         for (i=0; i<el->num_values; i++) {
1753                 struct ldb_val *val1 = &val;
1754                 struct ldb_val *val2 = &el->values[i];
1755                 int cmp;
1756
1757                 if (val1->length != val2->length) {
1758                         continue;
1759                 }
1760
1761                 cmp = strncasecmp((const char *)val1->data,
1762                                   (const char *)val2->data,
1763                                   val1->length);
1764                 if (cmp != 0) {
1765                         continue;
1766                 }
1767
1768                 found = true;
1769                 break;
1770         }
1771
1772         if (!found) {
1773                 goto bad_option;
1774         }
1775
1776         DEBUG(10,("samba_kdc_check_s4u2proxy: client[%s] allowed target[%s]\n",
1777                  client_dn, tmp));
1778         talloc_free(mem_ctx);
1779         return 0;
1780
1781 bad_option:
1782         krb5_set_error_message(context, ret,
1783                                "samba_kdc_check_s4u2proxy: client[%s] "
1784                                "not allowed for delegation to target[%s]",
1785                                client_dn,
1786                                target_principal_name);
1787         talloc_free(mem_ctx);
1788         return KRB5KDC_ERR_BADOPTION;
1789 }
1790
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)
1793 {
1794         int ldb_ret;
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
1800          * be circular.
1801          *
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
1804         */
1805
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;
1809         }
1810         kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
1811         kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
1812
1813         kdc_get_policy(base_ctx->lp_ctx, NULL, &kdc_db_ctx->policy);
1814
1815         session_info = system_session(kdc_db_ctx->lp_ctx);
1816         if (session_info == NULL) {
1817                 return NT_STATUS_INTERNAL_ERROR;
1818         }
1819
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;
1827         }
1828
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;
1836         }
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);
1842                 if (!server_dn) {
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;
1847                 }
1848
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;
1856                 }
1857
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;
1866                 }
1867
1868                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
1869                                           &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
1870                                           secondary_keytab,
1871                                           0,
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;
1880                 }
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),
1885                                   my_krbtgt_number));
1886                         talloc_free(kdc_db_ctx);
1887                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1888                 }
1889                 kdc_db_ctx->my_krbtgt_number = my_krbtgt_number;
1890
1891         } else {
1892                 kdc_db_ctx->my_krbtgt_number = 0;
1893                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
1894                                           &msg,
1895                                           ldb_get_default_basedn(kdc_db_ctx->samdb),
1896                                           LDB_SCOPE_SUBTREE,
1897                                           krbtgt_attrs,
1898                                           0,
1899                                           "(&(objectClass=user)(samAccountName=krbtgt))");
1900
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;
1905                 }
1906                 kdc_db_ctx->krbtgt_dn = talloc_steal(kdc_db_ctx, msg->dn);
1907                 kdc_db_ctx->my_krbtgt_number = 0;
1908                 talloc_free(msg);
1909         }
1910         *kdc_db_ctx_out = kdc_db_ctx;
1911         return NT_STATUS_OK;
1912 }