s4-kdc: treat a kvno of 255 as unspecified
[obnox/samba/samba-obnox.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,
1301                                           DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
1302                                           "(objectClass=*)");
1303                 if (ldb_ret != LDB_SUCCESS) {
1304                         return HDB_ERR_NOENTRY;
1305                 }
1306
1307         } else {
1308                 int lret;
1309                 char *filter = NULL;
1310                 char *short_princ;
1311                 const char *realm;
1312                 /* server as client principal case, but we must not lookup userPrincipalNames */
1313                 *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
1314                 realm = krb5_principal_get_realm(context, principal);
1315
1316                 /* TODO: Check if it is our realm, otherwise give referral */
1317
1318                 ret = krb5_unparse_name_flags(context, principal,  KRB5_PRINCIPAL_UNPARSE_NO_REALM, &short_princ);
1319
1320                 if (ret != 0) {
1321                         krb5_set_error_message(context, ret, "samba_kdc_lookup_principal: could not parse principal");
1322                         krb5_warnx(context, "samba_kdc_lookup_principal: could not parse principal");
1323                         return ret;
1324                 }
1325
1326                 lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx, msg,
1327                                        *realm_dn, LDB_SCOPE_SUBTREE,
1328                                        attrs,
1329                                        DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
1330                                        "(&(objectClass=user)(samAccountName=%s))",
1331                                        ldb_binary_encode_string(mem_ctx, short_princ));
1332                 free(short_princ);
1333                 if (lret == LDB_ERR_NO_SUCH_OBJECT) {
1334                         DEBUG(3, ("Failed find a entry for %s\n", filter));
1335                         return HDB_ERR_NOENTRY;
1336                 }
1337                 if (lret != LDB_SUCCESS) {
1338                         DEBUG(3, ("Failed single search for for %s - %s\n",
1339                                   filter, ldb_errstring(kdc_db_ctx->samdb)));
1340                         return HDB_ERR_NOENTRY;
1341                 }
1342         }
1343
1344         return 0;
1345 }
1346
1347 static krb5_error_code samba_kdc_fetch_server(krb5_context context,
1348                                               struct samba_kdc_db_context *kdc_db_ctx,
1349                                               TALLOC_CTX *mem_ctx,
1350                                               krb5_const_principal principal,
1351                                               unsigned flags,
1352                                               hdb_entry_ex *entry_ex)
1353 {
1354         krb5_error_code ret;
1355         struct ldb_dn *realm_dn;
1356         struct ldb_message *msg;
1357
1358         ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, principal,
1359                                        server_attrs, &realm_dn, &msg);
1360         if (ret != 0) {
1361                 return ret;
1362         }
1363
1364         ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1365                                       principal, SAMBA_KDC_ENT_TYPE_SERVER,
1366                                       flags,
1367                                       realm_dn, msg, entry_ex);
1368         if (ret != 0) {
1369                 krb5_warnx(context, "samba_kdc_fetch: message2entry failed");
1370         }
1371
1372         return ret;
1373 }
1374
1375 krb5_error_code samba_kdc_fetch(krb5_context context,
1376                                 struct samba_kdc_db_context *kdc_db_ctx,
1377                                 krb5_const_principal principal,
1378                                 unsigned flags,
1379                                 krb5_kvno kvno,
1380                                 hdb_entry_ex *entry_ex)
1381 {
1382         krb5_error_code ret = HDB_ERR_NOENTRY;
1383         TALLOC_CTX *mem_ctx;
1384         unsigned int krbtgt_number;
1385         /* w2k8r2 sometimes gives us a kvno of 255 for inter-domain
1386            trust tickets. We don't yet know what this means, but we do
1387            seem to need to treat it as unspecified */
1388         if ((flags & HDB_F_KVNO_SPECIFIED) && kvno != 255) {
1389                 krbtgt_number = SAMBA_KVNO_GET_KRBTGT(kvno);
1390                 if (kdc_db_ctx->rodc) {
1391                         if (krbtgt_number != kdc_db_ctx->my_krbtgt_number) {
1392                                 return HDB_ERR_NOT_FOUND_HERE;
1393                         }
1394                 }
1395         } else {
1396                 krbtgt_number = kdc_db_ctx->my_krbtgt_number;
1397         }
1398
1399         mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
1400         if (!mem_ctx) {
1401                 ret = ENOMEM;
1402                 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1403                 return ret;
1404         }
1405
1406         if (flags & HDB_F_GET_CLIENT) {
1407                 ret = samba_kdc_fetch_client(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
1408                 if (ret != HDB_ERR_NOENTRY) goto done;
1409         }
1410         if (flags & HDB_F_GET_SERVER) {
1411                 /* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
1412                 ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, krbtgt_number, entry_ex);
1413                 if (ret != HDB_ERR_NOENTRY) goto done;
1414
1415                 /* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
1416                 ret = samba_kdc_fetch_server(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
1417                 if (ret != HDB_ERR_NOENTRY) goto done;
1418         }
1419         if (flags & HDB_F_GET_KRBTGT) {
1420                 ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, krbtgt_number, entry_ex);
1421                 if (ret != HDB_ERR_NOENTRY) goto done;
1422         }
1423
1424 done:
1425         talloc_free(mem_ctx);
1426         return ret;
1427 }
1428
1429 struct samba_kdc_seq {
1430         unsigned int index;
1431         unsigned int count;
1432         struct ldb_message **msgs;
1433         struct ldb_dn *realm_dn;
1434 };
1435
1436 static krb5_error_code samba_kdc_seq(krb5_context context,
1437                                      struct samba_kdc_db_context *kdc_db_ctx,
1438                                      hdb_entry_ex *entry)
1439 {
1440         krb5_error_code ret;
1441         struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
1442         TALLOC_CTX *mem_ctx;
1443         hdb_entry_ex entry_ex;
1444         memset(&entry_ex, '\0', sizeof(entry_ex));
1445
1446         if (!priv) {
1447                 return HDB_ERR_NOENTRY;
1448         }
1449
1450         mem_ctx = talloc_named(priv, 0, "samba_kdc_seq context");
1451
1452         if (!mem_ctx) {
1453                 ret = ENOMEM;
1454                 krb5_set_error_message(context, ret, "samba_kdc_seq: talloc_named() failed!");
1455                 return ret;
1456         }
1457
1458         if (priv->index < priv->count) {
1459                 ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1460                                               NULL, SAMBA_KDC_ENT_TYPE_ANY,
1461                                               HDB_F_ADMIN_DATA|HDB_F_GET_ANY,
1462                                               priv->realm_dn, priv->msgs[priv->index++], entry);
1463         } else {
1464                 ret = HDB_ERR_NOENTRY;
1465         }
1466
1467         if (ret != 0) {
1468                 TALLOC_FREE(priv);
1469                 kdc_db_ctx->seq_ctx = NULL;
1470         } else {
1471                 talloc_free(mem_ctx);
1472         }
1473
1474         return ret;
1475 }
1476
1477 krb5_error_code samba_kdc_firstkey(krb5_context context,
1478                                    struct samba_kdc_db_context *kdc_db_ctx,
1479                                    hdb_entry_ex *entry)
1480 {
1481         struct ldb_context *ldb_ctx = kdc_db_ctx->samdb;
1482         struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
1483         char *realm;
1484         struct ldb_result *res = NULL;
1485         krb5_error_code ret;
1486         TALLOC_CTX *mem_ctx;
1487         int lret;
1488
1489         if (priv) {
1490                 TALLOC_FREE(priv);
1491                 kdc_db_ctx->seq_ctx = NULL;
1492         }
1493
1494         priv = (struct samba_kdc_seq *) talloc(kdc_db_ctx, struct samba_kdc_seq);
1495         if (!priv) {
1496                 ret = ENOMEM;
1497                 krb5_set_error_message(context, ret, "talloc: out of memory");
1498                 return ret;
1499         }
1500
1501         priv->index = 0;
1502         priv->msgs = NULL;
1503         priv->realm_dn = ldb_get_default_basedn(ldb_ctx);
1504         priv->count = 0;
1505
1506         mem_ctx = talloc_named(priv, 0, "samba_kdc_firstkey context");
1507
1508         if (!mem_ctx) {
1509                 ret = ENOMEM;
1510                 krb5_set_error_message(context, ret, "samba_kdc_firstkey: talloc_named() failed!");
1511                 return ret;
1512         }
1513
1514         ret = krb5_get_default_realm(context, &realm);
1515         if (ret != 0) {
1516                 TALLOC_FREE(priv);
1517                 return ret;
1518         }
1519
1520         lret = ldb_search(ldb_ctx, priv, &res,
1521                           priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs,
1522                           "(objectClass=user)");
1523
1524         if (lret != LDB_SUCCESS) {
1525                 TALLOC_FREE(priv);
1526                 return HDB_ERR_NOENTRY;
1527         }
1528
1529         priv->count = res->count;
1530         priv->msgs = talloc_steal(priv, res->msgs);
1531         talloc_free(res);
1532
1533         kdc_db_ctx->seq_ctx = priv;
1534
1535         ret = samba_kdc_seq(context, kdc_db_ctx, entry);
1536
1537         if (ret != 0) {
1538                 TALLOC_FREE(priv);
1539                 kdc_db_ctx->seq_ctx = NULL;
1540         } else {
1541                 talloc_free(mem_ctx);
1542         }
1543         return ret;
1544 }
1545
1546 krb5_error_code samba_kdc_nextkey(krb5_context context,
1547                                   struct samba_kdc_db_context *kdc_db_ctx,
1548                                   hdb_entry_ex *entry)
1549 {
1550         return samba_kdc_seq(context, kdc_db_ctx, entry);
1551 }
1552
1553 /* Check if a given entry may delegate or do s4u2self to this target principal
1554  *
1555  * This is currently a very nasty hack - allowing only delegation to itself.
1556  */
1557 krb5_error_code
1558 samba_kdc_check_s4u2self(krb5_context context,
1559                          struct samba_kdc_db_context *kdc_db_ctx,
1560                          hdb_entry_ex *entry,
1561                          krb5_const_principal target_principal)
1562 {
1563         krb5_error_code ret;
1564         krb5_principal enterprise_prinicpal = NULL;
1565         struct ldb_dn *realm_dn;
1566         struct ldb_message *msg;
1567         struct dom_sid *orig_sid;
1568         struct dom_sid *target_sid;
1569         struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1570         const char *delegation_check_attrs[] = {
1571                 "objectSid", NULL
1572         };
1573
1574         TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2self");
1575
1576         if (!mem_ctx) {
1577                 ret = ENOMEM;
1578                 krb5_set_error_message(context, ret, "samba_kdc_check_s4u2self: talloc_named() failed!");
1579                 return ret;
1580         }
1581
1582         if (target_principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
1583                 /* Need to reparse the enterprise principal to find the real target */
1584                 if (target_principal->name.name_string.len != 1) {
1585                         ret = KRB5_PARSE_MALFORMED;
1586                         krb5_set_error_message(context, ret, "samba_kdc_check_s4u2self: request for delegation to enterprise principal with wrong (%d) number of components",
1587                                                target_principal->name.name_string.len);
1588                         talloc_free(mem_ctx);
1589                         return ret;
1590                 }
1591                 ret = krb5_parse_name(context, target_principal->name.name_string.val[0],
1592                                       &enterprise_prinicpal);
1593                 if (ret) {
1594                         talloc_free(mem_ctx);
1595                         return ret;
1596                 }
1597                 target_principal = enterprise_prinicpal;
1598         }
1599
1600         ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, target_principal,
1601                                        delegation_check_attrs, &realm_dn, &msg);
1602
1603         krb5_free_principal(context, enterprise_prinicpal);
1604
1605         if (ret != 0) {
1606                 talloc_free(mem_ctx);
1607                 return ret;
1608         }
1609
1610         orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
1611         target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
1612
1613         /* Allow delegation to the same principal, even if by a different
1614          * name.  The easy and safe way to prove this is by SID
1615          * comparison */
1616         if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
1617                 talloc_free(mem_ctx);
1618                 return KRB5KDC_ERR_BADOPTION;
1619         }
1620
1621         talloc_free(mem_ctx);
1622         return ret;
1623 }
1624
1625 /* Certificates printed by a the Certificate Authority might have a
1626  * slightly different form of the user principal name to that in the
1627  * database.  Allow a mismatch where they both refer to the same
1628  * SID */
1629
1630 krb5_error_code
1631 samba_kdc_check_pkinit_ms_upn_match(krb5_context context,
1632                                     struct samba_kdc_db_context *kdc_db_ctx,
1633                                      hdb_entry_ex *entry,
1634                                      krb5_const_principal certificate_principal)
1635 {
1636         krb5_error_code ret;
1637         struct ldb_dn *realm_dn;
1638         struct ldb_message *msg;
1639         struct dom_sid *orig_sid;
1640         struct dom_sid *target_sid;
1641         struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1642         const char *ms_upn_check_attrs[] = {
1643                 "objectSid", NULL
1644         };
1645
1646         TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_pkinit_ms_upn_match");
1647
1648         if (!mem_ctx) {
1649                 ret = ENOMEM;
1650                 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1651                 return ret;
1652         }
1653
1654         ret = samba_kdc_lookup_client(context, kdc_db_ctx,
1655                                        mem_ctx, certificate_principal,
1656                                        ms_upn_check_attrs, &realm_dn, &msg);
1657
1658         if (ret != 0) {
1659                 talloc_free(mem_ctx);
1660                 return ret;
1661         }
1662
1663         orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
1664         target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
1665
1666         /* Consider these to be the same principal, even if by a different
1667          * name.  The easy and safe way to prove this is by SID
1668          * comparison */
1669         if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
1670                 talloc_free(mem_ctx);
1671                 return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1672         }
1673
1674         talloc_free(mem_ctx);
1675         return ret;
1676 }
1677
1678 /*
1679  * Check if a given entry may delegate to this target principal
1680  * with S4U2Proxy.
1681  */
1682 krb5_error_code
1683 samba_kdc_check_s4u2proxy(krb5_context context,
1684                           struct samba_kdc_db_context *kdc_db_ctx,
1685                           hdb_entry_ex *entry,
1686                           krb5_const_principal target_principal)
1687 {
1688         krb5_error_code ret;
1689         char *tmp = NULL;
1690         const char *client_dn = NULL;
1691         const char *target_principal_name = NULL;
1692         struct ldb_message_element *el;
1693         struct ldb_val val;
1694         unsigned int i;
1695         bool found = false;
1696         struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1697
1698         TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2proxy");
1699
1700         if (!mem_ctx) {
1701                 ret = ENOMEM;
1702                 krb5_set_error_message(context, ret,
1703                                        "samba_kdc_check_s4u2proxy:"
1704                                        " talloc_named() failed!");
1705                 return ret;
1706         }
1707
1708         client_dn = ldb_dn_get_linearized(p->msg->dn);
1709         if (!client_dn) {
1710                 if (errno == 0) {
1711                         errno = ENOMEM;
1712                 }
1713                 ret = errno;
1714                 krb5_set_error_message(context, ret,
1715                                        "samba_kdc_check_s4u2proxy:"
1716                                        " ldb_dn_get_linearized() failed!");
1717                 return ret;
1718         }
1719
1720         /*
1721          * The main heimdal code already checked that the target_principal
1722          * belongs to the same realm as the client.
1723          *
1724          * So we just need the principal without the realm,
1725          * as that is what is configured in the "msDS-AllowedToDelegateTo"
1726          * attribute.
1727          */
1728         ret = krb5_unparse_name_flags(context, target_principal,
1729                                       KRB5_PRINCIPAL_UNPARSE_NO_REALM, &tmp);
1730         if (ret) {
1731                 talloc_free(mem_ctx);
1732                 krb5_set_error_message(context, ret,
1733                                        "samba_kdc_check_s4u2proxy:"
1734                                        " krb5_unparse_name() failed!");
1735                 return ret;
1736         }
1737         DEBUG(10,("samba_kdc_check_s4u2proxy: client[%s] for target[%s]\n",
1738                  client_dn, tmp));
1739
1740         target_principal_name = talloc_strdup(mem_ctx, tmp);
1741         SAFE_FREE(tmp);
1742         if (target_principal_name == NULL) {
1743                 ret = ENOMEM;
1744                 krb5_set_error_message(context, ret,
1745                                        "samba_kdc_check_s4u2proxy:"
1746                                        " talloc_strdup() failed!");
1747                 return ret;
1748         }
1749
1750         el = ldb_msg_find_element(p->msg, "msDS-AllowedToDelegateTo");
1751         if (el == NULL) {
1752                 goto bad_option;
1753         }
1754
1755         val = data_blob_string_const(target_principal_name);
1756
1757         for (i=0; i<el->num_values; i++) {
1758                 struct ldb_val *val1 = &val;
1759                 struct ldb_val *val2 = &el->values[i];
1760                 int cmp;
1761
1762                 if (val1->length != val2->length) {
1763                         continue;
1764                 }
1765
1766                 cmp = strncasecmp((const char *)val1->data,
1767                                   (const char *)val2->data,
1768                                   val1->length);
1769                 if (cmp != 0) {
1770                         continue;
1771                 }
1772
1773                 found = true;
1774                 break;
1775         }
1776
1777         if (!found) {
1778                 goto bad_option;
1779         }
1780
1781         DEBUG(10,("samba_kdc_check_s4u2proxy: client[%s] allowed target[%s]\n",
1782                  client_dn, tmp));
1783         talloc_free(mem_ctx);
1784         return 0;
1785
1786 bad_option:
1787         krb5_set_error_message(context, ret,
1788                                "samba_kdc_check_s4u2proxy: client[%s] "
1789                                "not allowed for delegation to target[%s]",
1790                                client_dn,
1791                                target_principal_name);
1792         talloc_free(mem_ctx);
1793         return KRB5KDC_ERR_BADOPTION;
1794 }
1795
1796 NTSTATUS samba_kdc_setup_db_ctx(TALLOC_CTX *mem_ctx, struct samba_kdc_base_context *base_ctx,
1797                                 struct samba_kdc_db_context **kdc_db_ctx_out)
1798 {
1799         int ldb_ret;
1800         struct ldb_message *msg;
1801         struct auth_session_info *session_info;
1802         struct samba_kdc_db_context *kdc_db_ctx;
1803         /* The idea here is very simple.  Using Kerberos to
1804          * authenticate the KDC to the LDAP server is higly likely to
1805          * be circular.
1806          *
1807          * In future we may set this up to use EXERNAL and SSL
1808          * certificates, for now it will almost certainly be NTLMSSP_SET_USERNAME
1809         */
1810
1811         kdc_db_ctx = talloc_zero(mem_ctx, struct samba_kdc_db_context);
1812         if (kdc_db_ctx == NULL) {
1813                 return NT_STATUS_NO_MEMORY;
1814         }
1815         kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
1816         kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
1817
1818         kdc_get_policy(base_ctx->lp_ctx, NULL, &kdc_db_ctx->policy);
1819
1820         session_info = system_session(kdc_db_ctx->lp_ctx);
1821         if (session_info == NULL) {
1822                 return NT_STATUS_INTERNAL_ERROR;
1823         }
1824
1825         /* Setup the link to LDB */
1826         kdc_db_ctx->samdb = samdb_connect(kdc_db_ctx, base_ctx->ev_ctx,
1827                                           base_ctx->lp_ctx, session_info, 0);
1828         if (kdc_db_ctx->samdb == NULL) {
1829                 DEBUG(1, ("hdb_samba4_create: Cannot open samdb for KDC backend!"));
1830                 talloc_free(kdc_db_ctx);
1831                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1832         }
1833
1834         /* Find out our own krbtgt kvno */
1835         ldb_ret = samdb_rodc(kdc_db_ctx->samdb, &kdc_db_ctx->rodc);
1836         if (ldb_ret != LDB_SUCCESS) {
1837                 DEBUG(1, ("hdb_samba4_create: Cannot determine if we are an RODC in KDC backend: %s\n",
1838                           ldb_errstring(kdc_db_ctx->samdb)));
1839                 talloc_free(kdc_db_ctx);
1840                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1841         }
1842         if (kdc_db_ctx->rodc) {
1843                 int my_krbtgt_number;
1844                 const char *secondary_keytab[] = { "msDS-SecondaryKrbTgtNumber", NULL };
1845                 struct ldb_dn *account_dn;
1846                 struct ldb_dn *server_dn = samdb_server_dn(kdc_db_ctx->samdb, kdc_db_ctx);
1847                 if (!server_dn) {
1848                         DEBUG(1, ("hdb_samba4_create: Cannot determine server DN in KDC backend: %s\n",
1849                                   ldb_errstring(kdc_db_ctx->samdb)));
1850                         talloc_free(kdc_db_ctx);
1851                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1852                 }
1853
1854                 ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, server_dn,
1855                                              "serverReference", &account_dn);
1856                 if (ldb_ret != LDB_SUCCESS) {
1857                         DEBUG(1, ("hdb_samba4_create: Cannot determine server account in KDC backend: %s\n",
1858                                   ldb_errstring(kdc_db_ctx->samdb)));
1859                         talloc_free(kdc_db_ctx);
1860                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1861                 }
1862
1863                 ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, account_dn,
1864                                              "msDS-KrbTgtLink", &kdc_db_ctx->krbtgt_dn);
1865                 talloc_free(account_dn);
1866                 if (ldb_ret != LDB_SUCCESS) {
1867                         DEBUG(1, ("hdb_samba4_create: Cannot determine RODC krbtgt account in KDC backend: %s\n",
1868                                   ldb_errstring(kdc_db_ctx->samdb)));
1869                         talloc_free(kdc_db_ctx);
1870                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1871                 }
1872
1873                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
1874                                           &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
1875                                           secondary_keytab,
1876                                           0,
1877                                           "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=*))");
1878                 if (ldb_ret != LDB_SUCCESS) {
1879                         DEBUG(1, ("hdb_samba4_create: Cannot read krbtgt account %s in KDC backend to get msDS-SecondaryKrbTgtNumber: %s: %s\n",
1880                                   ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
1881                                   ldb_errstring(kdc_db_ctx->samdb),
1882                                   ldb_strerror(ldb_ret)));
1883                         talloc_free(kdc_db_ctx);
1884                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1885                 }
1886                 my_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
1887                 if (my_krbtgt_number == -1) {
1888                         DEBUG(1, ("hdb_samba4_create: Cannot read msDS-SecondaryKrbTgtNumber from krbtgt account %s in KDC backend: got %d\n",
1889                                   ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
1890                                   my_krbtgt_number));
1891                         talloc_free(kdc_db_ctx);
1892                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1893                 }
1894                 kdc_db_ctx->my_krbtgt_number = my_krbtgt_number;
1895
1896         } else {
1897                 kdc_db_ctx->my_krbtgt_number = 0;
1898                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
1899                                           &msg,
1900                                           ldb_get_default_basedn(kdc_db_ctx->samdb),
1901                                           LDB_SCOPE_SUBTREE,
1902                                           krbtgt_attrs,
1903                                           0,
1904                                           "(&(objectClass=user)(samAccountName=krbtgt))");
1905
1906                 if (ldb_ret != LDB_SUCCESS) {
1907                         DEBUG(1, ("samba_kdc_fetch: could not find own KRBTGT in DB: %s\n", ldb_errstring(kdc_db_ctx->samdb)));
1908                         talloc_free(kdc_db_ctx);
1909                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1910                 }
1911                 kdc_db_ctx->krbtgt_dn = talloc_steal(kdc_db_ctx, msg->dn);
1912                 kdc_db_ctx->my_krbtgt_number = 0;
1913                 talloc_free(msg);
1914         }
1915         *kdc_db_ctx_out = kdc_db_ctx;
1916         return NT_STATUS_OK;
1917 }