ed64685a4fc2cff11c8edcb68dd4901d9c594e52
[kai/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-policy.h"
38
39 enum samba_kdc_ent_type
40 { SAMBA_KDC_ENT_TYPE_CLIENT, SAMBA_KDC_ENT_TYPE_SERVER,
41   SAMBA_KDC_ENT_TYPE_KRBTGT, SAMBA_KDC_ENT_TYPE_TRUST, SAMBA_KDC_ENT_TYPE_ANY };
42
43 enum trust_direction {
44         UNKNOWN = 0,
45         INBOUND = LSA_TRUST_DIRECTION_INBOUND,
46         OUTBOUND = LSA_TRUST_DIRECTION_OUTBOUND
47 };
48
49 static const char *trust_attrs[] = {
50         "trustPartner",
51         "trustAuthIncoming",
52         "trustAuthOutgoing",
53         "whenCreated",
54         "msDS-SupportedEncryptionTypes",
55         "trustAttributes",
56         "trustDirection",
57         "trustType",
58         NULL
59 };
60
61 static KerberosTime ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const char *attr, KerberosTime default_val)
62 {
63     const char *tmp;
64     const char *gentime;
65     struct tm tm;
66
67     gentime = ldb_msg_find_attr_as_string(msg, attr, NULL);
68     if (!gentime)
69         return default_val;
70
71     tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm);
72     if (tmp == NULL) {
73             return default_val;
74     }
75
76     return timegm(&tm);
77 }
78
79 static HDBFlags uf2HDBFlags(krb5_context context, uint32_t userAccountControl, enum samba_kdc_ent_type ent_type)
80 {
81         HDBFlags flags = int2HDBFlags(0);
82
83         /* we don't allow kadmin deletes */
84         flags.immutable = 1;
85
86         /* mark the principal as invalid to start with */
87         flags.invalid = 1;
88
89         flags.renewable = 1;
90
91         /* All accounts are servers, but this may be disabled again in the caller */
92         flags.server = 1;
93
94         /* Account types - clear the invalid bit if it turns out to be valid */
95         if (userAccountControl & UF_NORMAL_ACCOUNT) {
96                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
97                         flags.client = 1;
98                 }
99                 flags.invalid = 0;
100         }
101
102         if (userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
103                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
104                         flags.client = 1;
105                 }
106                 flags.invalid = 0;
107         }
108         if (userAccountControl & UF_WORKSTATION_TRUST_ACCOUNT) {
109                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
110                         flags.client = 1;
111                 }
112                 flags.invalid = 0;
113         }
114         if (userAccountControl & UF_SERVER_TRUST_ACCOUNT) {
115                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
116                         flags.client = 1;
117                 }
118                 flags.invalid = 0;
119         }
120
121         /* Not permitted to act as a client if disabled */
122         if (userAccountControl & UF_ACCOUNTDISABLE) {
123                 flags.client = 0;
124         }
125         if (userAccountControl & UF_LOCKOUT) {
126                 flags.invalid = 1;
127         }
128 /*
129         if (userAccountControl & UF_PASSWORD_NOTREQD) {
130                 flags.invalid = 1;
131         }
132 */
133 /*
134         UF_PASSWORD_CANT_CHANGE and UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED are irrelevent
135 */
136         if (userAccountControl & UF_TEMP_DUPLICATE_ACCOUNT) {
137                 flags.invalid = 1;
138         }
139
140 /* UF_DONT_EXPIRE_PASSWD and UF_USE_DES_KEY_ONLY handled in samba_kdc_message2entry() */
141
142 /*
143         if (userAccountControl & UF_MNS_LOGON_ACCOUNT) {
144                 flags.invalid = 1;
145         }
146 */
147         if (userAccountControl & UF_SMARTCARD_REQUIRED) {
148                 flags.require_hwauth = 1;
149         }
150         if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) {
151                 flags.ok_as_delegate = 1;
152         }
153         if (!(userAccountControl & UF_NOT_DELEGATED)) {
154                 flags.forwardable = 1;
155                 flags.proxiable = 1;
156         }
157
158         if (userAccountControl & UF_DONT_REQUIRE_PREAUTH) {
159                 flags.require_preauth = 0;
160         } else {
161                 flags.require_preauth = 1;
162
163         }
164         return flags;
165 }
166
167 static int samba_kdc_entry_destructor(struct samba_kdc_entry *p)
168 {
169     hdb_entry_ex *entry_ex = p->entry_ex;
170     free_hdb_entry(&entry_ex->entry);
171     return 0;
172 }
173
174 static void samba_kdc_free_entry(krb5_context context, hdb_entry_ex *entry_ex)
175 {
176         /* this function is called only from hdb_free_entry().
177          * Make sure we neutralize the destructor or we will
178          * get a double free later when hdb_free_entry() will
179          * try to call free_hdb_entry() */
180         talloc_set_destructor(entry_ex->ctx, NULL);
181
182         /* now proceed to free the talloc part */
183         talloc_free(entry_ex->ctx);
184 }
185
186 static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
187                                                     struct samba_kdc_db_context *kdc_db_ctx,
188                                                     TALLOC_CTX *mem_ctx,
189                                                     struct ldb_message *msg,
190                                                     uint32_t rid,
191                                                     bool is_rodc,
192                                                     uint32_t userAccountControl,
193                                                     enum samba_kdc_ent_type ent_type,
194                                                     hdb_entry_ex *entry_ex)
195 {
196         krb5_error_code ret = 0;
197         enum ndr_err_code ndr_err;
198         struct samr_Password *hash;
199         const struct ldb_val *sc_val;
200         struct supplementalCredentialsBlob scb;
201         struct supplementalCredentialsPackage *scpk = NULL;
202         bool newer_keys = false;
203         struct package_PrimaryKerberosBlob _pkb;
204         struct package_PrimaryKerberosCtr3 *pkb3 = NULL;
205         struct package_PrimaryKerberosCtr4 *pkb4 = NULL;
206         uint16_t i;
207         uint16_t allocated_keys = 0;
208         int rodc_krbtgt_number = 0;
209         uint32_t supported_enctypes
210                 = ldb_msg_find_attr_as_uint(msg,
211                                             "msDS-SupportedEncryptionTypes",
212                                             0);
213
214         if (rid == DOMAIN_RID_KRBTGT || is_rodc) {
215                 /* KDCs (and KDCs on RODCs) use AES */
216                 supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
217         } else if (userAccountControl & (UF_PARTIAL_SECRETS_ACCOUNT|UF_SERVER_TRUST_ACCOUNT)) {
218                 /* DCs and RODCs comptuer accounts use AES */
219                 supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
220         } else if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT ||
221                    (ent_type == SAMBA_KDC_ENT_TYPE_ANY)) {
222                 /* for AS-REQ the client chooses the enc types it
223                  * supports, and this will vary between computers a
224                  * user logs in from.
225                  *
226                  * likewise for 'any' return as much as is supported,
227                  * to export into a keytab */
228                 supported_enctypes = ENC_ALL_TYPES;
229         }
230
231         /* If UF_USE_DES_KEY_ONLY has been set, then don't allow use of the newer enc types */
232         if (userAccountControl & UF_USE_DES_KEY_ONLY) {
233                 supported_enctypes = ENC_CRC32|ENC_RSA_MD5;
234         } else {
235                 /* Otherwise, add in the default enc types */
236                 supported_enctypes |= ENC_CRC32 | ENC_RSA_MD5 | ENC_RC4_HMAC_MD5;
237         }
238
239         /* Is this the krbtgt or a RODC krbtgt */
240         if (is_rodc) {
241                 rodc_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
242
243                 if (rodc_krbtgt_number == -1) {
244                         return EINVAL;
245                 }
246         }
247
248
249         entry_ex->entry.keys.val = NULL;
250         entry_ex->entry.keys.len = 0;
251
252         entry_ex->entry.kvno = ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0);
253         if (is_rodc) {
254                 entry_ex->entry.kvno |= (rodc_krbtgt_number << 16);
255         }
256
257         /* Get keys from the db */
258
259         hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
260         sc_val = ldb_msg_find_ldb_val(msg, "supplementalCredentials");
261
262         /* unicodePwd for enctype 0x17 (23) if present */
263         if (hash) {
264                 allocated_keys++;
265         }
266
267         /* supplementalCredentials if present */
268         if (sc_val) {
269                 ndr_err = ndr_pull_struct_blob_all(sc_val, mem_ctx, &scb,
270                                                    (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
271                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
272                         dump_data(0, sc_val->data, sc_val->length);
273                         ret = EINVAL;
274                         goto out;
275                 }
276
277                 if (scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
278                         NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
279                         ret = EINVAL;
280                         goto out;
281                 }
282
283                 for (i=0; i < scb.sub.num_packages; i++) {
284                         if (strcmp("Primary:Kerberos-Newer-Keys", scb.sub.packages[i].name) == 0) {
285                                 scpk = &scb.sub.packages[i];
286                                 if (!scpk->data || !scpk->data[0]) {
287                                         scpk = NULL;
288                                         continue;
289                                 }
290                                 newer_keys = true;
291                                 break;
292                         } else if (strcmp("Primary:Kerberos", scb.sub.packages[i].name) == 0) {
293                                 scpk = &scb.sub.packages[i];
294                                 if (!scpk->data || !scpk->data[0]) {
295                                         scpk = NULL;
296                                 }
297                                 /*
298                                  * we don't break here in hope to find
299                                  * a Kerberos-Newer-Keys package
300                                  */
301                         }
302                 }
303         }
304         /*
305          * Primary:Kerberos-Newer-Keys or Primary:Kerberos element
306          * of supplementalCredentials
307          */
308         if (scpk) {
309                 DATA_BLOB blob;
310
311                 blob = strhex_to_data_blob(mem_ctx, scpk->data);
312                 if (!blob.data) {
313                         ret = ENOMEM;
314                         goto out;
315                 }
316
317                 /* we cannot use ndr_pull_struct_blob_all() here, as w2k and w2k3 add padding bytes */
318                 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &_pkb,
319                                                (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
320                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
321                         ret = EINVAL;
322                         krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: could not parse package_PrimaryKerberosBlob");
323                         krb5_warnx(context, "samba_kdc_message2entry_keys: could not parse package_PrimaryKerberosBlob");
324                         goto out;
325                 }
326
327                 if (newer_keys && _pkb.version != 4) {
328                         ret = EINVAL;
329                         krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4");
330                         krb5_warnx(context, "samba_kdc_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4");
331                         goto out;
332                 }
333
334                 if (!newer_keys && _pkb.version != 3) {
335                         ret = EINVAL;
336                         krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: could not parse Primary:Kerberos not version 3");
337                         krb5_warnx(context, "samba_kdc_message2entry_keys: could not parse Primary:Kerberos not version 3");
338                         goto out;
339                 }
340
341                 if (_pkb.version == 4) {
342                         pkb4 = &_pkb.ctr.ctr4;
343                         allocated_keys += pkb4->num_keys;
344                 } else if (_pkb.version == 3) {
345                         pkb3 = &_pkb.ctr.ctr3;
346                         allocated_keys += pkb3->num_keys;
347                 }
348         }
349
350         if (allocated_keys == 0) {
351                 if (kdc_db_ctx->rodc) {
352                         /* We are on an RODC, but don't have keys for this account.  Signal this to the caller */
353                         return HDB_ERR_NOT_FOUND_HERE;
354                 }
355
356                 /* oh, no password.  Apparently (comment in
357                  * hdb-ldap.c) this violates the ASN.1, but this
358                  * allows an entry with no keys (yet). */
359                 return 0;
360         }
361
362         /* allocate space to decode into */
363         entry_ex->entry.keys.len = 0;
364         entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(Key));
365         if (entry_ex->entry.keys.val == NULL) {
366                 ret = ENOMEM;
367                 goto out;
368         }
369
370         if (hash && (supported_enctypes & ENC_RC4_HMAC_MD5)) {
371                 Key key;
372
373                 key.mkvno = 0;
374                 key.salt = NULL; /* No salt for this enc type */
375
376                 ret = krb5_keyblock_init(context,
377                                          ENCTYPE_ARCFOUR_HMAC,
378                                          hash->hash, sizeof(hash->hash),
379                                          &key.key);
380                 if (ret) {
381                         goto out;
382                 }
383
384                 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
385                 entry_ex->entry.keys.len++;
386         }
387
388         if (pkb4) {
389                 for (i=0; i < pkb4->num_keys; i++) {
390                         Key key;
391
392                         if (!pkb4->keys[i].value) continue;
393
394                         if (!(kerberos_enctype_to_bitmap(pkb4->keys[i].keytype) & supported_enctypes)) {
395                                 continue;
396                         }
397
398                         key.mkvno = 0;
399                         key.salt = NULL;
400
401                         if (pkb4->salt.string) {
402                                 DATA_BLOB salt;
403
404                                 salt = data_blob_string_const(pkb4->salt.string);
405
406                                 key.salt = calloc(1, sizeof(*key.salt));
407                                 if (key.salt == NULL) {
408                                         ret = ENOMEM;
409                                         goto out;
410                                 }
411
412                                 key.salt->type = hdb_pw_salt;
413
414                                 ret = krb5_data_copy(&key.salt->salt, salt.data, salt.length);
415                                 if (ret) {
416                                         free(key.salt);
417                                         key.salt = NULL;
418                                         goto out;
419                                 }
420                         }
421
422                         /* TODO: maybe pass the iteration_count somehow... */
423
424                         ret = krb5_keyblock_init(context,
425                                                  pkb4->keys[i].keytype,
426                                                  pkb4->keys[i].value->data,
427                                                  pkb4->keys[i].value->length,
428                                                  &key.key);
429                         if (ret == KRB5_PROG_ETYPE_NOSUPP) {
430                                 DEBUG(2,("Unsupported keytype ignored - type %u\n",
431                                          pkb4->keys[i].keytype));
432                                 ret = 0;
433                                 continue;
434                         }
435                         if (ret) {
436                                 if (key.salt) {
437                                         free_Salt(key.salt);
438                                         free(key.salt);
439                                         key.salt = NULL;
440                                 }
441                                 goto out;
442                         }
443
444                         entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
445                         entry_ex->entry.keys.len++;
446                 }
447         } else if (pkb3) {
448                 for (i=0; i < pkb3->num_keys; i++) {
449                         Key key;
450
451                         if (!pkb3->keys[i].value) continue;
452
453                         if (!(kerberos_enctype_to_bitmap(pkb3->keys[i].keytype) & supported_enctypes)) {
454                                 continue;
455                         }
456
457                         key.mkvno = 0;
458                         key.salt = NULL;
459
460                         if (pkb3->salt.string) {
461                                 DATA_BLOB salt;
462
463                                 salt = data_blob_string_const(pkb3->salt.string);
464
465                                 key.salt = calloc(1, sizeof(*key.salt));
466                                 if (key.salt == NULL) {
467                                         ret = ENOMEM;
468                                         goto out;
469                                 }
470
471                                 key.salt->type = hdb_pw_salt;
472
473                                 ret = krb5_data_copy(&key.salt->salt, salt.data, salt.length);
474                                 if (ret) {
475                                         free(key.salt);
476                                         key.salt = NULL;
477                                         goto out;
478                                 }
479                         }
480
481                         ret = krb5_keyblock_init(context,
482                                                  pkb3->keys[i].keytype,
483                                                  pkb3->keys[i].value->data,
484                                                  pkb3->keys[i].value->length,
485                                                  &key.key);
486                         if (ret) {
487                                 if (key.salt) {
488                                         free_Salt(key.salt);
489                                         free(key.salt);
490                                         key.salt = NULL;
491                                 }
492                                 goto out;
493                         }
494
495                         entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
496                         entry_ex->entry.keys.len++;
497                 }
498         }
499
500 out:
501         if (ret != 0) {
502                 entry_ex->entry.keys.len = 0;
503         }
504         if (entry_ex->entry.keys.len == 0 && entry_ex->entry.keys.val) {
505                 free(entry_ex->entry.keys.val);
506                 entry_ex->entry.keys.val = NULL;
507         }
508         return ret;
509 }
510
511 /*
512  * Construct an hdb_entry from a directory entry.
513  */
514 static krb5_error_code samba_kdc_message2entry(krb5_context context,
515                                                struct samba_kdc_db_context *kdc_db_ctx,
516                                                TALLOC_CTX *mem_ctx, krb5_const_principal principal,
517                                                enum samba_kdc_ent_type ent_type,
518                                                unsigned flags,
519                                                struct ldb_dn *realm_dn,
520                                                struct ldb_message *msg,
521                                                hdb_entry_ex *entry_ex)
522 {
523         struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
524         uint32_t userAccountControl;
525         unsigned int i;
526         krb5_error_code ret = 0;
527         krb5_boolean is_computer = FALSE;
528
529         struct samba_kdc_entry *p;
530         NTTIME acct_expiry;
531         NTSTATUS status;
532
533         uint32_t rid;
534         bool is_rodc = false;
535         struct ldb_message_element *objectclasses;
536         struct ldb_val computer_val;
537         const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
538         computer_val.data = discard_const_p(uint8_t,"computer");
539         computer_val.length = strlen((const char *)computer_val.data);
540
541         if (ldb_msg_find_element(msg, "msDS-SecondaryKrbTgtNumber")) {
542                 is_rodc = true;
543         }
544
545         if (!samAccountName) {
546                 ret = ENOENT;
547                 krb5_set_error_message(context, ret, "samba_kdc_message2entry: no samAccountName present");
548                 goto out;
549         }
550
551         objectclasses = ldb_msg_find_element(msg, "objectClass");
552
553         if (objectclasses && ldb_msg_find_val(objectclasses, &computer_val)) {
554                 is_computer = TRUE;
555         }
556
557         memset(entry_ex, 0, sizeof(*entry_ex));
558
559         p = talloc(mem_ctx, struct samba_kdc_entry);
560         if (!p) {
561                 ret = ENOMEM;
562                 goto out;
563         }
564
565         p->kdc_db_ctx = kdc_db_ctx;
566         p->entry_ex = entry_ex;
567         p->realm_dn = talloc_reference(p, realm_dn);
568         if (!p->realm_dn) {
569                 ret = ENOMEM;
570                 goto out;
571         }
572
573         talloc_set_destructor(p, samba_kdc_entry_destructor);
574
575         /* make sure we do not have bogus data in there */
576         memset(&entry_ex->entry, 0, sizeof(hdb_entry));
577
578         entry_ex->ctx = p;
579         entry_ex->free_entry = samba_kdc_free_entry;
580
581         userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
582
583
584         entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal)));
585         if (ent_type == SAMBA_KDC_ENT_TYPE_ANY && principal == NULL) {
586                 krb5_make_principal(context, &entry_ex->entry.principal, lpcfg_realm(lp_ctx), samAccountName, NULL);
587         } else {
588                 ret = copy_Principal(principal, entry_ex->entry.principal);
589                 if (ret) {
590                         krb5_clear_error_message(context);
591                         goto out;
592                 }
593
594                 /* While we have copied the client principal, tests
595                  * show that Win2k3 returns the 'corrected' realm, not
596                  * the client-specified realm.  This code attempts to
597                  * replace the client principal's realm with the one
598                  * we determine from our records */
599
600                 /* this has to be with malloc() */
601                 krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
602         }
603
604         /* First try and figure out the flags based on the userAccountControl */
605         entry_ex->entry.flags = uf2HDBFlags(context, userAccountControl, ent_type);
606
607         /* Windows 2008 seems to enforce this (very sensible) rule by
608          * default - don't allow offline attacks on a user's password
609          * by asking for a ticket to them as a service (encrypted with
610          * their probably patheticly insecure password) */
611
612         if (entry_ex->entry.flags.server
613             && lpcfg_parm_bool(lp_ctx, NULL, "kdc", "require spn for service", true)) {
614                 if (!is_computer && !ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL)) {
615                         entry_ex->entry.flags.server = 0;
616                 }
617         }
618
619         if (flags & HDB_F_ADMIN_DATA) {
620                 /* These (created_by, modified_by) parts of the entry are not relevant for Samba4's use
621                  * of the Heimdal KDC.  They are stored in a the traditional
622                  * DB for audit purposes, and still form part of the structure
623                  * we must return */
624
625                 /* use 'whenCreated' */
626                 entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
627                 /* use 'kadmin' for now (needed by mit_samba) */
628                 krb5_make_principal(context,
629                                     &entry_ex->entry.created_by.principal,
630                                     lpcfg_realm(lp_ctx), "kadmin", NULL);
631
632                 entry_ex->entry.modified_by = (Event *) malloc(sizeof(Event));
633                 if (entry_ex->entry.modified_by == NULL) {
634                         ret = ENOMEM;
635                         krb5_set_error_message(context, ret, "malloc: out of memory");
636                         goto out;
637                 }
638
639                 /* use 'whenChanged' */
640                 entry_ex->entry.modified_by->time = ldb_msg_find_krb5time_ldap_time(msg, "whenChanged", 0);
641                 /* use 'kadmin' for now (needed by mit_samba) */
642                 krb5_make_principal(context,
643                                     &entry_ex->entry.modified_by->principal,
644                                     lpcfg_realm(lp_ctx), "kadmin", NULL);
645         }
646
647
648         /* The lack of password controls etc applies to krbtgt by
649          * virtue of being that particular RID */
650         status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, msg, "objectSid"), NULL, &rid);
651
652         if (!NT_STATUS_IS_OK(status)) {
653                 ret = EINVAL;
654                 goto out;
655         }
656
657         if (rid == DOMAIN_RID_KRBTGT) {
658                 entry_ex->entry.valid_end = NULL;
659                 entry_ex->entry.pw_end = NULL;
660
661                 entry_ex->entry.flags.invalid = 0;
662                 entry_ex->entry.flags.server = 1;
663
664                 /* Don't mark all requests for the krbtgt/realm as
665                  * 'change password', as otherwise we could get into
666                  * trouble, and not enforce the password expirty.
667                  * Instead, only do it when request is for the kpasswd service */
668                 if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER
669                     && principal->name.name_string.len == 2
670                     && (strcmp(principal->name.name_string.val[0], "kadmin") == 0)
671                     && (strcmp(principal->name.name_string.val[1], "changepw") == 0)
672                     && lpcfg_is_my_domain_or_realm(lp_ctx, principal->realm)) {
673                         entry_ex->entry.flags.change_pw = 1;
674                 }
675                 entry_ex->entry.flags.client = 0;
676                 entry_ex->entry.flags.forwardable = 1;
677                 entry_ex->entry.flags.ok_as_delegate = 1;
678         } else if (is_rodc) {
679                 /* The RODC krbtgt account is like the main krbtgt,
680                  * but it does not have a changepw or kadmin
681                  * service */
682
683                 entry_ex->entry.valid_end = NULL;
684                 entry_ex->entry.pw_end = NULL;
685
686                 /* Also don't allow the RODC krbtgt to be a client (it should not be needed) */
687                 entry_ex->entry.flags.client = 0;
688                 entry_ex->entry.flags.invalid = 0;
689                 entry_ex->entry.flags.server = 1;
690
691                 entry_ex->entry.flags.client = 0;
692                 entry_ex->entry.flags.forwardable = 1;
693                 entry_ex->entry.flags.ok_as_delegate = 0;
694         } else if (entry_ex->entry.flags.server && ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
695                 /* The account/password expiry only applies when the account is used as a
696                  * client (ie password login), not when used as a server */
697
698                 /* Make very well sure we don't use this for a client,
699                  * it could bypass the password restrictions */
700                 entry_ex->entry.flags.client = 0;
701
702                 entry_ex->entry.valid_end = NULL;
703                 entry_ex->entry.pw_end = NULL;
704
705         } else {
706                 NTTIME must_change_time
707                         = samdb_result_force_password_change(kdc_db_ctx->samdb, mem_ctx,
708                                                              realm_dn, msg);
709                 if (must_change_time == 0x7FFFFFFFFFFFFFFFULL) {
710                         entry_ex->entry.pw_end = NULL;
711                 } else {
712                         entry_ex->entry.pw_end = malloc(sizeof(*entry_ex->entry.pw_end));
713                         if (entry_ex->entry.pw_end == NULL) {
714                                 ret = ENOMEM;
715                                 goto out;
716                         }
717                         *entry_ex->entry.pw_end = nt_time_to_unix(must_change_time);
718                 }
719
720                 acct_expiry = samdb_result_account_expires(msg);
721                 if (acct_expiry == 0x7FFFFFFFFFFFFFFFULL) {
722                         entry_ex->entry.valid_end = NULL;
723                 } else {
724                         entry_ex->entry.valid_end = malloc(sizeof(*entry_ex->entry.valid_end));
725                         if (entry_ex->entry.valid_end == NULL) {
726                                 ret = ENOMEM;
727                                 goto out;
728                         }
729                         *entry_ex->entry.valid_end = nt_time_to_unix(acct_expiry);
730                 }
731         }
732
733         entry_ex->entry.valid_start = NULL;
734
735         entry_ex->entry.max_life = malloc(sizeof(*entry_ex->entry.max_life));
736         if (entry_ex->entry.max_life == NULL) {
737                 ret = ENOMEM;
738                 goto out;
739         }
740
741         if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
742                 *entry_ex->entry.max_life = nt_time_to_unix(kdc_db_ctx->policy.service_tkt_lifetime);
743         } else if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT || ent_type == SAMBA_KDC_ENT_TYPE_CLIENT) {
744                 *entry_ex->entry.max_life = nt_time_to_unix(kdc_db_ctx->policy.user_tkt_lifetime);
745         } else {
746                 *entry_ex->entry.max_life = MIN(nt_time_to_unix(kdc_db_ctx->policy.service_tkt_lifetime),
747                                                nt_time_to_unix(kdc_db_ctx->policy.user_tkt_lifetime));
748         }
749
750         entry_ex->entry.max_renew = malloc(sizeof(*entry_ex->entry.max_life));
751         if (entry_ex->entry.max_renew == NULL) {
752                 ret = ENOMEM;
753                 goto out;
754         }
755
756         *entry_ex->entry.max_renew = nt_time_to_unix(kdc_db_ctx->policy.user_tkt_renewaltime);
757
758         entry_ex->entry.generation = NULL;
759
760         /* Get keys from the db */
761         ret = samba_kdc_message2entry_keys(context, kdc_db_ctx, p, msg,
762                                            rid, is_rodc, userAccountControl,
763                                            ent_type, entry_ex);
764         if (ret) {
765                 /* Could be bougus data in the entry, or out of memory */
766                 goto out;
767         }
768
769         entry_ex->entry.etypes = malloc(sizeof(*(entry_ex->entry.etypes)));
770         if (entry_ex->entry.etypes == NULL) {
771                 krb5_clear_error_message(context);
772                 ret = ENOMEM;
773                 goto out;
774         }
775         entry_ex->entry.etypes->len = entry_ex->entry.keys.len;
776         entry_ex->entry.etypes->val = calloc(entry_ex->entry.etypes->len, sizeof(int));
777         if (entry_ex->entry.etypes->val == NULL) {
778                 krb5_clear_error_message(context);
779                 ret = ENOMEM;
780                 goto out;
781         }
782         for (i=0; i < entry_ex->entry.etypes->len; i++) {
783                 entry_ex->entry.etypes->val[i] = entry_ex->entry.keys.val[i].key.keytype;
784         }
785
786
787         p->msg = talloc_steal(p, msg);
788
789 out:
790         if (ret != 0) {
791                 /* This doesn't free ent itself, that is for the eventual caller to do */
792                 hdb_free_entry(context, entry_ex);
793         } else {
794                 talloc_steal(kdc_db_ctx, entry_ex->ctx);
795         }
796
797         return ret;
798 }
799
800 /*
801  * Construct an hdb_entry from a directory entry.
802  */
803 static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
804                                                struct samba_kdc_db_context *kdc_db_ctx,
805                                                TALLOC_CTX *mem_ctx, krb5_const_principal principal,
806                                                enum trust_direction direction,
807                                                struct ldb_dn *realm_dn,
808                                                struct ldb_message *msg,
809                                                hdb_entry_ex *entry_ex)
810 {
811         struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
812         const char *dnsdomain;
813         const char *realm = lpcfg_realm(lp_ctx);
814         DATA_BLOB password_utf16;
815         struct samr_Password password_hash;
816         const struct ldb_val *password_val;
817         struct trustAuthInOutBlob password_blob;
818         struct samba_kdc_entry *p;
819
820         enum ndr_err_code ndr_err;
821         int ret, trust_direction_flags;
822         unsigned int i;
823
824         p = talloc(mem_ctx, struct samba_kdc_entry);
825         if (!p) {
826                 ret = ENOMEM;
827                 goto out;
828         }
829
830         p->kdc_db_ctx = kdc_db_ctx;
831         p->entry_ex = entry_ex;
832         p->realm_dn = realm_dn;
833
834         talloc_set_destructor(p, samba_kdc_entry_destructor);
835
836         /* make sure we do not have bogus data in there */
837         memset(&entry_ex->entry, 0, sizeof(hdb_entry));
838
839         entry_ex->ctx = p;
840         entry_ex->free_entry = samba_kdc_free_entry;
841
842         /* use 'whenCreated' */
843         entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
844         /* use 'kadmin' for now (needed by mit_samba) */
845         krb5_make_principal(context,
846                             &entry_ex->entry.created_by.principal,
847                             realm, "kadmin", NULL);
848
849         entry_ex->entry.valid_start = NULL;
850
851         trust_direction_flags = ldb_msg_find_attr_as_int(msg, "trustDirection", 0);
852
853         if (direction == INBOUND) {
854                 password_val = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
855
856         } else { /* OUTBOUND */
857                 dnsdomain = ldb_msg_find_attr_as_string(msg, "trustPartner", NULL);
858                 /* replace realm */
859                 realm = strupper_talloc(mem_ctx, dnsdomain);
860                 password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
861         }
862
863         if (!password_val || !(trust_direction_flags & direction)) {
864                 ret = ENOENT;
865                 goto out;
866         }
867
868         ndr_err = ndr_pull_struct_blob(password_val, mem_ctx, &password_blob,
869                                            (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
870         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
871                 ret = EINVAL;
872                 goto out;
873         }
874
875         entry_ex->entry.kvno = -1;
876         for (i=0; i < password_blob.count; i++) {
877                 if (password_blob.current.array[i].AuthType == TRUST_AUTH_TYPE_VERSION) {
878                         entry_ex->entry.kvno = password_blob.current.array[i].AuthInfo.version.version;
879                 }
880         }
881
882         for (i=0; i < password_blob.count; i++) {
883                 if (password_blob.current.array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
884                         password_utf16 = data_blob_const(password_blob.current.array[i].AuthInfo.clear.password,
885                                                          password_blob.current.array[i].AuthInfo.clear.size);
886                         /* In the future, generate all sorts of
887                          * hashes, but for now we can't safely convert
888                          * the random strings windows uses into
889                          * utf8 */
890
891                         /* but as it is utf16 already, we can get the NT password/arcfour-hmac-md5 key */
892                         mdfour(password_hash.hash, password_utf16.data, password_utf16.length);
893                         break;
894                 } else if (password_blob.current.array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
895                         password_hash = password_blob.current.array[i].AuthInfo.nt4owf.password;
896                         break;
897                 }
898         }
899
900         if (i < password_blob.count) {
901                 Key key;
902                 /* Must have found a cleartext or MD4 password */
903                 entry_ex->entry.keys.val = calloc(1, sizeof(Key));
904
905                 key.mkvno = 0;
906                 key.salt = NULL; /* No salt for this enc type */
907
908                 if (entry_ex->entry.keys.val == NULL) {
909                         ret = ENOMEM;
910                         goto out;
911                 }
912
913                 ret = krb5_keyblock_init(context,
914                                          ENCTYPE_ARCFOUR_HMAC,
915                                          password_hash.hash, sizeof(password_hash.hash),
916                                          &key.key);
917
918                 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
919                 entry_ex->entry.keys.len++;
920         }
921
922         entry_ex->entry.principal = malloc(sizeof(*(entry_ex->entry.principal)));
923
924         ret = copy_Principal(principal, entry_ex->entry.principal);
925         if (ret) {
926                 krb5_clear_error_message(context);
927                 goto out;
928         }
929
930         /* While we have copied the client principal, tests
931          * show that Win2k3 returns the 'corrected' realm, not
932          * the client-specified realm.  This code attempts to
933          * replace the client principal's realm with the one
934          * we determine from our records */
935
936         krb5_principal_set_realm(context, entry_ex->entry.principal, realm);
937         entry_ex->entry.flags = int2HDBFlags(0);
938         entry_ex->entry.flags.immutable = 1;
939         entry_ex->entry.flags.invalid = 0;
940         entry_ex->entry.flags.server = 1;
941         entry_ex->entry.flags.require_preauth = 1;
942
943         entry_ex->entry.pw_end = NULL;
944
945         entry_ex->entry.max_life = NULL;
946
947         entry_ex->entry.max_renew = NULL;
948
949         entry_ex->entry.generation = NULL;
950
951         entry_ex->entry.etypes = malloc(sizeof(*(entry_ex->entry.etypes)));
952         if (entry_ex->entry.etypes == NULL) {
953                 krb5_clear_error_message(context);
954                 ret = ENOMEM;
955                 goto out;
956         }
957         entry_ex->entry.etypes->len = entry_ex->entry.keys.len;
958         entry_ex->entry.etypes->val = calloc(entry_ex->entry.etypes->len, sizeof(int));
959         if (entry_ex->entry.etypes->val == NULL) {
960                 krb5_clear_error_message(context);
961                 ret = ENOMEM;
962                 goto out;
963         }
964         for (i=0; i < entry_ex->entry.etypes->len; i++) {
965                 entry_ex->entry.etypes->val[i] = entry_ex->entry.keys.val[i].key.keytype;
966         }
967
968
969         p->msg = talloc_steal(p, msg);
970
971 out:
972         if (ret != 0) {
973                 /* This doesn't free ent itself, that is for the eventual caller to do */
974                 hdb_free_entry(context, entry_ex);
975         } else {
976                 talloc_steal(kdc_db_ctx, entry_ex->ctx);
977         }
978
979         return ret;
980
981 }
982
983 static krb5_error_code samba_kdc_lookup_trust(krb5_context context, struct ldb_context *ldb_ctx,
984                                         TALLOC_CTX *mem_ctx,
985                                         const char *realm,
986                                         struct ldb_dn *realm_dn,
987                                         struct ldb_message **pmsg)
988 {
989         int lret;
990         krb5_error_code ret;
991         char *filter = NULL;
992         const char * const *attrs = trust_attrs;
993
994         struct ldb_result *res = NULL;
995         filter = talloc_asprintf(mem_ctx, "(&(objectClass=trustedDomain)(|(flatname=%s)(trustPartner=%s)))", realm, realm);
996
997         if (!filter) {
998                 ret = ENOMEM;
999                 krb5_set_error_message(context, ret, "talloc_asprintf: out of memory");
1000                 return ret;
1001         }
1002
1003         lret = ldb_search(ldb_ctx, mem_ctx, &res,
1004                           ldb_get_default_basedn(ldb_ctx),
1005                           LDB_SCOPE_SUBTREE, attrs, "%s", filter);
1006         if (lret != LDB_SUCCESS) {
1007                 DEBUG(3, ("Failed to search for %s: %s\n", filter, ldb_errstring(ldb_ctx)));
1008                 return HDB_ERR_NOENTRY;
1009         } else if (res->count == 0 || res->count > 1) {
1010                 DEBUG(3, ("Failed find a single entry for %s: got %d\n", filter, res->count));
1011                 talloc_free(res);
1012                 return HDB_ERR_NOENTRY;
1013         }
1014         talloc_steal(mem_ctx, res->msgs);
1015         *pmsg = res->msgs[0];
1016         talloc_free(res);
1017         return 0;
1018 }
1019
1020 static krb5_error_code samba_kdc_lookup_client(krb5_context context,
1021                                                 struct samba_kdc_db_context *kdc_db_ctx,
1022                                                 TALLOC_CTX *mem_ctx,
1023                                                 krb5_const_principal principal,
1024                                                 const char **attrs,
1025                                                 struct ldb_dn **realm_dn,
1026                                                 struct ldb_message **msg) {
1027         NTSTATUS nt_status;
1028         char *principal_string;
1029         krb5_error_code ret;
1030
1031         ret = krb5_unparse_name(context, principal, &principal_string);
1032
1033         if (ret != 0) {
1034                 return ret;
1035         }
1036
1037         nt_status = sam_get_results_principal(kdc_db_ctx->samdb,
1038                                               mem_ctx, principal_string, attrs,
1039                                               realm_dn, msg);
1040         free(principal_string);
1041         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
1042                 return HDB_ERR_NOENTRY;
1043         } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
1044                 return ENOMEM;
1045         } else if (!NT_STATUS_IS_OK(nt_status)) {
1046                 return EINVAL;
1047         }
1048
1049         return ret;
1050 }
1051
1052 static krb5_error_code samba_kdc_fetch_client(krb5_context context,
1053                                                struct samba_kdc_db_context *kdc_db_ctx,
1054                                                TALLOC_CTX *mem_ctx,
1055                                                krb5_const_principal principal,
1056                                                unsigned flags,
1057                                                hdb_entry_ex *entry_ex) {
1058         struct ldb_dn *realm_dn;
1059         krb5_error_code ret;
1060         struct ldb_message *msg = NULL;
1061
1062         ret = samba_kdc_lookup_client(context, kdc_db_ctx,
1063                                        mem_ctx, principal, user_attrs,
1064                                        &realm_dn, &msg);
1065         if (ret != 0) {
1066                 return ret;
1067         }
1068
1069         ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1070                                       principal, SAMBA_KDC_ENT_TYPE_CLIENT,
1071                                       flags,
1072                                       realm_dn, msg, entry_ex);
1073         return ret;
1074 }
1075
1076 static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
1077                                               struct samba_kdc_db_context *kdc_db_ctx,
1078                                               TALLOC_CTX *mem_ctx,
1079                                               krb5_const_principal principal,
1080                                               unsigned flags,
1081                                               uint32_t krbtgt_number,
1082                                               hdb_entry_ex *entry_ex)
1083 {
1084         struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
1085         krb5_error_code ret;
1086         struct ldb_message *msg = NULL;
1087         struct ldb_dn *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
1088
1089         krb5_principal alloc_principal = NULL;
1090         if (principal->name.name_string.len != 2
1091             || (strcmp(principal->name.name_string.val[0], KRB5_TGS_NAME) != 0)) {
1092                 /* Not a krbtgt */
1093                 return HDB_ERR_NOENTRY;
1094         }
1095
1096         /* krbtgt case.  Either us or a trusted realm */
1097
1098         if (lpcfg_is_my_domain_or_realm(lp_ctx, principal->realm)
1099             && lpcfg_is_my_domain_or_realm(lp_ctx, principal->name.name_string.val[1])) {
1100                 /* us, or someone quite like us */
1101                 /* Cludge, cludge cludge.  If the realm part of krbtgt/realm,
1102                  * is in our db, then direct the caller at our primary
1103                  * krbtgt */
1104
1105                 int lret;
1106
1107                 if (krbtgt_number == kdc_db_ctx->my_krbtgt_number) {
1108                         lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx,
1109                                                &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
1110                                                krbtgt_attrs, 0,
1111                                                "(objectClass=user)");
1112                 } else {
1113                         /* We need to look up an RODC krbtgt (perhaps
1114                          * ours, if we are an RODC, perhaps another
1115                          * RODC if we are a read-write DC */
1116                         lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx,
1117                                                &msg, realm_dn, LDB_SCOPE_SUBTREE,
1118                                                krbtgt_attrs,
1119                                                DSDB_SEARCH_SHOW_EXTENDED_DN,
1120                                                "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=%u))", (unsigned)(krbtgt_number));
1121                 }
1122
1123                 if (lret == LDB_ERR_NO_SUCH_OBJECT) {
1124                         krb5_warnx(context, "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1125                                    (unsigned)(krbtgt_number));
1126                         krb5_set_error_message(context, HDB_ERR_NOENTRY,
1127                                                "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1128                                                (unsigned)(krbtgt_number));
1129                         return HDB_ERR_NOENTRY;
1130                 } else if (lret != LDB_SUCCESS) {
1131                         krb5_warnx(context, "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1132                                    (unsigned)(krbtgt_number));
1133                         krb5_set_error_message(context, HDB_ERR_NOENTRY,
1134                                                "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1135                                                (unsigned)(krbtgt_number));
1136                         return HDB_ERR_NOENTRY;
1137                 }
1138
1139                 if (flags & HDB_F_CANON) {
1140                         ret = krb5_copy_principal(context, principal, &alloc_principal);
1141                         if (ret) {
1142                                 return ret;
1143                         }
1144
1145                         /* When requested to do so, ensure that the
1146                          * both realm values in the principal are set
1147                          * to the upper case, canonical realm */
1148                         free(alloc_principal->name.name_string.val[1]);
1149                         alloc_principal->name.name_string.val[1] = strdup(lpcfg_realm(lp_ctx));
1150                         if (!alloc_principal->name.name_string.val[1]) {
1151                                 ret = ENOMEM;
1152                                 krb5_set_error_message(context, ret, "samba_kdc_fetch: strdup() failed!");
1153                                 return ret;
1154                         }
1155                         principal = alloc_principal;
1156                 }
1157
1158                 ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1159                                               principal, SAMBA_KDC_ENT_TYPE_KRBTGT,
1160                                               flags, realm_dn, msg, entry_ex);
1161                 if (flags & HDB_F_CANON) {
1162                         /* This is again copied in the message2entry call */
1163                         krb5_free_principal(context, alloc_principal);
1164                 }
1165                 if (ret != 0) {
1166                         krb5_warnx(context, "samba_kdc_fetch: self krbtgt message2entry failed");
1167                 }
1168                 return ret;
1169
1170         } else {
1171                 enum trust_direction direction = UNKNOWN;
1172                 const char *realm = NULL;
1173
1174                 /* Either an inbound or outbound trust */
1175
1176                 if (strcasecmp(lpcfg_realm(lp_ctx), principal->realm) == 0) {
1177                         /* look for inbound trust */
1178                         direction = INBOUND;
1179                         realm = principal->name.name_string.val[1];
1180                 } else if (strcasecmp(lpcfg_realm(lp_ctx), principal->name.name_string.val[1]) == 0) {
1181                         /* look for outbound trust */
1182                         direction = OUTBOUND;
1183                         realm = principal->realm;
1184                 } else {
1185                         krb5_warnx(context, "samba_kdc_fetch: not our realm for trusts ('%s', '%s')",
1186                                    principal->realm, principal->name.name_string.val[1]);
1187                         krb5_set_error_message(context, HDB_ERR_NOENTRY, "samba_kdc_fetch: not our realm for trusts ('%s', '%s')",
1188                                                principal->realm, principal->name.name_string.val[1]);
1189                         return HDB_ERR_NOENTRY;
1190                 }
1191
1192                 /* Trusted domains are under CN=system */
1193
1194                 ret = samba_kdc_lookup_trust(context, kdc_db_ctx->samdb,
1195                                        mem_ctx,
1196                                        realm, realm_dn, &msg);
1197
1198                 if (ret != 0) {
1199                         krb5_warnx(context, "samba_kdc_fetch: could not find principal in DB");
1200                         krb5_set_error_message(context, ret, "samba_kdc_fetch: could not find principal in DB");
1201                         return ret;
1202                 }
1203
1204                 ret = samba_kdc_trust_message2entry(context, kdc_db_ctx, mem_ctx,
1205                                               principal, direction,
1206                                               realm_dn, msg, entry_ex);
1207                 if (ret != 0) {
1208                         krb5_warnx(context, "samba_kdc_fetch: trust_message2entry failed");
1209                 }
1210                 return ret;
1211         }
1212
1213 }
1214
1215 static krb5_error_code samba_kdc_lookup_server(krb5_context context,
1216                                                 struct samba_kdc_db_context *kdc_db_ctx,
1217                                                 TALLOC_CTX *mem_ctx,
1218                                                 krb5_const_principal principal,
1219                                                 const char **attrs,
1220                                                 struct ldb_dn **realm_dn,
1221                                                 struct ldb_message **msg)
1222 {
1223         krb5_error_code ret;
1224         if (principal->name.name_string.len >= 2) {
1225                 /* 'normal server' case */
1226                 int ldb_ret;
1227                 NTSTATUS nt_status;
1228                 struct ldb_dn *user_dn;
1229                 char *principal_string;
1230
1231                 ret = krb5_unparse_name_flags(context, principal,
1232                                               KRB5_PRINCIPAL_UNPARSE_NO_REALM,
1233                                               &principal_string);
1234                 if (ret != 0) {
1235                         return ret;
1236                 }
1237
1238                 /* At this point we may find the host is known to be
1239                  * in a different realm, so we should generate a
1240                  * referral instead */
1241                 nt_status = crack_service_principal_name(kdc_db_ctx->samdb,
1242                                                          mem_ctx, principal_string,
1243                                                          &user_dn, realm_dn);
1244                 free(principal_string);
1245
1246                 if (!NT_STATUS_IS_OK(nt_status)) {
1247                         return HDB_ERR_NOENTRY;
1248                 }
1249
1250                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb,
1251                                           mem_ctx,
1252                                           msg, user_dn, LDB_SCOPE_BASE,
1253                                           attrs, DSDB_SEARCH_SHOW_EXTENDED_DN, "(objectClass=*)");
1254                 if (ldb_ret != LDB_SUCCESS) {
1255                         return HDB_ERR_NOENTRY;
1256                 }
1257
1258         } else {
1259                 int lret;
1260                 char *filter = NULL;
1261                 char *short_princ;
1262                 const char *realm;
1263                 /* server as client principal case, but we must not lookup userPrincipalNames */
1264                 *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
1265                 realm = krb5_principal_get_realm(context, principal);
1266
1267                 /* TODO: Check if it is our realm, otherwise give referall */
1268
1269                 ret = krb5_unparse_name_flags(context, principal,  KRB5_PRINCIPAL_UNPARSE_NO_REALM, &short_princ);
1270
1271                 if (ret != 0) {
1272                         krb5_set_error_message(context, ret, "samba_kdc_lookup_principal: could not parse principal");
1273                         krb5_warnx(context, "samba_kdc_lookup_principal: could not parse principal");
1274                         return ret;
1275                 }
1276
1277                 lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx, msg,
1278                                        *realm_dn, LDB_SCOPE_SUBTREE,
1279                                        attrs,
1280                                        DSDB_SEARCH_SHOW_EXTENDED_DN,
1281                                        "(&(objectClass=user)(samAccountName=%s))",
1282                                        ldb_binary_encode_string(mem_ctx, short_princ));
1283                 free(short_princ);
1284                 if (lret == LDB_ERR_NO_SUCH_OBJECT) {
1285                         DEBUG(3, ("Failed find a entry for %s\n", filter));
1286                         return HDB_ERR_NOENTRY;
1287                 }
1288                 if (lret != LDB_SUCCESS) {
1289                         DEBUG(3, ("Failed single search for for %s - %s\n",
1290                                   filter, ldb_errstring(kdc_db_ctx->samdb)));
1291                         return HDB_ERR_NOENTRY;
1292                 }
1293         }
1294
1295         return 0;
1296 }
1297
1298 static krb5_error_code samba_kdc_fetch_server(krb5_context context,
1299                                               struct samba_kdc_db_context *kdc_db_ctx,
1300                                               TALLOC_CTX *mem_ctx,
1301                                               krb5_const_principal principal,
1302                                               unsigned flags,
1303                                               hdb_entry_ex *entry_ex)
1304 {
1305         krb5_error_code ret;
1306         struct ldb_dn *realm_dn;
1307         struct ldb_message *msg;
1308
1309         ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, principal,
1310                                        server_attrs, &realm_dn, &msg);
1311         if (ret != 0) {
1312                 return ret;
1313         }
1314
1315         ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1316                                       principal, SAMBA_KDC_ENT_TYPE_SERVER,
1317                                       flags,
1318                                       realm_dn, msg, entry_ex);
1319         if (ret != 0) {
1320                 krb5_warnx(context, "samba_kdc_fetch: message2entry failed");
1321         }
1322
1323         return ret;
1324 }
1325
1326 krb5_error_code samba_kdc_fetch(krb5_context context,
1327                                 struct samba_kdc_db_context *kdc_db_ctx,
1328                                 krb5_const_principal principal,
1329                                 unsigned flags,
1330                                 krb5_kvno kvno,
1331                                 hdb_entry_ex *entry_ex)
1332 {
1333         krb5_error_code ret = HDB_ERR_NOENTRY;
1334         TALLOC_CTX *mem_ctx;
1335         unsigned int krbtgt_number;
1336         if (flags & HDB_F_KVNO_SPECIFIED) {
1337                 krbtgt_number = kvno >> 16;
1338                 if (kdc_db_ctx->rodc) {
1339                         if (krbtgt_number != kdc_db_ctx->my_krbtgt_number) {
1340                                 return HDB_ERR_NOT_FOUND_HERE;
1341                         }
1342                 }
1343         } else {
1344                 krbtgt_number = kdc_db_ctx->my_krbtgt_number;
1345         }
1346
1347         mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
1348         if (!mem_ctx) {
1349                 ret = ENOMEM;
1350                 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1351                 return ret;
1352         }
1353
1354         if (flags & HDB_F_GET_CLIENT) {
1355                 ret = samba_kdc_fetch_client(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
1356                 if (ret != HDB_ERR_NOENTRY) goto done;
1357         }
1358         if (flags & HDB_F_GET_SERVER) {
1359                 /* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
1360                 ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, krbtgt_number, entry_ex);
1361                 if (ret != HDB_ERR_NOENTRY) goto done;
1362
1363                 /* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
1364                 ret = samba_kdc_fetch_server(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
1365                 if (ret != HDB_ERR_NOENTRY) goto done;
1366         }
1367         if (flags & HDB_F_GET_KRBTGT) {
1368                 ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, krbtgt_number, entry_ex);
1369                 if (ret != HDB_ERR_NOENTRY) goto done;
1370         }
1371
1372 done:
1373         talloc_free(mem_ctx);
1374         return ret;
1375 }
1376
1377 struct samba_kdc_seq {
1378         unsigned int index;
1379         unsigned int count;
1380         struct ldb_message **msgs;
1381         struct ldb_dn *realm_dn;
1382 };
1383
1384 static krb5_error_code samba_kdc_seq(krb5_context context,
1385                                      struct samba_kdc_db_context *kdc_db_ctx,
1386                                      hdb_entry_ex *entry)
1387 {
1388         krb5_error_code ret;
1389         struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
1390         TALLOC_CTX *mem_ctx;
1391         hdb_entry_ex entry_ex;
1392         memset(&entry_ex, '\0', sizeof(entry_ex));
1393
1394         if (!priv) {
1395                 return HDB_ERR_NOENTRY;
1396         }
1397
1398         mem_ctx = talloc_named(priv, 0, "samba_kdc_seq context");
1399
1400         if (!mem_ctx) {
1401                 ret = ENOMEM;
1402                 krb5_set_error_message(context, ret, "samba_kdc_seq: talloc_named() failed!");
1403                 return ret;
1404         }
1405
1406         if (priv->index < priv->count) {
1407                 ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1408                                               NULL, SAMBA_KDC_ENT_TYPE_ANY,
1409                                               HDB_F_ADMIN_DATA|HDB_F_GET_ANY,
1410                                               priv->realm_dn, priv->msgs[priv->index++], entry);
1411         } else {
1412                 ret = HDB_ERR_NOENTRY;
1413         }
1414
1415         if (ret != 0) {
1416                 TALLOC_FREE(priv);
1417                 kdc_db_ctx->seq_ctx = NULL;
1418         } else {
1419                 talloc_free(mem_ctx);
1420         }
1421
1422         return ret;
1423 }
1424
1425 krb5_error_code samba_kdc_firstkey(krb5_context context,
1426                                    struct samba_kdc_db_context *kdc_db_ctx,
1427                                    hdb_entry_ex *entry)
1428 {
1429         struct ldb_context *ldb_ctx = kdc_db_ctx->samdb;
1430         struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
1431         char *realm;
1432         struct ldb_result *res = NULL;
1433         krb5_error_code ret;
1434         TALLOC_CTX *mem_ctx;
1435         int lret;
1436
1437         if (priv) {
1438                 TALLOC_FREE(priv);
1439                 kdc_db_ctx->seq_ctx = NULL;
1440         }
1441
1442         priv = (struct samba_kdc_seq *) talloc(kdc_db_ctx, struct samba_kdc_seq);
1443         if (!priv) {
1444                 ret = ENOMEM;
1445                 krb5_set_error_message(context, ret, "talloc: out of memory");
1446                 return ret;
1447         }
1448
1449         priv->index = 0;
1450         priv->msgs = NULL;
1451         priv->realm_dn = ldb_get_default_basedn(ldb_ctx);
1452         priv->count = 0;
1453
1454         mem_ctx = talloc_named(priv, 0, "samba_kdc_firstkey context");
1455
1456         if (!mem_ctx) {
1457                 ret = ENOMEM;
1458                 krb5_set_error_message(context, ret, "samba_kdc_firstkey: talloc_named() failed!");
1459                 return ret;
1460         }
1461
1462         ret = krb5_get_default_realm(context, &realm);
1463         if (ret != 0) {
1464                 TALLOC_FREE(priv);
1465                 return ret;
1466         }
1467
1468         lret = ldb_search(ldb_ctx, priv, &res,
1469                           priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs,
1470                           "(objectClass=user)");
1471
1472         if (lret != LDB_SUCCESS) {
1473                 TALLOC_FREE(priv);
1474                 return HDB_ERR_NOENTRY;
1475         }
1476
1477         priv->count = res->count;
1478         priv->msgs = talloc_steal(priv, res->msgs);
1479         talloc_free(res);
1480
1481         kdc_db_ctx->seq_ctx = priv;
1482
1483         ret = samba_kdc_seq(context, kdc_db_ctx, entry);
1484
1485         if (ret != 0) {
1486                 TALLOC_FREE(priv);
1487                 kdc_db_ctx->seq_ctx = NULL;
1488         } else {
1489                 talloc_free(mem_ctx);
1490         }
1491         return ret;
1492 }
1493
1494 krb5_error_code samba_kdc_nextkey(krb5_context context,
1495                                   struct samba_kdc_db_context *kdc_db_ctx,
1496                                   hdb_entry_ex *entry)
1497 {
1498         return samba_kdc_seq(context, kdc_db_ctx, entry);
1499 }
1500
1501 /* Check if a given entry may delegate or do s4u2self to this target principal
1502  *
1503  * This is currently a very nasty hack - allowing only delegation to itself.
1504  *
1505  * This is shared between the constrained delegation and S4U2Self code.
1506  */
1507 krb5_error_code
1508 samba_kdc_check_identical_client_and_server(krb5_context context,
1509                                             struct samba_kdc_db_context *kdc_db_ctx,
1510                                             hdb_entry_ex *entry,
1511                                             krb5_const_principal target_principal)
1512 {
1513         krb5_error_code ret;
1514         krb5_principal enterprise_prinicpal = NULL;
1515         struct ldb_dn *realm_dn;
1516         struct ldb_message *msg;
1517         struct dom_sid *orig_sid;
1518         struct dom_sid *target_sid;
1519         struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1520         const char *delegation_check_attrs[] = {
1521                 "objectSid", NULL
1522         };
1523
1524         TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_constrained_delegation");
1525
1526         if (!mem_ctx) {
1527                 ret = ENOMEM;
1528                 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1529                 return ret;
1530         }
1531
1532         if (target_principal->name.name_type == KRB5_NT_ENTERPRISE_PRINCIPAL) {
1533                 /* Need to reparse the enterprise principal to find the real target */
1534                 if (target_principal->name.name_string.len != 1) {
1535                         ret = KRB5_PARSE_MALFORMED;
1536                         krb5_set_error_message(context, ret, "samba_kdc_check_constrained_delegation: request for delegation to enterprise principal with wrong (%d) number of components",
1537                                                target_principal->name.name_string.len);
1538                         talloc_free(mem_ctx);
1539                         return ret;
1540                 }
1541                 ret = krb5_parse_name(context, target_principal->name.name_string.val[0],
1542                                       &enterprise_prinicpal);
1543                 if (ret) {
1544                         talloc_free(mem_ctx);
1545                         return ret;
1546                 }
1547                 target_principal = enterprise_prinicpal;
1548         }
1549
1550         ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, target_principal,
1551                                        delegation_check_attrs, &realm_dn, &msg);
1552
1553         krb5_free_principal(context, enterprise_prinicpal);
1554
1555         if (ret != 0) {
1556                 talloc_free(mem_ctx);
1557                 return ret;
1558         }
1559
1560         orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
1561         target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
1562
1563         /* Allow delegation to the same principal, even if by a different
1564          * name.  The easy and safe way to prove this is by SID
1565          * comparison */
1566         if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
1567                 talloc_free(mem_ctx);
1568                 return KRB5KDC_ERR_BADOPTION;
1569         }
1570
1571         talloc_free(mem_ctx);
1572         return ret;
1573 }
1574
1575 /* Certificates printed by a the Certificate Authority might have a
1576  * slightly different form of the user principal name to that in the
1577  * database.  Allow a mismatch where they both refer to the same
1578  * SID */
1579
1580 krb5_error_code
1581 samba_kdc_check_pkinit_ms_upn_match(krb5_context context,
1582                                     struct samba_kdc_db_context *kdc_db_ctx,
1583                                      hdb_entry_ex *entry,
1584                                      krb5_const_principal certificate_principal)
1585 {
1586         krb5_error_code ret;
1587         struct ldb_dn *realm_dn;
1588         struct ldb_message *msg;
1589         struct dom_sid *orig_sid;
1590         struct dom_sid *target_sid;
1591         struct samba_kdc_entry *p = talloc_get_type(entry->ctx, struct samba_kdc_entry);
1592         const char *ms_upn_check_attrs[] = {
1593                 "objectSid", NULL
1594         };
1595
1596         TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_pkinit_ms_upn_match");
1597
1598         if (!mem_ctx) {
1599                 ret = ENOMEM;
1600                 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
1601                 return ret;
1602         }
1603
1604         ret = samba_kdc_lookup_client(context, kdc_db_ctx,
1605                                        mem_ctx, certificate_principal,
1606                                        ms_upn_check_attrs, &realm_dn, &msg);
1607
1608         if (ret != 0) {
1609                 talloc_free(mem_ctx);
1610                 return ret;
1611         }
1612
1613         orig_sid = samdb_result_dom_sid(mem_ctx, p->msg, "objectSid");
1614         target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
1615
1616         /* Consider these to be the same principal, even if by a different
1617          * name.  The easy and safe way to prove this is by SID
1618          * comparison */
1619         if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
1620                 talloc_free(mem_ctx);
1621                 return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
1622         }
1623
1624         talloc_free(mem_ctx);
1625         return ret;
1626 }
1627
1628 NTSTATUS samba_kdc_setup_db_ctx(TALLOC_CTX *mem_ctx, struct samba_kdc_base_context *base_ctx,
1629                                 struct samba_kdc_db_context **kdc_db_ctx_out)
1630 {
1631         int ldb_ret;
1632         struct ldb_message *msg;
1633         struct auth_session_info *session_info;
1634         struct samba_kdc_db_context *kdc_db_ctx;
1635         /* The idea here is very simple.  Using Kerberos to
1636          * authenticate the KDC to the LDAP server is higly likely to
1637          * be circular.
1638          *
1639          * In future we may set this up to use EXERNAL and SSL
1640          * certificates, for now it will almost certainly be NTLMSSP_SET_USERNAME
1641         */
1642
1643         kdc_db_ctx = talloc_zero(mem_ctx, struct samba_kdc_db_context);
1644         if (kdc_db_ctx == NULL) {
1645                 return NT_STATUS_NO_MEMORY;
1646         }
1647         kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
1648         kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
1649
1650         kdc_get_policy(base_ctx->lp_ctx, NULL, &kdc_db_ctx->policy);
1651
1652         session_info = system_session(kdc_db_ctx->lp_ctx);
1653         if (session_info == NULL) {
1654                 return NT_STATUS_INTERNAL_ERROR;
1655         }
1656
1657         /* Setup the link to LDB */
1658         kdc_db_ctx->samdb = samdb_connect(kdc_db_ctx, base_ctx->ev_ctx,
1659                                           base_ctx->lp_ctx, session_info, 0);
1660         if (kdc_db_ctx->samdb == NULL) {
1661                 DEBUG(1, ("hdb_samba4_create: Cannot open samdb for KDC backend!"));
1662                 talloc_free(kdc_db_ctx);
1663                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1664         }
1665
1666         /* Find out our own krbtgt kvno */
1667         ldb_ret = samdb_rodc(kdc_db_ctx->samdb, &kdc_db_ctx->rodc);
1668         if (ldb_ret != LDB_SUCCESS) {
1669                 DEBUG(1, ("hdb_samba4_create: Cannot determine if we are an RODC in KDC backend: %s\n",
1670                           ldb_errstring(kdc_db_ctx->samdb)));
1671                 talloc_free(kdc_db_ctx);
1672                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1673         }
1674         if (kdc_db_ctx->rodc) {
1675                 int my_krbtgt_number;
1676                 const char *secondary_keytab[] = { "msDS-SecondaryKrbTgtNumber", NULL };
1677                 struct ldb_dn *account_dn;
1678                 struct ldb_dn *server_dn = samdb_server_dn(kdc_db_ctx->samdb, kdc_db_ctx);
1679                 if (!server_dn) {
1680                         DEBUG(1, ("hdb_samba4_create: Cannot determine server DN in KDC backend: %s\n",
1681                                   ldb_errstring(kdc_db_ctx->samdb)));
1682                         talloc_free(kdc_db_ctx);
1683                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1684                 }
1685
1686                 ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, server_dn,
1687                                              "serverReference", &account_dn);
1688                 if (ldb_ret != LDB_SUCCESS) {
1689                         DEBUG(1, ("hdb_samba4_create: Cannot determine server account in KDC backend: %s\n",
1690                                   ldb_errstring(kdc_db_ctx->samdb)));
1691                         talloc_free(kdc_db_ctx);
1692                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1693                 }
1694
1695                 ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, account_dn,
1696                                              "msDS-KrbTgtLink", &kdc_db_ctx->krbtgt_dn);
1697                 talloc_free(account_dn);
1698                 if (ldb_ret != LDB_SUCCESS) {
1699                         DEBUG(1, ("hdb_samba4_create: Cannot determine RODC krbtgt account in KDC backend: %s\n",
1700                                   ldb_errstring(kdc_db_ctx->samdb)));
1701                         talloc_free(kdc_db_ctx);
1702                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1703                 }
1704
1705                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
1706                                           &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
1707                                           secondary_keytab,
1708                                           0,
1709                                           "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=*))");
1710                 if (ldb_ret != LDB_SUCCESS) {
1711                         DEBUG(1, ("hdb_samba4_create: Cannot read krbtgt account %s in KDC backend to get msDS-SecondaryKrbTgtNumber: %s: %s\n",
1712                                   ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
1713                                   ldb_errstring(kdc_db_ctx->samdb),
1714                                   ldb_strerror(ldb_ret)));
1715                         talloc_free(kdc_db_ctx);
1716                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1717                 }
1718                 my_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
1719                 if (my_krbtgt_number == -1) {
1720                         DEBUG(1, ("hdb_samba4_create: Cannot read msDS-SecondaryKrbTgtNumber from krbtgt account %s in KDC backend: got %d\n",
1721                                   ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
1722                                   my_krbtgt_number));
1723                         talloc_free(kdc_db_ctx);
1724                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1725                 }
1726                 kdc_db_ctx->my_krbtgt_number = my_krbtgt_number;
1727
1728         } else {
1729                 kdc_db_ctx->my_krbtgt_number = 0;
1730                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
1731                                           &msg, NULL, LDB_SCOPE_SUBTREE,
1732                                           krbtgt_attrs,
1733                                           0,
1734                                           "(&(objectClass=user)(samAccountName=krbtgt))");
1735
1736                 if (ldb_ret != LDB_SUCCESS) {
1737                         DEBUG(1, ("samba_kdc_fetch: could not find own KRBTGT in DB: %s\n", ldb_errstring(kdc_db_ctx->samdb)));
1738                         talloc_free(kdc_db_ctx);
1739                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1740                 }
1741                 kdc_db_ctx->krbtgt_dn = talloc_steal(kdc_db_ctx, msg->dn);
1742                 kdc_db_ctx->my_krbtgt_number = 0;
1743                 talloc_free(msg);
1744         }
1745         *kdc_db_ctx_out = kdc_db_ctx;
1746         return NT_STATUS_OK;
1747 }