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