s4:kdc: Make sure ret is set if we goto bad_option
[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 "librpc/gen_ndr/ndr_security.h"
27 #include "auth/auth.h"
28 #include "auth/auth_sam.h"
29 #include "dsdb/samdb/samdb.h"
30 #include "dsdb/common/util.h"
31 #include "librpc/gen_ndr/ndr_drsblobs.h"
32 #include "param/param.h"
33 #include "param/secrets.h"
34 #include "../lib/crypto/md4.h"
35 #include "system/kerberos.h"
36 #include "auth/kerberos/kerberos.h"
37 #include "kdc/sdb.h"
38 #include "kdc/samba_kdc.h"
39 #include "kdc/db-glue.h"
40 #include "librpc/gen_ndr/ndr_irpc_c.h"
41 #include "lib/messaging/irpc.h"
42
43 #undef strcasecmp
44 #undef strncasecmp
45
46 #define SAMBA_KVNO_GET_KRBTGT(kvno) \
47         ((uint16_t)(((uint32_t)kvno) >> 16))
48
49 #define SAMBA_KVNO_AND_KRBTGT(kvno, krbtgt) \
50         ((krb5_kvno)((((uint32_t)kvno) & 0xFFFF) | \
51          ((((uint32_t)krbtgt) << 16) & 0xFFFF0000)))
52
53 enum samba_kdc_ent_type
54 { SAMBA_KDC_ENT_TYPE_CLIENT, SAMBA_KDC_ENT_TYPE_SERVER,
55   SAMBA_KDC_ENT_TYPE_KRBTGT, SAMBA_KDC_ENT_TYPE_TRUST, SAMBA_KDC_ENT_TYPE_ANY };
56
57 enum trust_direction {
58         UNKNOWN = 0,
59         INBOUND = LSA_TRUST_DIRECTION_INBOUND,
60         OUTBOUND = LSA_TRUST_DIRECTION_OUTBOUND
61 };
62
63 static const char *trust_attrs[] = {
64         "securityIdentifier",
65         "flatName",
66         "trustPartner",
67         "trustAttributes",
68         "trustDirection",
69         "trustType",
70         "msDS-TrustForestTrustInfo",
71         "trustAuthIncoming",
72         "trustAuthOutgoing",
73         "whenCreated",
74         "msDS-SupportedEncryptionTypes",
75         NULL
76 };
77
78 /*
79   send a message to the drepl server telling it to initiate a
80   REPL_SECRET getncchanges extended op to fetch the users secrets
81  */
82 static void auth_sam_trigger_repl_secret(TALLOC_CTX *mem_ctx,
83                                   struct imessaging_context *msg_ctx,
84                                   struct tevent_context *event_ctx,
85                                   struct ldb_dn *user_dn)
86 {
87         struct dcerpc_binding_handle *irpc_handle;
88         struct drepl_trigger_repl_secret r;
89         struct tevent_req *req;
90         TALLOC_CTX *tmp_ctx;
91
92         tmp_ctx = talloc_new(mem_ctx);
93         if (tmp_ctx == NULL) {
94                 return;
95         }
96
97         irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg_ctx,
98                                                   "dreplsrv",
99                                                   &ndr_table_irpc);
100         if (irpc_handle == NULL) {
101                 DEBUG(1,(__location__ ": Unable to get binding handle for dreplsrv\n"));
102                 TALLOC_FREE(tmp_ctx);
103                 return;
104         }
105
106         r.in.user_dn = ldb_dn_get_linearized(user_dn);
107
108         /*
109          * This seem to rely on the current IRPC implementation,
110          * which delivers the message in the _send function.
111          *
112          * TODO: we need a ONE_WAY IRPC handle and register
113          * a callback and wait for it to be triggered!
114          */
115         req = dcerpc_drepl_trigger_repl_secret_r_send(tmp_ctx,
116                                                       event_ctx,
117                                                       irpc_handle,
118                                                       &r);
119
120         /* we aren't interested in a reply */
121         talloc_free(req);
122         TALLOC_FREE(tmp_ctx);
123 }
124
125 static time_t ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const char *attr, time_t default_val)
126 {
127     const char *tmp;
128     const char *gentime;
129     struct tm tm;
130
131     gentime = ldb_msg_find_attr_as_string(msg, attr, NULL);
132     if (!gentime)
133         return default_val;
134
135     tmp = strptime(gentime, "%Y%m%d%H%M%SZ", &tm);
136     if (tmp == NULL) {
137             return default_val;
138     }
139
140     return timegm(&tm);
141 }
142
143 static struct SDBFlags uf2SDBFlags(krb5_context context, uint32_t userAccountControl, enum samba_kdc_ent_type ent_type)
144 {
145         struct SDBFlags flags = int2SDBFlags(0);
146
147         /* we don't allow kadmin deletes */
148         flags.immutable = 1;
149
150         /* mark the principal as invalid to start with */
151         flags.invalid = 1;
152
153         flags.renewable = 1;
154
155         /* All accounts are servers, but this may be disabled again in the caller */
156         flags.server = 1;
157
158         /* Account types - clear the invalid bit if it turns out to be valid */
159         if (userAccountControl & UF_NORMAL_ACCOUNT) {
160                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
161                         flags.client = 1;
162                 }
163                 flags.invalid = 0;
164         }
165
166         if (userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
167                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
168                         flags.client = 1;
169                 }
170                 flags.invalid = 0;
171         }
172         if (userAccountControl & UF_WORKSTATION_TRUST_ACCOUNT) {
173                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
174                         flags.client = 1;
175                 }
176                 flags.invalid = 0;
177         }
178         if (userAccountControl & UF_SERVER_TRUST_ACCOUNT) {
179                 if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
180                         flags.client = 1;
181                 }
182                 flags.invalid = 0;
183         }
184
185         /* Not permitted to act as a client if disabled */
186         if (userAccountControl & UF_ACCOUNTDISABLE) {
187                 flags.client = 0;
188         }
189         if (userAccountControl & UF_LOCKOUT) {
190                 flags.locked_out = 1;
191         }
192 /*
193         if (userAccountControl & UF_PASSWORD_NOTREQD) {
194                 flags.invalid = 1;
195         }
196 */
197 /*
198         UF_PASSWORD_CANT_CHANGE and UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED are irrelevent
199 */
200         if (userAccountControl & UF_TEMP_DUPLICATE_ACCOUNT) {
201                 flags.invalid = 1;
202         }
203
204 /* UF_DONT_EXPIRE_PASSWD and UF_USE_DES_KEY_ONLY handled in samba_kdc_message2entry() */
205
206 /*
207         if (userAccountControl & UF_MNS_LOGON_ACCOUNT) {
208                 flags.invalid = 1;
209         }
210 */
211         if (userAccountControl & UF_SMARTCARD_REQUIRED) {
212                 flags.require_hwauth = 1;
213         }
214         if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) {
215                 flags.ok_as_delegate = 1;
216         }
217         if (userAccountControl & UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) {
218                 /*
219                  * this is confusing...
220                  *
221                  * UF_TRUSTED_FOR_DELEGATION
222                  * => ok_as_delegate
223                  *
224                  * and
225                  *
226                  * UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
227                  * => trusted_for_delegation
228                  */
229                 flags.trusted_for_delegation = 1;
230         }
231         if (!(userAccountControl & UF_NOT_DELEGATED)) {
232                 flags.forwardable = 1;
233                 flags.proxiable = 1;
234         }
235
236         if (userAccountControl & UF_DONT_REQUIRE_PREAUTH) {
237                 flags.require_preauth = 0;
238         } else {
239                 flags.require_preauth = 1;
240         }
241
242         if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
243                 flags.no_auth_data_reqd = 1;
244         }
245
246         return flags;
247 }
248
249 static int samba_kdc_entry_destructor(struct samba_kdc_entry *p)
250 {
251         if (p->entry_ex != NULL) {
252                 struct sdb_entry_ex *entry_ex = p->entry_ex;
253                 free_sdb_entry(&entry_ex->entry);
254         }
255
256         return 0;
257 }
258
259 /*
260  * Sort keys in descending order of strength.
261  *
262  * Explanaton from Greg Hudson:
263  *
264  * To encrypt tickets only the first returned key is used by the MIT KDC.  The
265  * other keys just communicate support for session key enctypes, and aren't
266  * really used.  The encryption key for the ticket enc part doesn't have
267  * to be of a type requested by the client. The session key enctype is chosen
268  * based on the client preference order, limited by the set of enctypes present
269  * in the server keys (unless the string attribute is set on the server
270  * principal overriding that set).
271  */
272 static int samba_kdc_sort_encryption_keys(struct sdb_entry_ex *entry_ex)
273 {
274         unsigned int i, j, idx = 0;
275         static const krb5_enctype etype_list[] = {
276                 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
277                 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
278                 ENCTYPE_DES3_CBC_SHA1,
279                 ENCTYPE_ARCFOUR_HMAC,
280                 ENCTYPE_DES_CBC_MD5,
281                 ENCTYPE_DES_CBC_MD4,
282                 ENCTYPE_DES_CBC_CRC,
283                 ENCTYPE_NULL
284         };
285         size_t etype_len = ARRAY_SIZE(etype_list);
286         size_t keys_size = entry_ex->entry.keys.len;
287         struct sdb_key *keys = entry_ex->entry.keys.val;
288         struct sdb_key *sorted_keys;
289
290         sorted_keys = calloc(keys_size, sizeof(struct sdb_key));
291         if (sorted_keys == NULL) {
292                 return -1;
293         }
294
295         for (i = 0; i < etype_len; i++) {
296                 for (j = 0; j < keys_size; j++) {
297                         const struct sdb_key skey = keys[j];
298
299                         if (idx == keys_size) {
300                                 break;
301                         }
302
303                         if (KRB5_KEY_TYPE(&skey.key) == etype_list[i]) {
304                                 sorted_keys[idx] = skey;
305                                 idx++;
306                         }
307                 }
308         }
309
310         /* Paranoia: Something went wrong during data copy */
311         if (idx != keys_size) {
312                 free(sorted_keys);
313                 return -1;
314         }
315
316         free(entry_ex->entry.keys.val);
317         entry_ex->entry.keys.val = sorted_keys;
318
319         return 0;
320 }
321
322 int samba_kdc_set_fixed_keys(krb5_context context,
323                              struct samba_kdc_db_context *kdc_db_ctx,
324                              const struct ldb_val *secretbuffer,
325                              struct sdb_entry_ex *entry_ex)
326 {
327         const uint32_t supported_enctypes = ENC_ALL_TYPES;
328         uint16_t allocated_keys = 0;
329         int ret;
330
331         allocated_keys = 3;
332         entry_ex->entry.keys.len = 0;
333         entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(struct sdb_key));
334         if (entry_ex->entry.keys.val == NULL) {
335                 memset(secretbuffer->data, 0, secretbuffer->length);
336                 ret = ENOMEM;
337                 goto out;
338         }
339
340         if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
341                 struct sdb_key key = {};
342
343                 ret = smb_krb5_keyblock_init_contents(context,
344                                                       ENCTYPE_AES256_CTS_HMAC_SHA1_96,
345                                                       secretbuffer->data,
346                                                       MIN(secretbuffer->length, 32),
347                                                       &key.key);
348                 if (ret) {
349                         memset(secretbuffer->data, 0, secretbuffer->length);
350                         goto out;
351                 }
352
353                 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
354                 entry_ex->entry.keys.len++;
355         }
356
357         if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
358                 struct sdb_key key = {};
359
360                 ret = smb_krb5_keyblock_init_contents(context,
361                                                       ENCTYPE_AES128_CTS_HMAC_SHA1_96,
362                                                       secretbuffer->data,
363                                                       MIN(secretbuffer->length, 16),
364                                                       &key.key);
365                 if (ret) {
366                         memset(secretbuffer->data, 0, secretbuffer->length);
367                         goto out;
368                 }
369
370                 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
371                 entry_ex->entry.keys.len++;
372         }
373
374         if (supported_enctypes & ENC_RC4_HMAC_MD5) {
375                 struct sdb_key key = {};
376
377                 ret = smb_krb5_keyblock_init_contents(context,
378                                                       ENCTYPE_ARCFOUR_HMAC,
379                                                       secretbuffer->data,
380                                                       MIN(secretbuffer->length, 16),
381                                                       &key.key);
382                 if (ret) {
383                         memset(secretbuffer->data, 0, secretbuffer->length);
384                         goto out;
385                 }
386
387                 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
388                 entry_ex->entry.keys.len++;
389         }
390         ret = 0;
391 out:
392         return ret;
393 }
394
395
396 static int samba_kdc_set_random_keys(krb5_context context,
397                                      struct samba_kdc_db_context *kdc_db_ctx,
398                                      struct sdb_entry_ex *entry_ex)
399 {
400         struct ldb_val secret_val;
401         uint8_t secretbuffer[32];
402
403         /*
404          * Fake keys until we have a better way to reject
405          * non-pkinit requests.
406          *
407          * We just need to indicate which encryption types are
408          * supported.
409          */
410         generate_secret_buffer(secretbuffer, sizeof(secretbuffer));
411
412         secret_val = data_blob_const(secretbuffer,
413                                      sizeof(secretbuffer));
414         return samba_kdc_set_fixed_keys(context, kdc_db_ctx,
415                                         &secret_val,
416                                         entry_ex);
417 }
418
419
420 static krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
421                                                     struct samba_kdc_db_context *kdc_db_ctx,
422                                                     TALLOC_CTX *mem_ctx,
423                                                     struct ldb_message *msg,
424                                                     uint32_t rid,
425                                                     bool is_rodc,
426                                                     uint32_t userAccountControl,
427                                                     enum samba_kdc_ent_type ent_type,
428                                                     struct sdb_entry_ex *entry_ex,
429                                                     uint32_t *supported_enctypes_out)
430 {
431         krb5_error_code ret = 0;
432         enum ndr_err_code ndr_err;
433         struct samr_Password *hash;
434         const struct ldb_val *sc_val;
435         struct supplementalCredentialsBlob scb;
436         struct supplementalCredentialsPackage *scpk = NULL;
437         bool newer_keys = false;
438         struct package_PrimaryKerberosBlob _pkb;
439         struct package_PrimaryKerberosCtr3 *pkb3 = NULL;
440         struct package_PrimaryKerberosCtr4 *pkb4 = NULL;
441         uint16_t i;
442         uint16_t allocated_keys = 0;
443         int rodc_krbtgt_number = 0;
444         int kvno = 0;
445         uint32_t supported_enctypes
446                 = ldb_msg_find_attr_as_uint(msg,
447                                             "msDS-SupportedEncryptionTypes",
448                                             0);
449         *supported_enctypes_out = 0;
450
451         if (rid == DOMAIN_RID_KRBTGT || is_rodc) {
452                 bool enable_fast;
453
454                 /* KDCs (and KDCs on RODCs) use AES */
455                 supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
456
457                 enable_fast = lpcfg_kdc_enable_fast(kdc_db_ctx->lp_ctx);
458                 if (enable_fast) {
459                         supported_enctypes |= ENC_FAST_SUPPORTED;
460                 }
461         } else if (userAccountControl & (UF_PARTIAL_SECRETS_ACCOUNT|UF_SERVER_TRUST_ACCOUNT)) {
462                 /* DCs and RODCs comptuer accounts use AES */
463                 supported_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
464         } else if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT ||
465                    (ent_type == SAMBA_KDC_ENT_TYPE_ANY)) {
466                 /* for AS-REQ the client chooses the enc types it
467                  * supports, and this will vary between computers a
468                  * user logs in from.
469                  *
470                  * likewise for 'any' return as much as is supported,
471                  * to export into a keytab */
472                 supported_enctypes = ENC_ALL_TYPES;
473         }
474
475         /* If UF_USE_DES_KEY_ONLY has been set, then don't allow use of the newer enc types */
476         if (userAccountControl & UF_USE_DES_KEY_ONLY) {
477                 supported_enctypes = 0;
478         } else {
479                 /* Otherwise, add in the default enc types */
480                 supported_enctypes |= ENC_RC4_HMAC_MD5;
481         }
482
483         /* Is this the krbtgt or a RODC krbtgt */
484         if (is_rodc) {
485                 rodc_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
486
487                 if (rodc_krbtgt_number == -1) {
488                         return EINVAL;
489                 }
490         }
491
492         entry_ex->entry.keys.val = NULL;
493         entry_ex->entry.keys.len = 0;
494         entry_ex->entry.kvno = 0;
495
496         if ((ent_type == SAMBA_KDC_ENT_TYPE_CLIENT)
497             && (userAccountControl & UF_SMARTCARD_REQUIRED)) {
498                 ret = samba_kdc_set_random_keys(context,
499                                                 kdc_db_ctx,
500                                                 entry_ex);
501
502                 *supported_enctypes_out = supported_enctypes;
503
504                 goto out;
505         }
506
507         kvno = ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0);
508         if (is_rodc) {
509                 kvno = SAMBA_KVNO_AND_KRBTGT(kvno, rodc_krbtgt_number);
510         }
511         entry_ex->entry.kvno = kvno;
512
513         /* Get keys from the db */
514
515         hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
516         sc_val = ldb_msg_find_ldb_val(msg, "supplementalCredentials");
517
518         /* unicodePwd for enctype 0x17 (23) if present */
519         if (hash) {
520                 allocated_keys++;
521         }
522
523         /* supplementalCredentials if present */
524         if (sc_val) {
525                 ndr_err = ndr_pull_struct_blob_all(sc_val, mem_ctx, &scb,
526                                                    (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
527                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
528                         dump_data(0, sc_val->data, sc_val->length);
529                         ret = EINVAL;
530                         goto out;
531                 }
532
533                 if (scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
534                         if (scb.sub.num_packages != 0) {
535                                 NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
536                                 ret = EINVAL;
537                                 goto out;
538                         }
539                 }
540
541                 for (i=0; i < scb.sub.num_packages; i++) {
542                         if (strcmp("Primary:Kerberos-Newer-Keys", scb.sub.packages[i].name) == 0) {
543                                 scpk = &scb.sub.packages[i];
544                                 if (!scpk->data || !scpk->data[0]) {
545                                         scpk = NULL;
546                                         continue;
547                                 }
548                                 newer_keys = true;
549                                 break;
550                         } else if (strcmp("Primary:Kerberos", scb.sub.packages[i].name) == 0) {
551                                 scpk = &scb.sub.packages[i];
552                                 if (!scpk->data || !scpk->data[0]) {
553                                         scpk = NULL;
554                                 }
555                                 /*
556                                  * we don't break here in hope to find
557                                  * a Kerberos-Newer-Keys package
558                                  */
559                         }
560                 }
561         }
562         /*
563          * Primary:Kerberos-Newer-Keys or Primary:Kerberos element
564          * of supplementalCredentials
565          */
566         if (scpk) {
567                 DATA_BLOB blob;
568
569                 blob = strhex_to_data_blob(mem_ctx, scpk->data);
570                 if (!blob.data) {
571                         ret = ENOMEM;
572                         goto out;
573                 }
574
575                 /* we cannot use ndr_pull_struct_blob_all() here, as w2k and w2k3 add padding bytes */
576                 ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &_pkb,
577                                                (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
578                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
579                         ret = EINVAL;
580                         krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: could not parse package_PrimaryKerberosBlob");
581                         krb5_warnx(context, "samba_kdc_message2entry_keys: could not parse package_PrimaryKerberosBlob");
582                         goto out;
583                 }
584
585                 if (newer_keys && _pkb.version != 4) {
586                         ret = EINVAL;
587                         krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4");
588                         krb5_warnx(context, "samba_kdc_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4");
589                         goto out;
590                 }
591
592                 if (!newer_keys && _pkb.version != 3) {
593                         ret = EINVAL;
594                         krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: could not parse Primary:Kerberos not version 3");
595                         krb5_warnx(context, "samba_kdc_message2entry_keys: could not parse Primary:Kerberos not version 3");
596                         goto out;
597                 }
598
599                 if (_pkb.version == 4) {
600                         pkb4 = &_pkb.ctr.ctr4;
601                         allocated_keys += pkb4->num_keys;
602                 } else if (_pkb.version == 3) {
603                         pkb3 = &_pkb.ctr.ctr3;
604                         allocated_keys += pkb3->num_keys;
605                 }
606         }
607
608         if (allocated_keys == 0) {
609                 if (kdc_db_ctx->rodc) {
610                         /* We are on an RODC, but don't have keys for this account.  Signal this to the caller */
611                         auth_sam_trigger_repl_secret(kdc_db_ctx, kdc_db_ctx->msg_ctx,
612                                                      kdc_db_ctx->ev_ctx, msg->dn);
613                         return SDB_ERR_NOT_FOUND_HERE;
614                 }
615
616                 /* oh, no password.  Apparently (comment in
617                  * hdb-ldap.c) this violates the ASN.1, but this
618                  * allows an entry with no keys (yet). */
619                 return 0;
620         }
621
622         /* allocate space to decode into */
623         entry_ex->entry.keys.len = 0;
624         entry_ex->entry.keys.val = calloc(allocated_keys, sizeof(struct sdb_key));
625         if (entry_ex->entry.keys.val == NULL) {
626                 ret = ENOMEM;
627                 goto out;
628         }
629
630         if (hash && (supported_enctypes & ENC_RC4_HMAC_MD5)) {
631                 struct sdb_key key = {};
632
633                 ret = smb_krb5_keyblock_init_contents(context,
634                                                       ENCTYPE_ARCFOUR_HMAC,
635                                                       hash->hash,
636                                                       sizeof(hash->hash),
637                                                       &key.key);
638                 if (ret) {
639                         goto out;
640                 }
641
642                 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
643                 entry_ex->entry.keys.len++;
644
645                 *supported_enctypes_out |= ENC_RC4_HMAC_MD5;
646         }
647
648         if (pkb4) {
649                 for (i=0; i < pkb4->num_keys; i++) {
650                         struct sdb_key key = {};
651                         uint32_t enctype_bit;
652
653                         if (!pkb4->keys[i].value) continue;
654
655                         enctype_bit = kerberos_enctype_to_bitmap(pkb4->keys[i].keytype);
656                         if (!(enctype_bit & supported_enctypes)) {
657                                 continue;
658                         }
659
660                         if (pkb4->salt.string) {
661                                 DATA_BLOB salt;
662
663                                 salt = data_blob_string_const(pkb4->salt.string);
664
665                                 key.salt = calloc(1, sizeof(*key.salt));
666                                 if (key.salt == NULL) {
667                                         ret = ENOMEM;
668                                         goto out;
669                                 }
670
671                                 key.salt->type = KRB5_PW_SALT;
672
673                                 ret = smb_krb5_copy_data_contents(&key.salt->salt,
674                                                                   salt.data,
675                                                                   salt.length);
676                                 if (ret) {
677                                         free(key.salt);
678                                         key.salt = NULL;
679                                         goto out;
680                                 }
681                         }
682
683                         /* TODO: maybe pass the iteration_count somehow... */
684
685                         ret = smb_krb5_keyblock_init_contents(context,
686                                                               pkb4->keys[i].keytype,
687                                                               pkb4->keys[i].value->data,
688                                                               pkb4->keys[i].value->length,
689                                                               &key.key);
690                         if (ret) {
691                                 if (key.salt) {
692                                         smb_krb5_free_data_contents(context, &key.salt->salt);
693                                         free(key.salt);
694                                         key.salt = NULL;
695                                 }
696                                 if (ret == KRB5_PROG_ETYPE_NOSUPP) {
697                                         DEBUG(2,("Unsupported keytype ignored - type %u\n",
698                                                  pkb4->keys[i].keytype));
699                                         ret = 0;
700                                         continue;
701                                 }
702                                 goto out;
703                         }
704
705                         entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
706                         entry_ex->entry.keys.len++;
707
708                         *supported_enctypes_out |= enctype_bit;
709                 }
710         } else if (pkb3) {
711                 for (i=0; i < pkb3->num_keys; i++) {
712                         struct sdb_key key = {};
713                         uint32_t enctype_bit;
714
715                         if (!pkb3->keys[i].value) continue;
716
717                         enctype_bit = kerberos_enctype_to_bitmap(pkb3->keys[i].keytype);
718                         if (!(enctype_bit & supported_enctypes)) {
719                                 continue;
720                         }
721
722                         if (pkb3->salt.string) {
723                                 DATA_BLOB salt;
724
725                                 salt = data_blob_string_const(pkb3->salt.string);
726
727                                 key.salt = calloc(1, sizeof(*key.salt));
728                                 if (key.salt == NULL) {
729                                         ret = ENOMEM;
730                                         goto out;
731                                 }
732
733                                 key.salt->type = KRB5_PW_SALT;
734
735                                 ret = smb_krb5_copy_data_contents(&key.salt->salt,
736                                                                   salt.data,
737                                                                   salt.length);
738                                 if (ret) {
739                                         free(key.salt);
740                                         key.salt = NULL;
741                                         goto out;
742                                 }
743                         }
744
745                         ret = smb_krb5_keyblock_init_contents(context,
746                                                               pkb3->keys[i].keytype,
747                                                               pkb3->keys[i].value->data,
748                                                               pkb3->keys[i].value->length,
749                                                               &key.key);
750                         if (ret) {
751                                 if (key.salt) {
752                                         smb_krb5_free_data_contents(context, &key.salt->salt);
753                                         free(key.salt);
754                                         key.salt = NULL;
755                                 }
756                                 if (ret == KRB5_PROG_ETYPE_NOSUPP) {
757                                         DEBUG(2,("Unsupported keytype ignored - type %u\n",
758                                                  pkb3->keys[i].keytype));
759                                         ret = 0;
760                                         continue;
761                                 }
762                                 goto out;
763                         }
764
765                         entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
766                         entry_ex->entry.keys.len++;
767
768                         *supported_enctypes_out |= enctype_bit;
769                 }
770         }
771
772         /* Set FAST support bits */
773         *supported_enctypes_out |= supported_enctypes & (ENC_FAST_SUPPORTED |
774                                                          ENC_COMPOUND_IDENTITY_SUPPORTED |
775                                                          ENC_CLAIMS_SUPPORTED);
776
777 out:
778         if (ret != 0) {
779                 entry_ex->entry.keys.len = 0;
780         } else if (entry_ex->entry.keys.len > 0 &&
781                    entry_ex->entry.keys.val != NULL) {
782                 ret = samba_kdc_sort_encryption_keys(entry_ex);
783                 if (ret != 0) {
784                         entry_ex->entry.keys.len = 0;
785                         ret = ENOMEM;
786                 }
787         }
788         if (entry_ex->entry.keys.len == 0 && entry_ex->entry.keys.val) {
789                 free(entry_ex->entry.keys.val);
790                 entry_ex->entry.keys.val = NULL;
791         }
792         return ret;
793 }
794
795 static int principal_comp_strcmp_int(krb5_context context,
796                                      krb5_const_principal principal,
797                                      unsigned int component,
798                                      const char *string,
799                                      bool do_strcasecmp)
800 {
801         const char *p;
802         size_t len;
803
804 #if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
805         p = krb5_principal_get_comp_string(context, principal, component);
806         if (p == NULL) {
807                 return -1;
808         }
809         len = strlen(p);
810 #else
811         krb5_data *d;
812         if (component >= krb5_princ_size(context, principal)) {
813                 return -1;
814         }
815
816         d = krb5_princ_component(context, principal, component);
817         if (d == NULL) {
818                 return -1;
819         }
820
821         p = d->data;
822         len = d->length;
823 #endif
824         if (do_strcasecmp) {
825                 return strncasecmp(p, string, len);
826         } else {
827                 return strncmp(p, string, len);
828         }
829 }
830
831 static int principal_comp_strcasecmp(krb5_context context,
832                                      krb5_const_principal principal,
833                                      unsigned int component,
834                                      const char *string)
835 {
836         return principal_comp_strcmp_int(context, principal,
837                                          component, string, true);
838 }
839
840 static int principal_comp_strcmp(krb5_context context,
841                                  krb5_const_principal principal,
842                                  unsigned int component,
843                                  const char *string)
844 {
845         return principal_comp_strcmp_int(context, principal,
846                                          component, string, false);
847 }
848
849 /*
850  * Construct an hdb_entry from a directory entry.
851  */
852 static krb5_error_code samba_kdc_message2entry(krb5_context context,
853                                                struct samba_kdc_db_context *kdc_db_ctx,
854                                                TALLOC_CTX *mem_ctx,
855                                                krb5_const_principal principal,
856                                                enum samba_kdc_ent_type ent_type,
857                                                unsigned flags,
858                                                struct ldb_dn *realm_dn,
859                                                struct ldb_message *msg,
860                                                struct sdb_entry_ex *entry_ex)
861 {
862         struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
863         uint32_t userAccountControl;
864         uint32_t msDS_User_Account_Control_Computed;
865         krb5_error_code ret = 0;
866         krb5_boolean is_computer = FALSE;
867
868         struct samba_kdc_entry *p;
869         uint32_t supported_enctypes = 0;
870         NTTIME acct_expiry;
871         NTSTATUS status;
872
873         uint32_t rid;
874         bool is_rodc = false;
875         struct ldb_message_element *objectclasses;
876         struct ldb_val computer_val;
877         const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
878         computer_val.data = discard_const_p(uint8_t,"computer");
879         computer_val.length = strlen((const char *)computer_val.data);
880
881         if (ldb_msg_find_element(msg, "msDS-SecondaryKrbTgtNumber")) {
882                 is_rodc = true;
883         }
884
885         if (!samAccountName) {
886                 ret = ENOENT;
887                 krb5_set_error_message(context, ret, "samba_kdc_message2entry: no samAccountName present");
888                 goto out;
889         }
890
891         objectclasses = ldb_msg_find_element(msg, "objectClass");
892
893         if (objectclasses && ldb_msg_find_val(objectclasses, &computer_val)) {
894                 is_computer = TRUE;
895         }
896
897         ZERO_STRUCTP(entry_ex);
898
899         p = talloc_zero(mem_ctx, struct samba_kdc_entry);
900         if (!p) {
901                 ret = ENOMEM;
902                 goto out;
903         }
904
905         p->is_rodc = is_rodc;
906         p->kdc_db_ctx = kdc_db_ctx;
907         p->realm_dn = talloc_reference(p, realm_dn);
908         if (!p->realm_dn) {
909                 ret = ENOMEM;
910                 goto out;
911         }
912
913         talloc_set_destructor(p, samba_kdc_entry_destructor);
914
915         entry_ex->ctx = p;
916
917         userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
918
919         msDS_User_Account_Control_Computed
920                 = ldb_msg_find_attr_as_uint(msg,
921                                             "msDS-User-Account-Control-Computed",
922                                             UF_ACCOUNTDISABLE);
923
924         /*
925          * This brings in the lockout flag, block the account if not
926          * found.  We need the weird UF_ACCOUNTDISABLE check because
927          * we do not want to fail open if the value is not returned,
928          * but 0 is a valid value (all OK)
929          */
930         if (msDS_User_Account_Control_Computed == UF_ACCOUNTDISABLE) {
931                 ret = EINVAL;
932                 krb5_set_error_message(context, ret, "samba_kdc_message2entry: "
933                                 "no msDS-User-Account-Control-Computed present");
934                 goto out;
935         } else {
936                 userAccountControl |= msDS_User_Account_Control_Computed;
937         }
938
939         /*
940          * If we are set to canonicalize, we get back the fixed UPPER
941          * case realm, and the real username (ie matching LDAP
942          * samAccountName)
943          *
944          * Otherwise, if we are set to enterprise, we
945          * get back the whole principal as-sent
946          *
947          * Finally, if we are not set to canonicalize, we get back the
948          * fixed UPPER case realm, but the as-sent username
949          */
950
951         if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT) {
952                 p->is_krbtgt = true;
953
954                 if (flags & (SDB_F_CANON|SDB_F_FORCE_CANON)) {
955                         /*
956                          * When requested to do so, ensure that the
957                          * both realm values in the principal are set
958                          * to the upper case, canonical realm
959                          */
960                         ret = smb_krb5_make_principal(context, &entry_ex->entry.principal,
961                                                       lpcfg_realm(lp_ctx), "krbtgt",
962                                                       lpcfg_realm(lp_ctx), NULL);
963                         if (ret) {
964                                 krb5_clear_error_message(context);
965                                 goto out;
966                         }
967                         smb_krb5_principal_set_type(context, entry_ex->entry.principal, KRB5_NT_SRV_INST);
968                 } else {
969                         ret = krb5_copy_principal(context, principal, &entry_ex->entry.principal);
970                         if (ret) {
971                                 krb5_clear_error_message(context);
972                                 goto out;
973                         }
974                         /*
975                          * this appears to be required regardless of
976                          * the canonicalize flag from the client
977                          */
978                         ret = smb_krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
979                         if (ret) {
980                                 krb5_clear_error_message(context);
981                                 goto out;
982                         }
983                 }
984
985         } else if (ent_type == SAMBA_KDC_ENT_TYPE_ANY && principal == NULL) {
986                 ret = smb_krb5_make_principal(context, &entry_ex->entry.principal, lpcfg_realm(lp_ctx), samAccountName, NULL);
987                 if (ret) {
988                         krb5_clear_error_message(context);
989                         goto out;
990                 }
991         } else if ((flags & SDB_F_FORCE_CANON) ||
992                    ((flags & SDB_F_CANON) && (flags & SDB_F_FOR_AS_REQ))) {
993                 /*
994                  * SDB_F_CANON maps from the canonicalize flag in the
995                  * packet, and has a different meaning between AS-REQ
996                  * and TGS-REQ.  We only change the principal in the AS-REQ case
997                  *
998                  * The SDB_F_FORCE_CANON if for new MIT KDC code that wants
999                  * the canonical name in all lookups, and takes care to
1000                  * canonicalize only when appropriate.
1001                  */
1002                 ret = smb_krb5_make_principal(context, &entry_ex->entry.principal, lpcfg_realm(lp_ctx), samAccountName, NULL);
1003                 if (ret) {
1004                         krb5_clear_error_message(context);
1005                         goto out;
1006                 }
1007         } else {
1008                 ret = krb5_copy_principal(context, principal, &entry_ex->entry.principal);
1009                 if (ret) {
1010                         krb5_clear_error_message(context);
1011                         goto out;
1012                 }
1013
1014                 /* While we have copied the client principal, tests
1015                  * show that Win2k3 returns the 'corrected' realm, not
1016                  * the client-specified realm.  This code attempts to
1017                  * replace the client principal's realm with the one
1018                  * we determine from our records */
1019
1020                 /* this has to be with malloc() */
1021                 ret = smb_krb5_principal_set_realm(context, entry_ex->entry.principal, lpcfg_realm(lp_ctx));
1022                 if (ret) {
1023                         krb5_clear_error_message(context);
1024                         goto out;
1025                 }
1026         }
1027
1028         /* First try and figure out the flags based on the userAccountControl */
1029         entry_ex->entry.flags = uf2SDBFlags(context, userAccountControl, ent_type);
1030
1031         /*
1032          * Take control of the returned principal here, rather than
1033          * allowing the Heimdal code to do it as we have specific
1034          * behaviour around the forced realm to honour
1035          */
1036         entry_ex->entry.flags.force_canonicalize = true;
1037
1038         /* Windows 2008 seems to enforce this (very sensible) rule by
1039          * default - don't allow offline attacks on a user's password
1040          * by asking for a ticket to them as a service (encrypted with
1041          * their probably patheticly insecure password) */
1042
1043         if (entry_ex->entry.flags.server
1044             && lpcfg_parm_bool(lp_ctx, NULL, "kdc", "require spn for service", true)) {
1045                 if (!is_computer && !ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL)) {
1046                         entry_ex->entry.flags.server = 0;
1047                 }
1048         }
1049
1050         /*
1051          * We restrict a 3-part SPN ending in my domain/realm to full
1052          * domain controllers.
1053          *
1054          * This avoids any cases where (eg) a demoted DC still has
1055          * these more restricted SPNs.
1056          */
1057         if (krb5_princ_size(context, principal) > 2) {
1058                 char *third_part
1059                         = smb_krb5_principal_get_comp_string(mem_ctx,
1060                                                              context,
1061                                                              principal,
1062                                                              2);
1063                 bool is_our_realm =
1064                          lpcfg_is_my_domain_or_realm(lp_ctx,
1065                                                      third_part);
1066                 bool is_dc = userAccountControl &
1067                         (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT);
1068                 if (is_our_realm && !is_dc) {
1069                         entry_ex->entry.flags.server = 0;
1070                 }
1071         }
1072         /*
1073          * To give the correct type of error to the client, we must
1074          * not just return the entry without .server set, we must
1075          * pretend the principal does not exist.  Otherwise we may
1076          * return ERR_POLICY instead of
1077          * KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
1078          */
1079         if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER && entry_ex->entry.flags.server == 0) {
1080                 ret = SDB_ERR_NOENTRY;
1081                 krb5_set_error_message(context, ret, "samba_kdc_message2entry: no servicePrincipalName present for this server, refusing with no-such-entry");
1082                 goto out;
1083         }
1084         if (flags & SDB_F_ADMIN_DATA) {
1085                 /* These (created_by, modified_by) parts of the entry are not relevant for Samba4's use
1086                  * of the Heimdal KDC.  They are stored in a the traditional
1087                  * DB for audit purposes, and still form part of the structure
1088                  * we must return */
1089
1090                 /* use 'whenCreated' */
1091                 entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
1092                 /* use 'kadmin' for now (needed by mit_samba) */
1093
1094                 ret = smb_krb5_make_principal(context,
1095                                               &entry_ex->entry.created_by.principal,
1096                                               lpcfg_realm(lp_ctx), "kadmin", NULL);
1097                 if (ret) {
1098                         krb5_clear_error_message(context);
1099                         goto out;
1100                 }
1101
1102                 entry_ex->entry.modified_by = (struct sdb_event *) malloc(sizeof(struct sdb_event));
1103                 if (entry_ex->entry.modified_by == NULL) {
1104                         ret = ENOMEM;
1105                         krb5_set_error_message(context, ret, "malloc: out of memory");
1106                         goto out;
1107                 }
1108
1109                 /* use 'whenChanged' */
1110                 entry_ex->entry.modified_by->time = ldb_msg_find_krb5time_ldap_time(msg, "whenChanged", 0);
1111                 /* use 'kadmin' for now (needed by mit_samba) */
1112                 ret = smb_krb5_make_principal(context,
1113                                               &entry_ex->entry.modified_by->principal,
1114                                               lpcfg_realm(lp_ctx), "kadmin", NULL);
1115                 if (ret) {
1116                         krb5_clear_error_message(context);
1117                         goto out;
1118                 }
1119         }
1120
1121
1122         /* The lack of password controls etc applies to krbtgt by
1123          * virtue of being that particular RID */
1124         status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, msg, "objectSid"), NULL, &rid);
1125
1126         if (!NT_STATUS_IS_OK(status)) {
1127                 ret = EINVAL;
1128                 goto out;
1129         }
1130
1131         if (rid == DOMAIN_RID_KRBTGT) {
1132                 char *realm = NULL;
1133
1134                 entry_ex->entry.valid_end = NULL;
1135                 entry_ex->entry.pw_end = NULL;
1136
1137                 entry_ex->entry.flags.invalid = 0;
1138                 entry_ex->entry.flags.server = 1;
1139
1140                 realm = smb_krb5_principal_get_realm(
1141                         mem_ctx, context, principal);
1142                 if (realm == NULL) {
1143                         ret = ENOMEM;
1144                         goto out;
1145                 }
1146
1147                 /* Don't mark all requests for the krbtgt/realm as
1148                  * 'change password', as otherwise we could get into
1149                  * trouble, and not enforce the password expirty.
1150                  * Instead, only do it when request is for the kpasswd service */
1151                 if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER
1152                     && krb5_princ_size(context, principal) == 2
1153                     && (principal_comp_strcmp(context, principal, 0, "kadmin") == 0)
1154                     && (principal_comp_strcmp(context, principal, 1, "changepw") == 0)
1155                     && lpcfg_is_my_domain_or_realm(lp_ctx, realm)) {
1156                         entry_ex->entry.flags.change_pw = 1;
1157                 }
1158
1159                 TALLOC_FREE(realm);
1160
1161                 entry_ex->entry.flags.client = 0;
1162                 entry_ex->entry.flags.forwardable = 1;
1163                 entry_ex->entry.flags.ok_as_delegate = 1;
1164         } else if (is_rodc) {
1165                 /* The RODC krbtgt account is like the main krbtgt,
1166                  * but it does not have a changepw or kadmin
1167                  * service */
1168
1169                 entry_ex->entry.valid_end = NULL;
1170                 entry_ex->entry.pw_end = NULL;
1171
1172                 /* Also don't allow the RODC krbtgt to be a client (it should not be needed) */
1173                 entry_ex->entry.flags.client = 0;
1174                 entry_ex->entry.flags.invalid = 0;
1175                 entry_ex->entry.flags.server = 1;
1176
1177                 entry_ex->entry.flags.client = 0;
1178                 entry_ex->entry.flags.forwardable = 1;
1179                 entry_ex->entry.flags.ok_as_delegate = 0;
1180         } else if (entry_ex->entry.flags.server && ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
1181                 /* The account/password expiry only applies when the account is used as a
1182                  * client (ie password login), not when used as a server */
1183
1184                 /* Make very well sure we don't use this for a client,
1185                  * it could bypass the password restrictions */
1186                 entry_ex->entry.flags.client = 0;
1187
1188                 entry_ex->entry.valid_end = NULL;
1189                 entry_ex->entry.pw_end = NULL;
1190
1191         } else {
1192                 NTTIME must_change_time
1193                         = samdb_result_nttime(msg,
1194                                         "msDS-UserPasswordExpiryTimeComputed",
1195                                         0);
1196                 if (must_change_time == 0x7FFFFFFFFFFFFFFFULL) {
1197                         entry_ex->entry.pw_end = NULL;
1198                 } else {
1199                         entry_ex->entry.pw_end = malloc(sizeof(*entry_ex->entry.pw_end));
1200                         if (entry_ex->entry.pw_end == NULL) {
1201                                 ret = ENOMEM;
1202                                 goto out;
1203                         }
1204                         *entry_ex->entry.pw_end = nt_time_to_unix(must_change_time);
1205                 }
1206
1207                 acct_expiry = samdb_result_account_expires(msg);
1208                 if (acct_expiry == 0x7FFFFFFFFFFFFFFFULL) {
1209                         entry_ex->entry.valid_end = NULL;
1210                 } else {
1211                         entry_ex->entry.valid_end = malloc(sizeof(*entry_ex->entry.valid_end));
1212                         if (entry_ex->entry.valid_end == NULL) {
1213                                 ret = ENOMEM;
1214                                 goto out;
1215                         }
1216                         *entry_ex->entry.valid_end = nt_time_to_unix(acct_expiry);
1217                 }
1218         }
1219
1220         entry_ex->entry.valid_start = NULL;
1221
1222         entry_ex->entry.max_life = malloc(sizeof(*entry_ex->entry.max_life));
1223         if (entry_ex->entry.max_life == NULL) {
1224                 ret = ENOMEM;
1225                 goto out;
1226         }
1227
1228         if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
1229                 *entry_ex->entry.max_life = kdc_db_ctx->policy.svc_tkt_lifetime;
1230         } else if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT || ent_type == SAMBA_KDC_ENT_TYPE_CLIENT) {
1231                 *entry_ex->entry.max_life = kdc_db_ctx->policy.usr_tkt_lifetime;
1232         } else {
1233                 *entry_ex->entry.max_life = MIN(kdc_db_ctx->policy.svc_tkt_lifetime,
1234                                                 kdc_db_ctx->policy.usr_tkt_lifetime);
1235         }
1236
1237         entry_ex->entry.max_renew = malloc(sizeof(*entry_ex->entry.max_life));
1238         if (entry_ex->entry.max_renew == NULL) {
1239                 ret = ENOMEM;
1240                 goto out;
1241         }
1242
1243         *entry_ex->entry.max_renew = kdc_db_ctx->policy.renewal_lifetime;
1244
1245         /* Get keys from the db */
1246         ret = samba_kdc_message2entry_keys(context, kdc_db_ctx, p, msg,
1247                                            rid, is_rodc, userAccountControl,
1248                                            ent_type, entry_ex, &supported_enctypes);
1249         if (ret) {
1250                 /* Could be bogus data in the entry, or out of memory */
1251                 goto out;
1252         }
1253
1254         p->msg = talloc_steal(p, msg);
1255         p->supported_enctypes = supported_enctypes;
1256
1257 out:
1258         if (ret != 0) {
1259                 /* This doesn't free ent itself, that is for the eventual caller to do */
1260                 sdb_free_entry(entry_ex);
1261                 ZERO_STRUCTP(entry_ex);
1262         } else {
1263                 talloc_steal(kdc_db_ctx, entry_ex->ctx);
1264         }
1265
1266         return ret;
1267 }
1268
1269 /*
1270  * Construct an hdb_entry from a directory entry.
1271  * The kvno is what the remote client asked for
1272  */
1273 static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
1274                                                struct samba_kdc_db_context *kdc_db_ctx,
1275                                                TALLOC_CTX *mem_ctx, krb5_const_principal principal,
1276                                                enum trust_direction direction,
1277                                                struct ldb_dn *realm_dn,
1278                                                unsigned flags,
1279                                                uint32_t kvno,
1280                                                struct ldb_message *msg,
1281                                                struct sdb_entry_ex *entry_ex)
1282 {
1283         struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
1284         const char *our_realm = lpcfg_realm(lp_ctx);
1285         char *partner_realm = NULL;
1286         const char *realm = NULL;
1287         const char *krbtgt_realm = NULL;
1288         DATA_BLOB password_utf16 = data_blob_null;
1289         DATA_BLOB password_utf8 = data_blob_null;
1290         struct samr_Password _password_hash;
1291         const struct samr_Password *password_hash = NULL;
1292         const struct ldb_val *password_val;
1293         struct trustAuthInOutBlob password_blob;
1294         struct samba_kdc_entry *p;
1295         bool use_previous = false;
1296         uint32_t current_kvno;
1297         uint32_t previous_kvno;
1298         uint32_t num_keys = 0;
1299         enum ndr_err_code ndr_err;
1300         int ret;
1301         unsigned int i;
1302         struct AuthenticationInformationArray *auth_array;
1303         struct timeval tv;
1304         NTTIME an_hour_ago;
1305         uint32_t *auth_kvno;
1306         bool preferr_current = false;
1307         uint32_t supported_enctypes = ENC_RC4_HMAC_MD5;
1308         struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
1309         NTSTATUS status;
1310
1311         if (dsdb_functional_level(kdc_db_ctx->samdb) >= DS_DOMAIN_FUNCTION_2008) {
1312                 supported_enctypes = ldb_msg_find_attr_as_uint(msg,
1313                                         "msDS-SupportedEncryptionTypes",
1314                                         supported_enctypes);
1315         }
1316
1317         status = dsdb_trust_parse_tdo_info(mem_ctx, msg, &tdo);
1318         if (!NT_STATUS_IS_OK(status)) {
1319                 krb5_clear_error_message(context);
1320                 ret = ENOMEM;
1321                 goto out;
1322         }
1323
1324         if (!(tdo->trust_direction & direction)) {
1325                 krb5_clear_error_message(context);
1326                 ret = SDB_ERR_NOENTRY;
1327                 goto out;
1328         }
1329
1330         if (tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
1331                 /*
1332                  * Only UPLEVEL domains support kerberos here,
1333                  * as we don't support LSA_TRUST_TYPE_MIT.
1334                  */
1335                 krb5_clear_error_message(context);
1336                 ret = SDB_ERR_NOENTRY;
1337                 goto out;
1338         }
1339
1340         if (tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_CROSS_ORGANIZATION) {
1341                 /*
1342                  * We don't support selective authentication yet.
1343                  */
1344                 krb5_clear_error_message(context);
1345                 ret = SDB_ERR_NOENTRY;
1346                 goto out;
1347         }
1348
1349         if (tdo->domain_name.string == NULL) {
1350                 krb5_clear_error_message(context);
1351                 ret = SDB_ERR_NOENTRY;
1352                 goto out;
1353         }
1354         partner_realm = strupper_talloc(mem_ctx, tdo->domain_name.string);
1355         if (partner_realm == NULL) {
1356                 krb5_clear_error_message(context);
1357                 ret = ENOMEM;
1358                 goto out;
1359         }
1360
1361         if (direction == INBOUND) {
1362                 realm = our_realm;
1363                 krbtgt_realm = partner_realm;
1364
1365                 password_val = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
1366         } else { /* OUTBOUND */
1367                 realm = partner_realm;
1368                 krbtgt_realm = our_realm;
1369
1370                 password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
1371         }
1372
1373         if (password_val == NULL) {
1374                 krb5_clear_error_message(context);
1375                 ret = SDB_ERR_NOENTRY;
1376                 goto out;
1377         }
1378
1379         ndr_err = ndr_pull_struct_blob(password_val, mem_ctx, &password_blob,
1380                                        (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
1381         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1382                 krb5_clear_error_message(context);
1383                 ret = EINVAL;
1384                 goto out;
1385         }
1386
1387         p = talloc_zero(mem_ctx, struct samba_kdc_entry);
1388         if (!p) {
1389                 ret = ENOMEM;
1390                 goto out;
1391         }
1392
1393         p->is_trust = true;
1394         p->kdc_db_ctx = kdc_db_ctx;
1395         p->realm_dn = realm_dn;
1396         p->supported_enctypes = supported_enctypes;
1397
1398         talloc_set_destructor(p, samba_kdc_entry_destructor);
1399
1400         /* make sure we do not have bogus data in there */
1401         memset(&entry_ex->entry, 0, sizeof(struct sdb_entry));
1402
1403         entry_ex->ctx = p;
1404
1405         /* use 'whenCreated' */
1406         entry_ex->entry.created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
1407         /* use 'kadmin' for now (needed by mit_samba) */
1408         ret = smb_krb5_make_principal(context,
1409                                       &entry_ex->entry.created_by.principal,
1410                                       realm, "kadmin", NULL);
1411         if (ret) {
1412                 krb5_clear_error_message(context);
1413                 goto out;
1414         }
1415
1416         /*
1417          * We always need to generate the canonicalized principal
1418          * with the values of our database.
1419          */
1420         ret = smb_krb5_make_principal(context, &entry_ex->entry.principal, realm,
1421                                       "krbtgt", krbtgt_realm, NULL);
1422         if (ret) {
1423                 krb5_clear_error_message(context);
1424                 goto out;
1425         }
1426         smb_krb5_principal_set_type(context, entry_ex->entry.principal,
1427                                     KRB5_NT_SRV_INST);
1428
1429         entry_ex->entry.valid_start = NULL;
1430
1431         /* we need to work out if we are going to use the current or
1432          * the previous password hash.
1433          * We base this on the kvno the client passes in. If the kvno
1434          * passed in is equal to the current kvno in our database then
1435          * we use the current structure. If it is the current kvno-1,
1436          * then we use the previous substrucure.
1437          */
1438
1439         /*
1440          * Windows preferrs the previous key for one hour.
1441          */
1442         tv = timeval_current();
1443         if (tv.tv_sec > 3600) {
1444                 tv.tv_sec -= 3600;
1445         }
1446         an_hour_ago = timeval_to_nttime(&tv);
1447
1448         /* first work out the current kvno */
1449         current_kvno = 0;
1450         for (i=0; i < password_blob.count; i++) {
1451                 struct AuthenticationInformation *a =
1452                         &password_blob.current.array[i];
1453
1454                 if (a->LastUpdateTime <= an_hour_ago) {
1455                         preferr_current = true;
1456                 }
1457
1458                 if (a->AuthType == TRUST_AUTH_TYPE_VERSION) {
1459                         current_kvno = a->AuthInfo.version.version;
1460                 }
1461         }
1462         if (current_kvno == 0) {
1463                 previous_kvno = 255;
1464         } else {
1465                 previous_kvno = current_kvno - 1;
1466         }
1467         for (i=0; i < password_blob.count; i++) {
1468                 struct AuthenticationInformation *a =
1469                         &password_blob.previous.array[i];
1470
1471                 if (a->AuthType == TRUST_AUTH_TYPE_VERSION) {
1472                         previous_kvno = a->AuthInfo.version.version;
1473                 }
1474         }
1475
1476         /* work out whether we will use the previous or current
1477            password */
1478         if (password_blob.previous.count == 0) {
1479                 /* there is no previous password */
1480                 use_previous = false;
1481         } else if (!(flags & SDB_F_KVNO_SPECIFIED)) {
1482                 /*
1483                  * If not specified we use the lowest kvno
1484                  * for the first hour after an update.
1485                  */
1486                 if (preferr_current) {
1487                         use_previous = false;
1488                 } else if (previous_kvno < current_kvno) {
1489                         use_previous = true;
1490                 } else {
1491                         use_previous = false;
1492                 }
1493         } else if (kvno == current_kvno) {
1494                 /*
1495                  * Exact match ...
1496                  */
1497                 use_previous = false;
1498         } else if (kvno == previous_kvno) {
1499                 /*
1500                  * Exact match ...
1501                  */
1502                 use_previous = true;
1503         } else {
1504                 /*
1505                  * Fallback to the current one for anything else
1506                  */
1507                 use_previous = false;
1508         }
1509
1510         if (use_previous) {
1511                 auth_array = &password_blob.previous;
1512                 auth_kvno = &previous_kvno;
1513         } else {
1514                 auth_array = &password_blob.current;
1515                 auth_kvno = &current_kvno;
1516         }
1517
1518         /* use the kvno the client specified, if available */
1519         if (flags & SDB_F_KVNO_SPECIFIED) {
1520                 entry_ex->entry.kvno = kvno;
1521         } else {
1522                 entry_ex->entry.kvno = *auth_kvno;
1523         }
1524
1525         for (i=0; i < auth_array->count; i++) {
1526                 if (auth_array->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
1527                         bool ok;
1528
1529                         password_utf16 = data_blob_const(auth_array->array[i].AuthInfo.clear.password,
1530                                                          auth_array->array[i].AuthInfo.clear.size);
1531                         if (password_utf16.length == 0) {
1532                                 break;
1533                         }
1534
1535                         if (supported_enctypes & ENC_RC4_HMAC_MD5) {
1536                                 mdfour(_password_hash.hash, password_utf16.data, password_utf16.length);
1537                                 if (password_hash == NULL) {
1538                                         num_keys += 1;
1539                                 }
1540                                 password_hash = &_password_hash;
1541                         }
1542
1543                         if (!(supported_enctypes & (ENC_HMAC_SHA1_96_AES128|ENC_HMAC_SHA1_96_AES256))) {
1544                                 break;
1545                         }
1546
1547                         ok = convert_string_talloc(mem_ctx,
1548                                                    CH_UTF16MUNGED, CH_UTF8,
1549                                                    password_utf16.data,
1550                                                    password_utf16.length,
1551                                                    (void *)&password_utf8.data,
1552                                                    &password_utf8.length);
1553                         if (!ok) {
1554                                 krb5_clear_error_message(context);
1555                                 ret = ENOMEM;
1556                                 goto out;
1557                         }
1558
1559                         if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
1560                                 num_keys += 1;
1561                         }
1562                         if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
1563                                 num_keys += 1;
1564                         }
1565                         break;
1566                 } else if (auth_array->array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
1567                         if (supported_enctypes & ENC_RC4_HMAC_MD5) {
1568                                 password_hash = &auth_array->array[i].AuthInfo.nt4owf.password;
1569                                 num_keys += 1;
1570                         }
1571                 }
1572         }
1573
1574         /* Must have found a cleartext or MD4 password */
1575         if (num_keys == 0) {
1576                 DEBUG(1,(__location__ ": no usable key found\n"));
1577                 krb5_clear_error_message(context);
1578                 ret = SDB_ERR_NOENTRY;
1579                 goto out;
1580         }
1581
1582         entry_ex->entry.keys.val = calloc(num_keys, sizeof(struct sdb_key));
1583         if (entry_ex->entry.keys.val == NULL) {
1584                 krb5_clear_error_message(context);
1585                 ret = ENOMEM;
1586                 goto out;
1587         }
1588
1589         if (password_utf8.length != 0) {
1590                 struct sdb_key key = {};
1591                 krb5_const_principal salt_principal = entry_ex->entry.principal;
1592                 krb5_data salt;
1593                 krb5_data cleartext_data;
1594
1595                 cleartext_data.data = discard_const_p(char, password_utf8.data);
1596                 cleartext_data.length = password_utf8.length;
1597
1598                 ret = smb_krb5_get_pw_salt(context,
1599                                            salt_principal,
1600                                            &salt);
1601                 if (ret != 0) {
1602                         goto out;
1603                 }
1604
1605                 if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
1606                         ret = smb_krb5_create_key_from_string(context,
1607                                                               salt_principal,
1608                                                               &salt,
1609                                                               &cleartext_data,
1610                                                               ENCTYPE_AES256_CTS_HMAC_SHA1_96,
1611                                                               &key.key);
1612                         if (ret != 0) {
1613                                 smb_krb5_free_data_contents(context, &salt);
1614                                 goto out;
1615                         }
1616
1617                         entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
1618                         entry_ex->entry.keys.len++;
1619                 }
1620
1621                 if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
1622                         ret = smb_krb5_create_key_from_string(context,
1623                                                               salt_principal,
1624                                                               &salt,
1625                                                               &cleartext_data,
1626                                                               ENCTYPE_AES128_CTS_HMAC_SHA1_96,
1627                                                               &key.key);
1628                         if (ret != 0) {
1629                                 smb_krb5_free_data_contents(context, &salt);
1630                                 goto out;
1631                         }
1632
1633                         entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
1634                         entry_ex->entry.keys.len++;
1635                 }
1636
1637                 smb_krb5_free_data_contents(context, &salt);
1638         }
1639
1640         if (password_hash != NULL) {
1641                 struct sdb_key key = {};
1642
1643                 ret = smb_krb5_keyblock_init_contents(context,
1644                                                       ENCTYPE_ARCFOUR_HMAC,
1645                                                       password_hash->hash,
1646                                                       sizeof(password_hash->hash),
1647                                                       &key.key);
1648                 if (ret != 0) {
1649                         goto out;
1650                 }
1651
1652                 entry_ex->entry.keys.val[entry_ex->entry.keys.len] = key;
1653                 entry_ex->entry.keys.len++;
1654         }
1655
1656         entry_ex->entry.flags = int2SDBFlags(0);
1657         entry_ex->entry.flags.immutable = 1;
1658         entry_ex->entry.flags.invalid = 0;
1659         entry_ex->entry.flags.server = 1;
1660         entry_ex->entry.flags.require_preauth = 1;
1661
1662         entry_ex->entry.pw_end = NULL;
1663
1664         entry_ex->entry.max_life = NULL;
1665
1666         entry_ex->entry.max_renew = NULL;
1667
1668         /* Match Windows behavior and allow forwardable flag in cross-realm. */
1669         entry_ex->entry.flags.forwardable = 1;
1670
1671         ret = samba_kdc_sort_encryption_keys(entry_ex);
1672         if (ret != 0) {
1673                 krb5_clear_error_message(context);
1674                 ret = ENOMEM;
1675                 goto out;
1676         }
1677
1678         p->msg = talloc_steal(p, msg);
1679
1680 out:
1681         TALLOC_FREE(partner_realm);
1682
1683         if (ret != 0) {
1684                 /* This doesn't free ent itself, that is for the eventual caller to do */
1685                 sdb_free_entry(entry_ex);
1686         } else {
1687                 talloc_steal(kdc_db_ctx, entry_ex->ctx);
1688         }
1689
1690         return ret;
1691
1692 }
1693
1694 static krb5_error_code samba_kdc_lookup_trust(krb5_context context, struct ldb_context *ldb_ctx,
1695                                         TALLOC_CTX *mem_ctx,
1696                                         const char *realm,
1697                                         struct ldb_dn *realm_dn,
1698                                         struct ldb_message **pmsg)
1699 {
1700         NTSTATUS status;
1701         const char * const *attrs = trust_attrs;
1702
1703         status = dsdb_trust_search_tdo(ldb_ctx, realm, realm,
1704                                        attrs, mem_ctx, pmsg);
1705         if (NT_STATUS_IS_OK(status)) {
1706                 return 0;
1707         } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1708                 return SDB_ERR_NOENTRY;
1709         } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
1710                 int ret = ENOMEM;
1711                 krb5_set_error_message(context, ret, "get_sam_result_trust: out of memory");
1712                 return ret;
1713         } else {
1714                 int ret = EINVAL;
1715                 krb5_set_error_message(context, ret, "get_sam_result_trust: %s", nt_errstr(status));
1716                 return ret;
1717         }
1718 }
1719
1720 static krb5_error_code samba_kdc_lookup_client(krb5_context context,
1721                                                 struct samba_kdc_db_context *kdc_db_ctx,
1722                                                 TALLOC_CTX *mem_ctx,
1723                                                 krb5_const_principal principal,
1724                                                 const char **attrs,
1725                                                 struct ldb_dn **realm_dn,
1726                                                 struct ldb_message **msg)
1727 {
1728         NTSTATUS nt_status;
1729         char *principal_string = NULL;
1730
1731         if (smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
1732                 principal_string = smb_krb5_principal_get_comp_string(mem_ctx, context,
1733                                                                       principal, 0);
1734                 if (principal_string == NULL) {
1735                         return ENOMEM;
1736                 }
1737         } else {
1738                 char *principal_string_m = NULL;
1739                 krb5_error_code ret;
1740
1741                 ret = krb5_unparse_name(context, principal, &principal_string_m);
1742                 if (ret != 0) {
1743                         return ret;
1744                 }
1745
1746                 principal_string = talloc_strdup(mem_ctx, principal_string_m);
1747                 SAFE_FREE(principal_string_m);
1748                 if (principal_string == NULL) {
1749                         return ENOMEM;
1750                 }
1751         }
1752
1753         nt_status = sam_get_results_principal(kdc_db_ctx->samdb,
1754                                               mem_ctx, principal_string, attrs,
1755                                               realm_dn, msg);
1756         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
1757                 krb5_principal fallback_principal = NULL;
1758                 unsigned int num_comp;
1759                 char *fallback_realm = NULL;
1760                 char *fallback_account = NULL;
1761                 krb5_error_code ret;
1762
1763                 ret = krb5_parse_name(context, principal_string,
1764                                       &fallback_principal);
1765                 TALLOC_FREE(principal_string);
1766                 if (ret != 0) {
1767                         return ret;
1768                 }
1769
1770                 num_comp = krb5_princ_size(context, fallback_principal);
1771                 fallback_realm = smb_krb5_principal_get_realm(
1772                         mem_ctx, context, fallback_principal);
1773                 if (fallback_realm == NULL) {
1774                         krb5_free_principal(context, fallback_principal);
1775                         return ENOMEM;
1776                 }
1777
1778                 if (num_comp == 1) {
1779                         size_t len;
1780
1781                         fallback_account = smb_krb5_principal_get_comp_string(mem_ctx,
1782                                                 context, fallback_principal, 0);
1783                         if (fallback_account == NULL) {
1784                                 krb5_free_principal(context, fallback_principal);
1785                                 TALLOC_FREE(fallback_realm);
1786                                 return ENOMEM;
1787                         }
1788
1789                         len = strlen(fallback_account);
1790                         if (len >= 2 && fallback_account[len - 1] == '$') {
1791                                 TALLOC_FREE(fallback_account);
1792                         }
1793                 }
1794                 krb5_free_principal(context, fallback_principal);
1795                 fallback_principal = NULL;
1796
1797                 if (fallback_account != NULL) {
1798                         char *with_dollar;
1799
1800                         with_dollar = talloc_asprintf(mem_ctx, "%s$",
1801                                                      fallback_account);
1802                         if (with_dollar == NULL) {
1803                                 TALLOC_FREE(fallback_realm);
1804                                 return ENOMEM;
1805                         }
1806                         TALLOC_FREE(fallback_account);
1807
1808                         ret = smb_krb5_make_principal(context,
1809                                                       &fallback_principal,
1810                                                       fallback_realm,
1811                                                       with_dollar, NULL);
1812                         TALLOC_FREE(with_dollar);
1813                         if (ret != 0) {
1814                                 TALLOC_FREE(fallback_realm);
1815                                 return ret;
1816                         }
1817                 }
1818                 TALLOC_FREE(fallback_realm);
1819
1820                 if (fallback_principal != NULL) {
1821                         char *fallback_string = NULL;
1822
1823                         ret = krb5_unparse_name(context,
1824                                                 fallback_principal,
1825                                                 &fallback_string);
1826                         if (ret != 0) {
1827                                 krb5_free_principal(context, fallback_principal);
1828                                 return ret;
1829                         }
1830
1831                         nt_status = sam_get_results_principal(kdc_db_ctx->samdb,
1832                                                               mem_ctx,
1833                                                               fallback_string,
1834                                                               attrs,
1835                                                               realm_dn, msg);
1836                         SAFE_FREE(fallback_string);
1837                 }
1838                 krb5_free_principal(context, fallback_principal);
1839                 fallback_principal = NULL;
1840         }
1841         TALLOC_FREE(principal_string);
1842
1843         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
1844                 return SDB_ERR_NOENTRY;
1845         } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
1846                 return ENOMEM;
1847         } else if (!NT_STATUS_IS_OK(nt_status)) {
1848                 return EINVAL;
1849         }
1850
1851         return 0;
1852 }
1853
1854 static krb5_error_code samba_kdc_fetch_client(krb5_context context,
1855                                                struct samba_kdc_db_context *kdc_db_ctx,
1856                                                TALLOC_CTX *mem_ctx,
1857                                                krb5_const_principal principal,
1858                                                unsigned flags,
1859                                                struct sdb_entry_ex *entry_ex) {
1860         struct ldb_dn *realm_dn;
1861         krb5_error_code ret;
1862         struct ldb_message *msg = NULL;
1863
1864         ret = samba_kdc_lookup_client(context, kdc_db_ctx,
1865                                       mem_ctx, principal, user_attrs,
1866                                       &realm_dn, &msg);
1867         if (ret != 0) {
1868                 return ret;
1869         }
1870
1871         ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1872                                       principal, SAMBA_KDC_ENT_TYPE_CLIENT,
1873                                       flags,
1874                                       realm_dn, msg, entry_ex);
1875         return ret;
1876 }
1877
1878 static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
1879                                               struct samba_kdc_db_context *kdc_db_ctx,
1880                                               TALLOC_CTX *mem_ctx,
1881                                               krb5_const_principal principal,
1882                                               unsigned flags,
1883                                               uint32_t kvno,
1884                                               struct sdb_entry_ex *entry_ex)
1885 {
1886         struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
1887         krb5_error_code ret;
1888         struct ldb_message *msg = NULL;
1889         struct ldb_dn *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
1890         char *realm_from_princ;
1891         char *realm_princ_comp = smb_krb5_principal_get_comp_string(mem_ctx, context, principal, 1);
1892
1893         realm_from_princ = smb_krb5_principal_get_realm(
1894                 mem_ctx, context, principal);
1895         if (realm_from_princ == NULL) {
1896                 /* can't happen */
1897                 return SDB_ERR_NOENTRY;
1898         }
1899
1900         if (krb5_princ_size(context, principal) != 2
1901             || (principal_comp_strcmp(context, principal, 0, KRB5_TGS_NAME) != 0)) {
1902                 /* Not a krbtgt */
1903                 return SDB_ERR_NOENTRY;
1904         }
1905
1906         /* krbtgt case.  Either us or a trusted realm */
1907
1908         if (lpcfg_is_my_domain_or_realm(lp_ctx, realm_from_princ)
1909             && lpcfg_is_my_domain_or_realm(lp_ctx, realm_princ_comp)) {
1910                 /* us, or someone quite like us */
1911                 /* Cludge, cludge cludge.  If the realm part of krbtgt/realm,
1912                  * is in our db, then direct the caller at our primary
1913                  * krbtgt */
1914
1915                 int lret;
1916                 unsigned int krbtgt_number;
1917                 /* w2k8r2 sometimes gives us a kvno of 255 for inter-domain
1918                    trust tickets. We don't yet know what this means, but we do
1919                    seem to need to treat it as unspecified */
1920                 if (flags & SDB_F_KVNO_SPECIFIED) {
1921                         krbtgt_number = SAMBA_KVNO_GET_KRBTGT(kvno);
1922                         if (kdc_db_ctx->rodc) {
1923                                 if (krbtgt_number != kdc_db_ctx->my_krbtgt_number) {
1924                                         return SDB_ERR_NOT_FOUND_HERE;
1925                                 }
1926                         }
1927                 } else {
1928                         krbtgt_number = kdc_db_ctx->my_krbtgt_number;
1929                 }
1930
1931                 if (krbtgt_number == kdc_db_ctx->my_krbtgt_number) {
1932                         lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx,
1933                                                &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
1934                                                krbtgt_attrs, DSDB_SEARCH_NO_GLOBAL_CATALOG,
1935                                                "(objectClass=user)");
1936                 } else {
1937                         /* We need to look up an RODC krbtgt (perhaps
1938                          * ours, if we are an RODC, perhaps another
1939                          * RODC if we are a read-write DC */
1940                         lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx,
1941                                                &msg, realm_dn, LDB_SCOPE_SUBTREE,
1942                                                krbtgt_attrs,
1943                                                DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
1944                                                "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=%u))", (unsigned)(krbtgt_number));
1945                 }
1946
1947                 if (lret == LDB_ERR_NO_SUCH_OBJECT) {
1948                         krb5_warnx(context, "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1949                                    (unsigned)(krbtgt_number));
1950                         krb5_set_error_message(context, SDB_ERR_NOENTRY,
1951                                                "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1952                                                (unsigned)(krbtgt_number));
1953                         return SDB_ERR_NOENTRY;
1954                 } else if (lret != LDB_SUCCESS) {
1955                         krb5_warnx(context, "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1956                                    (unsigned)(krbtgt_number));
1957                         krb5_set_error_message(context, SDB_ERR_NOENTRY,
1958                                                "samba_kdc_fetch: could not find KRBTGT number %u in DB!",
1959                                                (unsigned)(krbtgt_number));
1960                         return SDB_ERR_NOENTRY;
1961                 }
1962
1963                 ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
1964                                               principal, SAMBA_KDC_ENT_TYPE_KRBTGT,
1965                                               flags, realm_dn, msg, entry_ex);
1966                 if (ret != 0) {
1967                         krb5_warnx(context, "samba_kdc_fetch: self krbtgt message2entry failed");
1968                 }
1969                 return ret;
1970
1971         } else {
1972                 enum trust_direction direction = UNKNOWN;
1973                 const char *realm = NULL;
1974
1975                 /* Either an inbound or outbound trust */
1976
1977                 if (strcasecmp(lpcfg_realm(lp_ctx), realm_from_princ) == 0) {
1978                         /* look for inbound trust */
1979                         direction = INBOUND;
1980                         realm = realm_princ_comp;
1981                 } else if (principal_comp_strcasecmp(context, principal, 1, lpcfg_realm(lp_ctx)) == 0) {
1982                         /* look for outbound trust */
1983                         direction = OUTBOUND;
1984                         realm = realm_from_princ;
1985                 } else {
1986                         krb5_warnx(context, "samba_kdc_fetch: not our realm for trusts ('%s', '%s')",
1987                                    realm_from_princ,
1988                                    realm_princ_comp);
1989                         krb5_set_error_message(context, SDB_ERR_NOENTRY, "samba_kdc_fetch: not our realm for trusts ('%s', '%s')",
1990                                                realm_from_princ,
1991                                                realm_princ_comp);
1992                         return SDB_ERR_NOENTRY;
1993                 }
1994
1995                 /* Trusted domains are under CN=system */
1996
1997                 ret = samba_kdc_lookup_trust(context, kdc_db_ctx->samdb,
1998                                        mem_ctx,
1999                                        realm, realm_dn, &msg);
2000
2001                 if (ret != 0) {
2002                         krb5_warnx(context, "samba_kdc_fetch: could not find principal in DB");
2003                         krb5_set_error_message(context, ret, "samba_kdc_fetch: could not find principal in DB");
2004                         return ret;
2005                 }
2006
2007                 ret = samba_kdc_trust_message2entry(context, kdc_db_ctx, mem_ctx,
2008                                                     principal, direction,
2009                                                     realm_dn, flags, kvno, msg, entry_ex);
2010                 if (ret != 0) {
2011                         krb5_warnx(context, "samba_kdc_fetch: trust_message2entry failed for %s",
2012                                    ldb_dn_get_linearized(msg->dn));
2013                         krb5_set_error_message(context, ret, "samba_kdc_fetch: "
2014                                                "trust_message2entry failed for %s",
2015                                                ldb_dn_get_linearized(msg->dn));
2016                 }
2017                 return ret;
2018         }
2019
2020 }
2021
2022 static krb5_error_code samba_kdc_lookup_server(krb5_context context,
2023                                                struct samba_kdc_db_context *kdc_db_ctx,
2024                                                TALLOC_CTX *mem_ctx,
2025                                                krb5_const_principal principal,
2026                                                unsigned flags,
2027                                                const char **attrs,
2028                                                struct ldb_dn **realm_dn,
2029                                                struct ldb_message **msg)
2030 {
2031         krb5_error_code ret;
2032         if ((smb_krb5_principal_get_type(context, principal) != KRB5_NT_ENTERPRISE_PRINCIPAL)
2033             && krb5_princ_size(context, principal) >= 2) {
2034                 /* 'normal server' case */
2035                 int ldb_ret;
2036                 NTSTATUS nt_status;
2037                 struct ldb_dn *user_dn;
2038                 char *principal_string;
2039
2040                 ret = krb5_unparse_name_flags(context, principal,
2041                                               KRB5_PRINCIPAL_UNPARSE_NO_REALM,
2042                                               &principal_string);
2043                 if (ret != 0) {
2044                         return ret;
2045                 }
2046
2047                 /* At this point we may find the host is known to be
2048                  * in a different realm, so we should generate a
2049                  * referral instead */
2050                 nt_status = crack_service_principal_name(kdc_db_ctx->samdb,
2051                                                          mem_ctx, principal_string,
2052                                                          &user_dn, realm_dn);
2053                 free(principal_string);
2054
2055                 if (!NT_STATUS_IS_OK(nt_status)) {
2056                         return SDB_ERR_NOENTRY;
2057                 }
2058
2059                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb,
2060                                           mem_ctx,
2061                                           msg, user_dn, LDB_SCOPE_BASE,
2062                                           attrs,
2063                                           DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
2064                                           "(objectClass=*)");
2065                 if (ldb_ret != LDB_SUCCESS) {
2066                         return SDB_ERR_NOENTRY;
2067                 }
2068                 return 0;
2069         } else if (!(flags & SDB_F_FOR_AS_REQ)
2070                    && smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
2071                 /*
2072                  * The behaviour of accepting an
2073                  * KRB5_NT_ENTERPRISE_PRINCIPAL server principal
2074                  * containing a UPN only applies to TGS-REQ packets,
2075                  * not AS-REQ packets.
2076                  */
2077                 return samba_kdc_lookup_client(context, kdc_db_ctx,
2078                                                mem_ctx, principal, attrs,
2079                                                realm_dn, msg);
2080         } else {
2081                 /*
2082                  * This case is for:
2083                  *  - the AS-REQ, where we only accept
2084                  *    samAccountName based lookups for the server, no
2085                  *    matter if the name is an
2086                  *    KRB5_NT_ENTERPRISE_PRINCIPAL or not
2087                  *  - for the TGS-REQ when we are not given an
2088                  *    KRB5_NT_ENTERPRISE_PRINCIPAL, which also must
2089                  *    only lookup samAccountName based names.
2090                  */
2091                 int lret;
2092                 char *short_princ;
2093                 krb5_principal enterprise_principal = NULL;
2094                 krb5_const_principal used_principal = NULL;
2095                 char *name1 = NULL;
2096                 size_t len1 = 0;
2097                 char *filter = NULL;
2098
2099                 if (smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
2100                         char *str = NULL;
2101                         /* Need to reparse the enterprise principal to find the real target */
2102                         if (krb5_princ_size(context, principal) != 1) {
2103                                 ret = KRB5_PARSE_MALFORMED;
2104                                 krb5_set_error_message(context, ret, "samba_kdc_lookup_server: request for an "
2105                                                        "enterprise principal with wrong (%d) number of components",
2106                                                        krb5_princ_size(context, principal));
2107                                 return ret;
2108                         }
2109                         str = smb_krb5_principal_get_comp_string(mem_ctx, context, principal, 0);
2110                         if (str == NULL) {
2111                                 return KRB5_PARSE_MALFORMED;
2112                         }
2113                         ret = krb5_parse_name(context, str,
2114                                               &enterprise_principal);
2115                         talloc_free(str);
2116                         if (ret) {
2117                                 return ret;
2118                         }
2119                         used_principal = enterprise_principal;
2120                 } else {
2121                         used_principal = principal;
2122                 }
2123
2124                 /* server as client principal case, but we must not lookup userPrincipalNames */
2125                 *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
2126
2127                 /* TODO: Check if it is our realm, otherwise give referral */
2128
2129                 ret = krb5_unparse_name_flags(context, used_principal,
2130                                               KRB5_PRINCIPAL_UNPARSE_NO_REALM |
2131                                               KRB5_PRINCIPAL_UNPARSE_DISPLAY,
2132                                               &short_princ);
2133                 used_principal = NULL;
2134                 krb5_free_principal(context, enterprise_principal);
2135                 enterprise_principal = NULL;
2136
2137                 if (ret != 0) {
2138                         krb5_set_error_message(context, ret, "samba_kdc_lookup_principal: could not parse principal");
2139                         krb5_warnx(context, "samba_kdc_lookup_principal: could not parse principal");
2140                         return ret;
2141                 }
2142
2143                 name1 = ldb_binary_encode_string(mem_ctx, short_princ);
2144                 SAFE_FREE(short_princ);
2145                 if (name1 == NULL) {
2146                         return ENOMEM;
2147                 }
2148                 len1 = strlen(name1);
2149                 if (len1 >= 1 && name1[len1 - 1] != '$') {
2150                         filter = talloc_asprintf(mem_ctx,
2151                                         "(&(objectClass=user)(|(samAccountName=%s)(samAccountName=%s$)))",
2152                                         name1, name1);
2153                         if (filter == NULL) {
2154                                 return ENOMEM;
2155                         }
2156                 } else {
2157                         filter = talloc_asprintf(mem_ctx,
2158                                         "(&(objectClass=user)(samAccountName=%s))",
2159                                         name1);
2160                         if (filter == NULL) {
2161                                 return ENOMEM;
2162                         }
2163                 }
2164
2165                 lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx, msg,
2166                                        *realm_dn, LDB_SCOPE_SUBTREE,
2167                                        attrs,
2168                                        DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
2169                                        "%s", filter);
2170                 if (lret == LDB_ERR_NO_SUCH_OBJECT) {
2171                         DEBUG(10, ("Failed to find an entry for %s filter:%s\n",
2172                                   name1, filter));
2173                         return SDB_ERR_NOENTRY;
2174                 }
2175                 if (lret == LDB_ERR_CONSTRAINT_VIOLATION) {
2176                         DEBUG(10, ("Failed to find unique entry for %s filter:%s\n",
2177                                   name1, filter));
2178                         return SDB_ERR_NOENTRY;
2179                 }
2180                 if (lret != LDB_SUCCESS) {
2181                         DEBUG(0, ("Failed single search for %s - %s\n",
2182                                   name1, ldb_errstring(kdc_db_ctx->samdb)));
2183                         return SDB_ERR_NOENTRY;
2184                 }
2185                 return 0;
2186         }
2187         return SDB_ERR_NOENTRY;
2188 }
2189
2190
2191
2192 static krb5_error_code samba_kdc_fetch_server(krb5_context context,
2193                                               struct samba_kdc_db_context *kdc_db_ctx,
2194                                               TALLOC_CTX *mem_ctx,
2195                                               krb5_const_principal principal,
2196                                               unsigned flags,
2197                                               struct sdb_entry_ex *entry_ex)
2198 {
2199         krb5_error_code ret;
2200         struct ldb_dn *realm_dn;
2201         struct ldb_message *msg;
2202
2203         ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, principal,
2204                                       flags, server_attrs, &realm_dn, &msg);
2205         if (ret != 0) {
2206                 return ret;
2207         }
2208
2209         ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
2210                                       principal, SAMBA_KDC_ENT_TYPE_SERVER,
2211                                       flags,
2212                                       realm_dn, msg, entry_ex);
2213         if (ret != 0) {
2214                 krb5_warnx(context, "samba_kdc_fetch: message2entry failed");
2215         }
2216
2217         return ret;
2218 }
2219
2220 static krb5_error_code samba_kdc_lookup_realm(krb5_context context,
2221                                               struct samba_kdc_db_context *kdc_db_ctx,
2222                                               TALLOC_CTX *mem_ctx,
2223                                               krb5_const_principal principal,
2224                                               unsigned flags,
2225                                               struct sdb_entry_ex *entry_ex)
2226 {
2227         TALLOC_CTX *frame = talloc_stackframe();
2228         NTSTATUS status;
2229         krb5_error_code ret;
2230         bool check_realm = false;
2231         const char *realm = NULL;
2232         struct dsdb_trust_routing_table *trt = NULL;
2233         const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
2234         unsigned int num_comp;
2235         bool ok;
2236         char *upper = NULL;
2237
2238         num_comp = krb5_princ_size(context, principal);
2239
2240         if (flags & SDB_F_GET_CLIENT) {
2241                 if (flags & SDB_F_FOR_AS_REQ) {
2242                         check_realm = true;
2243                 }
2244         }
2245         if (flags & SDB_F_GET_SERVER) {
2246                 if (flags & SDB_F_FOR_TGS_REQ) {
2247                         check_realm = true;
2248                 }
2249         }
2250
2251         if (!check_realm) {
2252                 TALLOC_FREE(frame);
2253                 return 0;
2254         }
2255
2256         realm = smb_krb5_principal_get_realm(frame, context, principal);
2257         if (realm == NULL) {
2258                 TALLOC_FREE(frame);
2259                 return ENOMEM;
2260         }
2261
2262         /*
2263          * The requested realm needs to be our own
2264          */
2265         ok = lpcfg_is_my_domain_or_realm(kdc_db_ctx->lp_ctx, realm);
2266         if (!ok) {
2267                 /*
2268                  * The request is not for us...
2269                  */
2270                 TALLOC_FREE(frame);
2271                 return SDB_ERR_NOENTRY;
2272         }
2273
2274         if (smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
2275                 char *principal_string = NULL;
2276                 krb5_principal enterprise_principal = NULL;
2277                 char *enterprise_realm = NULL;
2278
2279                 if (num_comp != 1) {
2280                         TALLOC_FREE(frame);
2281                         return SDB_ERR_NOENTRY;
2282                 }
2283
2284                 principal_string = smb_krb5_principal_get_comp_string(frame, context,
2285                                                                       principal, 0);
2286                 if (principal_string == NULL) {
2287                         TALLOC_FREE(frame);
2288                         return ENOMEM;
2289                 }
2290
2291                 ret = krb5_parse_name(context, principal_string,
2292                                       &enterprise_principal);
2293                 TALLOC_FREE(principal_string);
2294                 if (ret) {
2295                         TALLOC_FREE(frame);
2296                         return ret;
2297                 }
2298
2299                 enterprise_realm = smb_krb5_principal_get_realm(
2300                         frame, context, enterprise_principal);
2301                 krb5_free_principal(context, enterprise_principal);
2302                 if (enterprise_realm != NULL) {
2303                         realm = enterprise_realm;
2304                 }
2305         }
2306
2307         if (flags & SDB_F_GET_SERVER) {
2308                 char *service_realm = NULL;
2309
2310                 ret = principal_comp_strcmp(context, principal, 0, KRB5_TGS_NAME);
2311                 if (ret == 0) {
2312                         /*
2313                          * we need to search krbtgt/ locally
2314                          */
2315                         TALLOC_FREE(frame);
2316                         return 0;
2317                 }
2318
2319                 /*
2320                  * We need to check the last component against the routing table.
2321                  *
2322                  * Note this works only with 2 or 3 component principals, e.g:
2323                  *
2324                  * servicePrincipalName: ldap/W2K8R2-219.bla.base
2325                  * servicePrincipalName: ldap/W2K8R2-219.bla.base/bla.base
2326                  * servicePrincipalName: ldap/W2K8R2-219.bla.base/ForestDnsZones.bla.base
2327                  * servicePrincipalName: ldap/W2K8R2-219.bla.base/DomainDnsZones.bla.base
2328                  */
2329
2330                 if (num_comp == 2 || num_comp == 3) {
2331                         service_realm = smb_krb5_principal_get_comp_string(frame,
2332                                                                            context,
2333                                                                            principal,
2334                                                                            num_comp - 1);
2335                 }
2336
2337                 if (service_realm != NULL) {
2338                         realm = service_realm;
2339                 }
2340         }
2341
2342         ok = lpcfg_is_my_domain_or_realm(kdc_db_ctx->lp_ctx, realm);
2343         if (ok) {
2344                 /*
2345                  * skip the expensive routing lookup
2346                  */
2347                 TALLOC_FREE(frame);
2348                 return 0;
2349         }
2350
2351         status = dsdb_trust_routing_table_load(kdc_db_ctx->samdb,
2352                                                frame, &trt);
2353         if (!NT_STATUS_IS_OK(status)) {
2354                 TALLOC_FREE(frame);
2355                 return EINVAL;
2356         }
2357
2358         tdo = dsdb_trust_routing_by_name(trt, realm);
2359         if (tdo == NULL) {
2360                 /*
2361                  * This principal has to be local
2362                  */
2363                 TALLOC_FREE(frame);
2364                 return 0;
2365         }
2366
2367         if (tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
2368                 /*
2369                  * TODO: handle the routing within the forest
2370                  *
2371                  * This should likely be handled in
2372                  * samba_kdc_message2entry() in case we're
2373                  * a global catalog. We'd need to check
2374                  * if realm_dn is our own domain and derive
2375                  * the dns domain name from realm_dn and check that
2376                  * against the routing table or fallback to
2377                  * the tdo we found here.
2378                  *
2379                  * But for now we don't support multiple domains
2380                  * in our forest correctly anyway.
2381                  *
2382                  * Just search in our local database.
2383                  */
2384                 TALLOC_FREE(frame);
2385                 return 0;
2386         }
2387
2388         ZERO_STRUCT(entry_ex->entry);
2389
2390         ret = krb5_copy_principal(context, principal,
2391                                   &entry_ex->entry.principal);
2392         if (ret) {
2393                 TALLOC_FREE(frame);
2394                 return ret;
2395         }
2396
2397         upper = strupper_talloc(frame, tdo->domain_name.string);
2398         if (upper == NULL) {
2399                 TALLOC_FREE(frame);
2400                 return ENOMEM;
2401         }
2402
2403         ret = smb_krb5_principal_set_realm(context,
2404                                            entry_ex->entry.principal,
2405                                            upper);
2406         if (ret) {
2407                 TALLOC_FREE(frame);
2408                 return ret;
2409         }
2410
2411         TALLOC_FREE(frame);
2412         return SDB_ERR_WRONG_REALM;
2413 }
2414
2415 krb5_error_code samba_kdc_fetch(krb5_context context,
2416                                 struct samba_kdc_db_context *kdc_db_ctx,
2417                                 krb5_const_principal principal,
2418                                 unsigned flags,
2419                                 krb5_kvno kvno,
2420                                 struct sdb_entry_ex *entry_ex)
2421 {
2422         krb5_error_code ret = SDB_ERR_NOENTRY;
2423         TALLOC_CTX *mem_ctx;
2424
2425         mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
2426         if (!mem_ctx) {
2427                 ret = ENOMEM;
2428                 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
2429                 return ret;
2430         }
2431
2432         ret = samba_kdc_lookup_realm(context, kdc_db_ctx, mem_ctx,
2433                                      principal, flags, entry_ex);
2434         if (ret != 0) {
2435                 goto done;
2436         }
2437
2438         ret = SDB_ERR_NOENTRY;
2439
2440         if (flags & SDB_F_GET_CLIENT) {
2441                 ret = samba_kdc_fetch_client(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
2442                 if (ret != SDB_ERR_NOENTRY) goto done;
2443         }
2444         if (flags & SDB_F_GET_SERVER) {
2445                 /* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
2446                 ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry_ex);
2447                 if (ret != SDB_ERR_NOENTRY) goto done;
2448
2449                 /* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
2450                 ret = samba_kdc_fetch_server(context, kdc_db_ctx, mem_ctx, principal, flags, entry_ex);
2451                 if (ret != SDB_ERR_NOENTRY) goto done;
2452         }
2453         if (flags & SDB_F_GET_KRBTGT) {
2454                 ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry_ex);
2455                 if (ret != SDB_ERR_NOENTRY) goto done;
2456         }
2457
2458 done:
2459         talloc_free(mem_ctx);
2460         return ret;
2461 }
2462
2463 struct samba_kdc_seq {
2464         unsigned int index;
2465         unsigned int count;
2466         struct ldb_message **msgs;
2467         struct ldb_dn *realm_dn;
2468 };
2469
2470 static krb5_error_code samba_kdc_seq(krb5_context context,
2471                                      struct samba_kdc_db_context *kdc_db_ctx,
2472                                      struct sdb_entry_ex *entry)
2473 {
2474         krb5_error_code ret;
2475         struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
2476         const char *realm = lpcfg_realm(kdc_db_ctx->lp_ctx);
2477         struct ldb_message *msg = NULL;
2478         const char *sAMAccountName = NULL;
2479         krb5_principal principal = NULL;
2480         TALLOC_CTX *mem_ctx;
2481
2482         if (!priv) {
2483                 return SDB_ERR_NOENTRY;
2484         }
2485
2486         mem_ctx = talloc_named(priv, 0, "samba_kdc_seq context");
2487
2488         if (!mem_ctx) {
2489                 ret = ENOMEM;
2490                 krb5_set_error_message(context, ret, "samba_kdc_seq: talloc_named() failed!");
2491                 return ret;
2492         }
2493
2494         while (priv->index < priv->count) {
2495                 msg = priv->msgs[priv->index++];
2496
2497                 sAMAccountName = ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL);
2498                 if (sAMAccountName != NULL) {
2499                         break;
2500                 }
2501         }
2502
2503         if (sAMAccountName == NULL) {
2504                 ret = SDB_ERR_NOENTRY;
2505                 goto out;
2506         }
2507
2508         ret = smb_krb5_make_principal(context, &principal,
2509                                       realm, sAMAccountName, NULL);
2510         if (ret != 0) {
2511                 goto out;
2512         }
2513
2514         ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
2515                                       principal, SAMBA_KDC_ENT_TYPE_ANY,
2516                                       SDB_F_ADMIN_DATA|SDB_F_GET_ANY,
2517                                       priv->realm_dn, msg, entry);
2518
2519 out:
2520         if (principal != NULL) {
2521                 krb5_free_principal(context, principal);
2522         }
2523
2524         if (ret != 0) {
2525                 TALLOC_FREE(priv);
2526                 kdc_db_ctx->seq_ctx = NULL;
2527         } else {
2528                 talloc_free(mem_ctx);
2529         }
2530
2531         return ret;
2532 }
2533
2534 krb5_error_code samba_kdc_firstkey(krb5_context context,
2535                                    struct samba_kdc_db_context *kdc_db_ctx,
2536                                    struct sdb_entry_ex *entry)
2537 {
2538         struct ldb_context *ldb_ctx = kdc_db_ctx->samdb;
2539         struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
2540         char *realm;
2541         struct ldb_result *res = NULL;
2542         krb5_error_code ret;
2543         TALLOC_CTX *mem_ctx;
2544         int lret;
2545
2546         if (priv) {
2547                 TALLOC_FREE(priv);
2548                 kdc_db_ctx->seq_ctx = NULL;
2549         }
2550
2551         priv = (struct samba_kdc_seq *) talloc(kdc_db_ctx, struct samba_kdc_seq);
2552         if (!priv) {
2553                 ret = ENOMEM;
2554                 krb5_set_error_message(context, ret, "talloc: out of memory");
2555                 return ret;
2556         }
2557
2558         priv->index = 0;
2559         priv->msgs = NULL;
2560         priv->realm_dn = ldb_get_default_basedn(ldb_ctx);
2561         priv->count = 0;
2562
2563         mem_ctx = talloc_named(priv, 0, "samba_kdc_firstkey context");
2564
2565         if (!mem_ctx) {
2566                 ret = ENOMEM;
2567                 krb5_set_error_message(context, ret, "samba_kdc_firstkey: talloc_named() failed!");
2568                 return ret;
2569         }
2570
2571         ret = krb5_get_default_realm(context, &realm);
2572         if (ret != 0) {
2573                 TALLOC_FREE(priv);
2574                 return ret;
2575         }
2576         krb5_free_default_realm(context, realm);
2577
2578         lret = dsdb_search(ldb_ctx, priv, &res,
2579                            priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs,
2580                            DSDB_SEARCH_NO_GLOBAL_CATALOG,
2581                            "(objectClass=user)");
2582
2583         if (lret != LDB_SUCCESS) {
2584                 TALLOC_FREE(priv);
2585                 return SDB_ERR_NOENTRY;
2586         }
2587
2588         priv->count = res->count;
2589         priv->msgs = talloc_steal(priv, res->msgs);
2590         talloc_free(res);
2591
2592         kdc_db_ctx->seq_ctx = priv;
2593
2594         ret = samba_kdc_seq(context, kdc_db_ctx, entry);
2595
2596         if (ret != 0) {
2597                 TALLOC_FREE(priv);
2598                 kdc_db_ctx->seq_ctx = NULL;
2599         } else {
2600                 talloc_free(mem_ctx);
2601         }
2602         return ret;
2603 }
2604
2605 krb5_error_code samba_kdc_nextkey(krb5_context context,
2606                                   struct samba_kdc_db_context *kdc_db_ctx,
2607                                   struct sdb_entry_ex *entry)
2608 {
2609         return samba_kdc_seq(context, kdc_db_ctx, entry);
2610 }
2611
2612 /* Check if a given entry may delegate or do s4u2self to this target principal
2613  *
2614  * The safest way to determine 'self' is to check the DB record made at
2615  * the time the principal was presented to the KDC.
2616  */
2617 krb5_error_code
2618 samba_kdc_check_client_matches_target_service(krb5_context context,
2619                                               struct samba_kdc_entry *skdc_entry_client,
2620                                               struct samba_kdc_entry *skdc_entry_server_target)
2621 {
2622         struct dom_sid *orig_sid;
2623         struct dom_sid *target_sid;
2624         TALLOC_CTX *frame = talloc_stackframe();
2625
2626         orig_sid = samdb_result_dom_sid(frame,
2627                                         skdc_entry_client->msg,
2628                                         "objectSid");
2629         target_sid = samdb_result_dom_sid(frame,
2630                                           skdc_entry_server_target->msg,
2631                                           "objectSid");
2632
2633         /*
2634          * Allow delegation to the same record (representing a
2635          * principal), even if by a different name.  The easy and safe
2636          * way to prove this is by SID comparison
2637          */
2638         if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
2639                 talloc_free(frame);
2640                 return KRB5KRB_AP_ERR_BADMATCH;
2641         }
2642
2643         talloc_free(frame);
2644         return 0;
2645 }
2646
2647 /* Certificates printed by a the Certificate Authority might have a
2648  * slightly different form of the user principal name to that in the
2649  * database.  Allow a mismatch where they both refer to the same
2650  * SID */
2651
2652 krb5_error_code
2653 samba_kdc_check_pkinit_ms_upn_match(krb5_context context,
2654                                     struct samba_kdc_db_context *kdc_db_ctx,
2655                                     struct samba_kdc_entry *skdc_entry,
2656                                      krb5_const_principal certificate_principal)
2657 {
2658         krb5_error_code ret;
2659         struct ldb_dn *realm_dn;
2660         struct ldb_message *msg;
2661         struct dom_sid *orig_sid;
2662         struct dom_sid *target_sid;
2663         const char *ms_upn_check_attrs[] = {
2664                 "objectSid", NULL
2665         };
2666
2667         TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_pkinit_ms_upn_match");
2668
2669         if (!mem_ctx) {
2670                 ret = ENOMEM;
2671                 krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
2672                 return ret;
2673         }
2674
2675         ret = samba_kdc_lookup_client(context, kdc_db_ctx,
2676                                       mem_ctx, certificate_principal,
2677                                       ms_upn_check_attrs, &realm_dn, &msg);
2678
2679         if (ret != 0) {
2680                 talloc_free(mem_ctx);
2681                 return ret;
2682         }
2683
2684         orig_sid = samdb_result_dom_sid(mem_ctx, skdc_entry->msg, "objectSid");
2685         target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
2686
2687         /* Consider these to be the same principal, even if by a different
2688          * name.  The easy and safe way to prove this is by SID
2689          * comparison */
2690         if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
2691                 talloc_free(mem_ctx);
2692 #if defined(KRB5KDC_ERR_CLIENT_NAME_MISMATCH) /* MIT */
2693                 return KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
2694 #else /* Heimdal (where this is an enum) */
2695                 return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
2696 #endif
2697         }
2698
2699         talloc_free(mem_ctx);
2700         return ret;
2701 }
2702
2703 /*
2704  * Check if a given entry may delegate to this target principal
2705  * with S4U2Proxy.
2706  */
2707 krb5_error_code
2708 samba_kdc_check_s4u2proxy(krb5_context context,
2709                           struct samba_kdc_db_context *kdc_db_ctx,
2710                           struct samba_kdc_entry *skdc_entry,
2711                           krb5_const_principal target_principal)
2712 {
2713         krb5_error_code ret;
2714         char *tmp = NULL;
2715         const char *client_dn = NULL;
2716         const char *target_principal_name = NULL;
2717         struct ldb_message_element *el;
2718         struct ldb_val val;
2719         unsigned int i;
2720         bool found = false;
2721
2722         TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2proxy");
2723
2724         if (!mem_ctx) {
2725                 ret = ENOMEM;
2726                 krb5_set_error_message(context, ret,
2727                                        "samba_kdc_check_s4u2proxy:"
2728                                        " talloc_named() failed!");
2729                 return ret;
2730         }
2731
2732         client_dn = ldb_dn_get_linearized(skdc_entry->msg->dn);
2733         if (!client_dn) {
2734                 if (errno == 0) {
2735                         errno = ENOMEM;
2736                 }
2737                 ret = errno;
2738                 krb5_set_error_message(context, ret,
2739                                        "samba_kdc_check_s4u2proxy:"
2740                                        " ldb_dn_get_linearized() failed!");
2741                 return ret;
2742         }
2743
2744         el = ldb_msg_find_element(skdc_entry->msg, "msDS-AllowedToDelegateTo");
2745         if (el == NULL) {
2746                 ret = ENOENT;
2747                 goto bad_option;
2748         }
2749
2750         /*
2751          * This is the Microsoft forwardable flag behavior.
2752          *
2753          * If the proxy (target) principal is NULL, and we have any authorized
2754          * delegation target, allow to forward.
2755          */
2756         if (el->num_values >= 0 && target_principal == NULL) {
2757                 return 0;
2758         }
2759
2760
2761         /*
2762          * The main heimdal code already checked that the target_principal
2763          * belongs to the same realm as the client.
2764          *
2765          * So we just need the principal without the realm,
2766          * as that is what is configured in the "msDS-AllowedToDelegateTo"
2767          * attribute.
2768          */
2769         ret = krb5_unparse_name_flags(context, target_principal,
2770                                       KRB5_PRINCIPAL_UNPARSE_NO_REALM, &tmp);
2771         if (ret) {
2772                 talloc_free(mem_ctx);
2773                 krb5_set_error_message(context, ret,
2774                                        "samba_kdc_check_s4u2proxy:"
2775                                        " krb5_unparse_name() failed!");
2776                 return ret;
2777         }
2778         DEBUG(10,("samba_kdc_check_s4u2proxy: client[%s] for target[%s]\n",
2779                  client_dn, tmp));
2780
2781         target_principal_name = talloc_strdup(mem_ctx, tmp);
2782         SAFE_FREE(tmp);
2783         if (target_principal_name == NULL) {
2784                 ret = ENOMEM;
2785                 krb5_set_error_message(context, ret,
2786                                        "samba_kdc_check_s4u2proxy:"
2787                                        " talloc_strdup() failed!");
2788                 return ret;
2789         }
2790
2791         val = data_blob_string_const(target_principal_name);
2792
2793         for (i=0; i<el->num_values; i++) {
2794                 struct ldb_val *val1 = &val;
2795                 struct ldb_val *val2 = &el->values[i];
2796                 int cmp;
2797
2798                 if (val1->length != val2->length) {
2799                         continue;
2800                 }
2801
2802                 cmp = strncasecmp((const char *)val1->data,
2803                                   (const char *)val2->data,
2804                                   val1->length);
2805                 if (cmp != 0) {
2806                         continue;
2807                 }
2808
2809                 found = true;
2810                 break;
2811         }
2812
2813         if (!found) {
2814                 ret = ENOENT;
2815                 goto bad_option;
2816         }
2817
2818         DEBUG(10,("samba_kdc_check_s4u2proxy: client[%s] allowed target[%s]\n",
2819                  client_dn, tmp));
2820         talloc_free(mem_ctx);
2821         return 0;
2822
2823 bad_option:
2824         krb5_set_error_message(context, ret,
2825                                "samba_kdc_check_s4u2proxy: client[%s] "
2826                                "not allowed for delegation to target[%s]",
2827                                client_dn,
2828                                target_principal_name);
2829         talloc_free(mem_ctx);
2830         return KRB5KDC_ERR_BADOPTION;
2831 }
2832
2833 /*
2834  * This method is called for S4U2Proxy requests and implements the
2835  * resource-based constrained delegation variant, which can support
2836  * cross-realm delegation.
2837  */
2838 krb5_error_code samba_kdc_check_s4u2proxy_rbcd(
2839                 krb5_context context,
2840                 struct samba_kdc_db_context *kdc_db_ctx,
2841                 krb5_const_principal client_principal,
2842                 krb5_const_principal server_principal,
2843                 krb5_pac header_pac,
2844                 struct samba_kdc_entry *proxy_skdc_entry)
2845 {
2846         krb5_error_code code;
2847         enum ndr_err_code ndr_err;
2848         char *client_name = NULL;
2849         char *server_name = NULL;
2850         const char *proxy_dn = NULL;
2851         const DATA_BLOB *data = NULL;
2852         struct security_descriptor *rbcd_security_descriptor = NULL;
2853         struct auth_user_info_dc *user_info_dc = NULL;
2854         struct auth_session_info *session_info = NULL;
2855         uint32_t session_info_flags = AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
2856         uint32_t access_desired = SEC_ADS_GENERIC_ALL; /* => 0x000f01ff */
2857         uint32_t access_granted = 0;
2858         NTSTATUS nt_status;
2859         TALLOC_CTX *mem_ctx = NULL;
2860
2861         mem_ctx = talloc_named(kdc_db_ctx,
2862                                0,
2863                                "samba_kdc_check_s4u2proxy_rbcd");
2864         if (mem_ctx == NULL) {
2865                 errno = ENOMEM;
2866                 code = errno;
2867
2868                 return code;
2869         }
2870
2871         proxy_dn = ldb_dn_get_linearized(proxy_skdc_entry->msg->dn);
2872         if (proxy_dn == NULL) {
2873                 DBG_ERR("ldb_dn_get_linearized failed for proxy_dn!\n");
2874                 TALLOC_FREE(mem_ctx);
2875                 if (errno == 0) {
2876                         errno = ENOMEM;
2877                 }
2878                 code = errno;
2879
2880                 goto out;
2881         }
2882
2883         rbcd_security_descriptor = talloc_zero(mem_ctx,
2884                                                struct security_descriptor);
2885         if (rbcd_security_descriptor == NULL) {
2886                 errno = ENOMEM;
2887                 code = errno;
2888
2889                 goto out;
2890         }
2891
2892         code = krb5_unparse_name_flags(context,
2893                                        client_principal,
2894                                        KRB5_PRINCIPAL_UNPARSE_DISPLAY,
2895                                        &client_name);
2896         if (code != 0) {
2897                 DBG_ERR("Unable to parse client_principal!\n");
2898                 goto out;
2899         }
2900
2901         code = krb5_unparse_name_flags(context,
2902                                        server_principal,
2903                                        KRB5_PRINCIPAL_UNPARSE_DISPLAY,
2904                                        &server_name);
2905         if (code != 0) {
2906                 DBG_ERR("Unable to parse server_principal!\n");
2907                 SAFE_FREE(client_name);
2908                 goto out;
2909         }
2910
2911         DBG_INFO("Check delegation from client[%s] to server[%s] via "
2912                  "proxy[%s]\n",
2913                  client_name,
2914                  server_name,
2915                  proxy_dn);
2916
2917         code = kerberos_pac_to_user_info_dc(mem_ctx,
2918                                             header_pac,
2919                                             context,
2920                                             &user_info_dc,
2921                                             NULL,
2922                                             NULL);
2923         if (code != 0) {
2924                 goto out;
2925         }
2926
2927         if (user_info_dc->info->authenticated) {
2928                 session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
2929         }
2930
2931         nt_status = auth_generate_session_info(mem_ctx,
2932                                                kdc_db_ctx->lp_ctx,
2933                                                kdc_db_ctx->samdb,
2934                                                user_info_dc,
2935                                                session_info_flags,
2936                                                &session_info);
2937         if (!NT_STATUS_IS_OK(nt_status)) {
2938                 code = map_errno_from_nt_status(nt_status);
2939                 goto out;
2940         }
2941
2942         data = ldb_msg_find_ldb_val(proxy_skdc_entry->msg,
2943                                     "msDS-AllowedToActOnBehalfOfOtherIdentity");
2944         if (data == NULL) {
2945                 DBG_ERR("Could not find security descriptor"
2946                         "msDS-AllowedToActOnBehalfOfOtherIdentity in "
2947                         "proxy[%s]\n",
2948                         proxy_dn);
2949                 code = KRB5KDC_ERR_BADOPTION;
2950                 goto out;
2951         }
2952
2953         ndr_err = ndr_pull_struct_blob(
2954                         data,
2955                         mem_ctx,
2956                         rbcd_security_descriptor,
2957                         (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
2958         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2959                 errno = ndr_map_error2errno(ndr_err);
2960                 DBG_ERR("Failed to unmarshall "
2961                         "msDS-AllowedToActOnBehalfOfOtherIdentity "
2962                         "security descriptor of proxy[%s]\n",
2963                         proxy_dn);
2964                 code = KRB5KDC_ERR_BADOPTION;
2965                 goto out;
2966         }
2967
2968         if (DEBUGLEVEL >= 10) {
2969                 NDR_PRINT_DEBUG(security_token, session_info->security_token);
2970                 NDR_PRINT_DEBUG(security_descriptor, rbcd_security_descriptor);
2971         }
2972
2973         nt_status = sec_access_check_ds(rbcd_security_descriptor,
2974                                         session_info->security_token,
2975                                         access_desired,
2976                                         &access_granted,
2977                                         NULL,
2978                                         NULL);
2979
2980         if (!NT_STATUS_IS_OK(nt_status)) {
2981                 DBG_WARNING("RBCD: sec_access_check_ds(access_desired=%#08x, "
2982                             "access_granted:%#08x) failed with: %s\n",
2983                             access_desired,
2984                             access_granted,
2985                             nt_errstr(nt_status));
2986
2987                 code = KRB5KDC_ERR_BADOPTION;
2988                 goto out;
2989         }
2990
2991         DBG_NOTICE("RBCD: Access granted for client[%s]\n", client_name);
2992
2993         code = 0;
2994 out:
2995         SAFE_FREE(client_name);
2996         SAFE_FREE(server_name);
2997
2998         TALLOC_FREE(mem_ctx);
2999         return code;
3000 }
3001
3002 NTSTATUS samba_kdc_setup_db_ctx(TALLOC_CTX *mem_ctx, struct samba_kdc_base_context *base_ctx,
3003                                 struct samba_kdc_db_context **kdc_db_ctx_out)
3004 {
3005         int ldb_ret;
3006         struct ldb_message *msg;
3007         struct auth_session_info *session_info;
3008         struct samba_kdc_db_context *kdc_db_ctx;
3009         /* The idea here is very simple.  Using Kerberos to
3010          * authenticate the KDC to the LDAP server is higly likely to
3011          * be circular.
3012          *
3013          * In future we may set this up to use EXERNAL and SSL
3014          * certificates, for now it will almost certainly be NTLMSSP_SET_USERNAME
3015         */
3016
3017         kdc_db_ctx = talloc_zero(mem_ctx, struct samba_kdc_db_context);
3018         if (kdc_db_ctx == NULL) {
3019                 return NT_STATUS_NO_MEMORY;
3020         }
3021         kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
3022         kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
3023         kdc_db_ctx->msg_ctx = base_ctx->msg_ctx;
3024
3025         /* get default kdc policy */
3026         lpcfg_default_kdc_policy(mem_ctx,
3027                                  base_ctx->lp_ctx,
3028                                  &kdc_db_ctx->policy.svc_tkt_lifetime,
3029                                  &kdc_db_ctx->policy.usr_tkt_lifetime,
3030                                  &kdc_db_ctx->policy.renewal_lifetime);
3031
3032         session_info = system_session(kdc_db_ctx->lp_ctx);
3033         if (session_info == NULL) {
3034                 return NT_STATUS_INTERNAL_ERROR;
3035         }
3036
3037         /* Setup the link to secrets.ldb */
3038
3039         kdc_db_ctx->secrets_db = secrets_db_connect(kdc_db_ctx,
3040                                                     base_ctx->lp_ctx);
3041         if (kdc_db_ctx->secrets_db == NULL) {
3042                 DEBUG(1, ("samba_kdc_setup_db_ctx: "
3043                           "Cannot open secrets.ldb for KDC backend!"));
3044                 talloc_free(kdc_db_ctx);
3045                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3046         }
3047
3048         kdc_db_ctx->fx_cookie_dn = ldb_dn_new(kdc_db_ctx,
3049                                               kdc_db_ctx->secrets_db,
3050                                               "CN=FX Cookie");
3051
3052         /* Setup the link to LDB */
3053         kdc_db_ctx->samdb = samdb_connect(kdc_db_ctx,
3054                                           base_ctx->ev_ctx,
3055                                           base_ctx->lp_ctx,
3056                                           session_info,
3057                                           NULL,
3058                                           0);
3059         if (kdc_db_ctx->samdb == NULL) {
3060                 DEBUG(1, ("samba_kdc_setup_db_ctx: Cannot open samdb for KDC backend!"));
3061                 talloc_free(kdc_db_ctx);
3062                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3063         }
3064
3065         /* Find out our own krbtgt kvno */
3066         ldb_ret = samdb_rodc(kdc_db_ctx->samdb, &kdc_db_ctx->rodc);
3067         if (ldb_ret != LDB_SUCCESS) {
3068                 DEBUG(1, ("samba_kdc_setup_db_ctx: Cannot determine if we are an RODC in KDC backend: %s\n",
3069                           ldb_errstring(kdc_db_ctx->samdb)));
3070                 talloc_free(kdc_db_ctx);
3071                 return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3072         }
3073         if (kdc_db_ctx->rodc) {
3074                 int my_krbtgt_number;
3075                 const char *secondary_keytab[] = { "msDS-SecondaryKrbTgtNumber", NULL };
3076                 struct ldb_dn *account_dn;
3077                 struct ldb_dn *server_dn = samdb_server_dn(kdc_db_ctx->samdb, kdc_db_ctx);
3078                 if (!server_dn) {
3079                         DEBUG(1, ("samba_kdc_setup_db_ctx: Cannot determine server DN in KDC backend: %s\n",
3080                                   ldb_errstring(kdc_db_ctx->samdb)));
3081                         talloc_free(kdc_db_ctx);
3082                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3083                 }
3084
3085                 ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, server_dn,
3086                                              "serverReference", &account_dn);
3087                 if (ldb_ret != LDB_SUCCESS) {
3088                         DEBUG(1, ("samba_kdc_setup_db_ctx: Cannot determine server account in KDC backend: %s\n",
3089                                   ldb_errstring(kdc_db_ctx->samdb)));
3090                         talloc_free(kdc_db_ctx);
3091                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3092                 }
3093
3094                 ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, account_dn,
3095                                              "msDS-KrbTgtLink", &kdc_db_ctx->krbtgt_dn);
3096                 talloc_free(account_dn);
3097                 if (ldb_ret != LDB_SUCCESS) {
3098                         DEBUG(1, ("samba_kdc_setup_db_ctx: Cannot determine RODC krbtgt account in KDC backend: %s\n",
3099                                   ldb_errstring(kdc_db_ctx->samdb)));
3100                         talloc_free(kdc_db_ctx);
3101                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3102                 }
3103
3104                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
3105                                           &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
3106                                           secondary_keytab,
3107                                           DSDB_SEARCH_NO_GLOBAL_CATALOG,
3108                                           "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=*))");
3109                 if (ldb_ret != LDB_SUCCESS) {
3110                         DEBUG(1, ("samba_kdc_setup_db_ctx: Cannot read krbtgt account %s in KDC backend to get msDS-SecondaryKrbTgtNumber: %s: %s\n",
3111                                   ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
3112                                   ldb_errstring(kdc_db_ctx->samdb),
3113                                   ldb_strerror(ldb_ret)));
3114                         talloc_free(kdc_db_ctx);
3115                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3116                 }
3117                 my_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
3118                 if (my_krbtgt_number == -1) {
3119                         DEBUG(1, ("samba_kdc_setup_db_ctx: Cannot read msDS-SecondaryKrbTgtNumber from krbtgt account %s in KDC backend: got %d\n",
3120                                   ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
3121                                   my_krbtgt_number));
3122                         talloc_free(kdc_db_ctx);
3123                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3124                 }
3125                 kdc_db_ctx->my_krbtgt_number = my_krbtgt_number;
3126
3127         } else {
3128                 kdc_db_ctx->my_krbtgt_number = 0;
3129                 ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
3130                                           &msg,
3131                                           ldb_get_default_basedn(kdc_db_ctx->samdb),
3132                                           LDB_SCOPE_SUBTREE,
3133                                           krbtgt_attrs,
3134                                           DSDB_SEARCH_NO_GLOBAL_CATALOG,
3135                                           "(&(objectClass=user)(samAccountName=krbtgt))");
3136
3137                 if (ldb_ret != LDB_SUCCESS) {
3138                         DEBUG(1, ("samba_kdc_fetch: could not find own KRBTGT in DB: %s\n", ldb_errstring(kdc_db_ctx->samdb)));
3139                         talloc_free(kdc_db_ctx);
3140                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3141                 }
3142                 kdc_db_ctx->krbtgt_dn = talloc_steal(kdc_db_ctx, msg->dn);
3143                 kdc_db_ctx->my_krbtgt_number = 0;
3144                 talloc_free(msg);
3145         }
3146         *kdc_db_ctx_out = kdc_db_ctx;
3147         return NT_STATUS_OK;
3148 }