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