Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Database Glue between Samba and the KDC
5 :
6 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 : Copyright (C) Simo Sorce <idra@samba.org> 2010
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "libcli/security/security.h"
26 : #include "librpc/gen_ndr/ndr_security.h"
27 : #include "auth/auth.h"
28 : #include "auth/auth_sam.h"
29 : #include "dsdb/gmsa/util.h"
30 : #include "dsdb/samdb/samdb.h"
31 : #include "dsdb/common/util.h"
32 : #include "librpc/gen_ndr/ndr_drsblobs.h"
33 : #include "param/param.h"
34 : #include "param/secrets.h"
35 : #include "lib/crypto/gkdi.h"
36 : #include "../lib/crypto/md4.h"
37 : #include "lib/util/memory.h"
38 : #include "system/kerberos.h"
39 : #include "auth/kerberos/kerberos.h"
40 : #include "kdc/authn_policy_util.h"
41 : #include "kdc/sdb.h"
42 : #include "kdc/samba_kdc.h"
43 : #include "kdc/db-glue.h"
44 : #include "kdc/pac-glue.h"
45 : #include "librpc/gen_ndr/ndr_irpc_c.h"
46 : #include "lib/messaging/irpc.h"
47 :
48 : #undef DBGC_CLASS
49 : #define DBGC_CLASS DBGC_KERBEROS
50 :
51 : #undef strcasecmp
52 : #undef strncasecmp
53 :
54 : #define SAMBA_KVNO_GET_KRBTGT(kvno) \
55 : ((uint16_t)(((uint32_t)kvno) >> 16))
56 :
57 : #define SAMBA_KVNO_GET_VALUE(kvno) \
58 : ((uint16_t)(((uint32_t)kvno) & 0xFFFF))
59 :
60 : #define SAMBA_KVNO_AND_KRBTGT(kvno, krbtgt) \
61 : ((krb5_kvno)((((uint32_t)kvno) & 0xFFFF) | \
62 : ((((uint32_t)krbtgt) << 16) & 0xFFFF0000)))
63 :
64 : enum trust_direction {
65 : UNKNOWN = 0,
66 : INBOUND = LSA_TRUST_DIRECTION_INBOUND,
67 : OUTBOUND = LSA_TRUST_DIRECTION_OUTBOUND
68 : };
69 :
70 : static const char *trust_attrs[] = {
71 : "securityIdentifier",
72 : "flatName",
73 : "trustPartner",
74 : "trustAttributes",
75 : "trustDirection",
76 : "trustType",
77 : "msDS-TrustForestTrustInfo",
78 : "trustAuthIncoming",
79 : "trustAuthOutgoing",
80 : "whenCreated",
81 : "msDS-SupportedEncryptionTypes",
82 : NULL
83 : };
84 :
85 : /*
86 : send a message to the drepl server telling it to initiate a
87 : REPL_SECRET getncchanges extended op to fetch the users secrets
88 : */
89 1670 : static void auth_sam_trigger_repl_secret(TALLOC_CTX *mem_ctx,
90 : struct imessaging_context *msg_ctx,
91 : struct tevent_context *event_ctx,
92 : struct ldb_dn *user_dn)
93 : {
94 0 : struct dcerpc_binding_handle *irpc_handle;
95 0 : struct drepl_trigger_repl_secret r;
96 0 : struct tevent_req *req;
97 0 : TALLOC_CTX *tmp_ctx;
98 :
99 1670 : tmp_ctx = talloc_new(mem_ctx);
100 1670 : if (tmp_ctx == NULL) {
101 0 : return;
102 : }
103 :
104 1670 : irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg_ctx,
105 : "dreplsrv",
106 : &ndr_table_irpc);
107 1670 : if (irpc_handle == NULL) {
108 0 : DBG_WARNING("Unable to get binding handle for dreplsrv\n");
109 0 : TALLOC_FREE(tmp_ctx);
110 0 : return;
111 : }
112 :
113 1670 : r.in.user_dn = ldb_dn_get_linearized(user_dn);
114 1670 : if (r.in.user_dn == NULL) {
115 0 : DBG_WARNING("Unable to get user DN\n");
116 0 : TALLOC_FREE(tmp_ctx);
117 0 : return;
118 : }
119 :
120 : /*
121 : * This seem to rely on the current IRPC implementation,
122 : * which delivers the message in the _send function.
123 : *
124 : * TODO: we need a ONE_WAY IRPC handle and register
125 : * a callback and wait for it to be triggered!
126 : */
127 1670 : req = dcerpc_drepl_trigger_repl_secret_r_send(tmp_ctx,
128 : event_ctx,
129 : irpc_handle,
130 : &r);
131 :
132 : /* we aren't interested in a reply */
133 1670 : talloc_free(req);
134 1670 : TALLOC_FREE(tmp_ctx);
135 : }
136 :
137 2633 : static time_t ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const char *attr, time_t default_val)
138 : {
139 2633 : const struct ldb_val *gentime = NULL;
140 0 : time_t t;
141 0 : int ret;
142 :
143 2633 : gentime = ldb_msg_find_ldb_val(msg, attr);
144 2633 : ret = ldb_val_to_time(gentime, &t);
145 2633 : if (ret) {
146 264 : return default_val;
147 : }
148 :
149 2369 : return t;
150 : }
151 :
152 306249 : static struct SDBFlags uf2SDBFlags(krb5_context context, uint32_t userAccountControl, enum samba_kdc_ent_type ent_type)
153 : {
154 306249 : struct SDBFlags flags = {};
155 :
156 : /* we don't allow kadmin deletes */
157 306249 : flags.immutable = 1;
158 :
159 : /* mark the principal as invalid to start with */
160 306249 : flags.invalid = 1;
161 :
162 306249 : flags.renewable = 1;
163 :
164 : /* All accounts are servers, but this may be disabled again in the caller */
165 306249 : flags.server = 1;
166 :
167 : /* Account types - clear the invalid bit if it turns out to be valid */
168 306249 : if (userAccountControl & UF_NORMAL_ACCOUNT) {
169 263114 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
170 84016 : flags.client = 1;
171 : }
172 254107 : flags.invalid = 0;
173 : }
174 :
175 306249 : if (userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
176 3059 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
177 3059 : flags.client = 1;
178 : }
179 3059 : flags.invalid = 0;
180 : }
181 306249 : if (userAccountControl & UF_WORKSTATION_TRUST_ACCOUNT) {
182 13230 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
183 6708 : flags.client = 1;
184 : }
185 12956 : flags.invalid = 0;
186 : }
187 306249 : if (userAccountControl & UF_SERVER_TRUST_ACCOUNT) {
188 26846 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
189 7831 : flags.client = 1;
190 : }
191 25887 : flags.invalid = 0;
192 : }
193 :
194 : /* Not permitted to act as a client if disabled */
195 306249 : if (userAccountControl & UF_ACCOUNTDISABLE) {
196 176668 : flags.client = 0;
197 : }
198 306249 : if (userAccountControl & UF_LOCKOUT) {
199 26 : flags.locked_out = 1;
200 : }
201 : /*
202 : if (userAccountControl & UF_PASSWD_NOTREQD) {
203 : flags.invalid = 1;
204 : }
205 : */
206 : /*
207 : UF_PASSWD_CANT_CHANGE and UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED are irrelevant
208 : */
209 306249 : if (userAccountControl & UF_TEMP_DUPLICATE_ACCOUNT) {
210 0 : flags.invalid = 1;
211 : }
212 :
213 : /* UF_DONT_EXPIRE_PASSWD and UF_USE_DES_KEY_ONLY handled in samba_kdc_message2entry() */
214 :
215 : /*
216 : if (userAccountControl & UF_MNS_LOGON_ACCOUNT) {
217 : flags.invalid = 1;
218 : }
219 : */
220 306249 : if (userAccountControl & UF_SMARTCARD_REQUIRED) {
221 57 : flags.require_hwauth = 1;
222 : }
223 306249 : if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) {
224 21549 : flags.ok_as_delegate = 1;
225 : }
226 306249 : if (userAccountControl & UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION) {
227 : /*
228 : * this is confusing...
229 : *
230 : * UF_TRUSTED_FOR_DELEGATION
231 : * => ok_as_delegate
232 : *
233 : * and
234 : *
235 : * UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION
236 : * => trusted_for_delegation
237 : */
238 3608 : flags.trusted_for_delegation = 1;
239 : }
240 306249 : if (!(userAccountControl & UF_NOT_DELEGATED)) {
241 306241 : flags.forwardable = 1;
242 306241 : flags.proxiable = 1;
243 : }
244 :
245 306249 : if (userAccountControl & UF_DONT_REQUIRE_PREAUTH) {
246 0 : flags.require_preauth = 0;
247 : } else {
248 306249 : flags.require_preauth = 1;
249 : }
250 :
251 306249 : if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
252 30 : flags.no_auth_data_reqd = 1;
253 : }
254 :
255 306249 : return flags;
256 : }
257 :
258 616447 : static int samba_kdc_entry_destructor(struct samba_kdc_entry *p)
259 : {
260 616447 : if (p->db_entry != NULL) {
261 : /*
262 : * A sdb_entry still has a reference
263 : */
264 0 : return -1;
265 : }
266 :
267 616447 : if (p->kdc_entry != NULL) {
268 : /*
269 : * hdb_entry or krb5_db_entry still
270 : * have a reference...
271 : */
272 308557 : return -1;
273 : }
274 :
275 297650 : return 0;
276 : }
277 :
278 : /*
279 : * Sort keys in descending order of strength.
280 : *
281 : * Explanation from Greg Hudson:
282 : *
283 : * To encrypt tickets only the first returned key is used by the MIT KDC. The
284 : * other keys just communicate support for session key enctypes, and aren't
285 : * really used. The encryption key for the ticket enc part doesn't have
286 : * to be of a type requested by the client. The session key enctype is chosen
287 : * based on the client preference order, limited by the set of enctypes present
288 : * in the server keys (unless the string attribute is set on the server
289 : * principal overriding that set).
290 : */
291 :
292 1103378 : static int sdb_key_strength_priority(krb5_enctype etype)
293 : {
294 20442 : static const krb5_enctype etype_list[] = {
295 : ENCTYPE_AES256_CTS_HMAC_SHA1_96,
296 : ENCTYPE_AES128_CTS_HMAC_SHA1_96,
297 : ENCTYPE_DES3_CBC_SHA1,
298 : ENCTYPE_ARCFOUR_HMAC,
299 : ENCTYPE_DES_CBC_MD5,
300 : ENCTYPE_DES_CBC_MD4,
301 : ENCTYPE_DES_CBC_CRC,
302 : ENCTYPE_NULL
303 : };
304 20442 : int i;
305 :
306 2472540 : for (i = 0; i < ARRAY_SIZE(etype_list); i++) {
307 2472540 : if (etype == etype_list[i]) {
308 1062494 : break;
309 : }
310 : }
311 :
312 1103378 : return ARRAY_SIZE(etype_list) - i;
313 : }
314 :
315 551689 : static int sdb_key_strength_cmp(const struct sdb_key *k1, const struct sdb_key *k2)
316 : {
317 551689 : int p1 = sdb_key_strength_priority(KRB5_KEY_TYPE(&k1->key));
318 551689 : int p2 = sdb_key_strength_priority(KRB5_KEY_TYPE(&k2->key));
319 :
320 551689 : if (p1 == p2) {
321 0 : return 0;
322 : }
323 :
324 551689 : if (p1 > p2) {
325 : /*
326 : * Higher priority comes first
327 : */
328 531247 : return -1;
329 : } else {
330 0 : return 1;
331 : }
332 : }
333 :
334 335562 : static void samba_kdc_sort_keys(struct sdb_keys *keys)
335 : {
336 335562 : if (keys == NULL) {
337 0 : return;
338 : }
339 :
340 335562 : TYPESAFE_QSORT(keys->val, keys->len, sdb_key_strength_cmp);
341 : }
342 :
343 96 : int samba_kdc_set_fixed_keys(krb5_context context,
344 : const struct ldb_val *secretbuffer,
345 : uint32_t supported_enctypes,
346 : struct sdb_keys *keys)
347 : {
348 96 : uint16_t allocated_keys = 0;
349 0 : int ret;
350 :
351 96 : allocated_keys = 3;
352 96 : keys->len = 0;
353 96 : keys->val = calloc(allocated_keys, sizeof(struct sdb_key));
354 96 : if (keys->val == NULL) {
355 0 : memset(secretbuffer->data, 0, secretbuffer->length);
356 0 : ret = ENOMEM;
357 0 : goto out;
358 : }
359 :
360 96 : if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
361 58 : struct sdb_key key = {};
362 :
363 58 : ret = smb_krb5_keyblock_init_contents(context,
364 : ENCTYPE_AES256_CTS_HMAC_SHA1_96,
365 58 : secretbuffer->data,
366 58 : MIN(secretbuffer->length, 32),
367 : &key.key);
368 58 : if (ret) {
369 0 : memset(secretbuffer->data, 0, secretbuffer->length);
370 0 : goto out;
371 : }
372 :
373 58 : keys->val[keys->len] = key;
374 58 : keys->len++;
375 : }
376 :
377 96 : if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
378 58 : struct sdb_key key = {};
379 :
380 58 : ret = smb_krb5_keyblock_init_contents(context,
381 : ENCTYPE_AES128_CTS_HMAC_SHA1_96,
382 58 : secretbuffer->data,
383 58 : MIN(secretbuffer->length, 16),
384 : &key.key);
385 58 : if (ret) {
386 0 : memset(secretbuffer->data, 0, secretbuffer->length);
387 0 : goto out;
388 : }
389 :
390 58 : keys->val[keys->len] = key;
391 58 : keys->len++;
392 : }
393 :
394 96 : if (supported_enctypes & ENC_RC4_HMAC_MD5) {
395 96 : struct sdb_key key = {};
396 :
397 96 : ret = smb_krb5_keyblock_init_contents(context,
398 : ENCTYPE_ARCFOUR_HMAC,
399 96 : secretbuffer->data,
400 96 : MIN(secretbuffer->length, 16),
401 : &key.key);
402 96 : if (ret) {
403 0 : memset(secretbuffer->data, 0, secretbuffer->length);
404 0 : goto out;
405 : }
406 :
407 96 : keys->val[keys->len] = key;
408 96 : keys->len++;
409 : }
410 96 : ret = 0;
411 96 : out:
412 96 : return ret;
413 : }
414 :
415 :
416 96 : static int samba_kdc_set_random_keys(krb5_context context,
417 : uint32_t supported_enctypes,
418 : struct sdb_keys *keys)
419 : {
420 0 : struct ldb_val secret_val;
421 0 : uint8_t secretbuffer[32];
422 :
423 : /*
424 : * Fake keys until we have a better way to reject
425 : * non-pkinit requests.
426 : *
427 : * We just need to indicate which encryption types are
428 : * supported.
429 : */
430 96 : generate_secret_buffer(secretbuffer, sizeof(secretbuffer));
431 :
432 96 : secret_val = data_blob_const(secretbuffer,
433 : sizeof(secretbuffer));
434 96 : return samba_kdc_set_fixed_keys(context,
435 : &secret_val,
436 : supported_enctypes,
437 : keys);
438 : }
439 :
440 : struct samba_kdc_user_keys {
441 : struct sdb_keys *skeys;
442 : uint32_t kvno;
443 : uint32_t *returned_kvno;
444 : uint32_t supported_enctypes;
445 : uint32_t *available_enctypes;
446 : const struct samr_Password *nthash;
447 : const char *salt_string;
448 : uint16_t num_pkeys;
449 : const struct package_PrimaryKerberosKey4 *pkeys;
450 : };
451 :
452 333457 : static krb5_error_code samba_kdc_fill_user_keys(krb5_context context,
453 : struct samba_kdc_user_keys *p)
454 : {
455 : /*
456 : * Make sure we'll never reveal DES keys
457 : */
458 333457 : uint32_t supported_enctypes = p->supported_enctypes &= ~(ENC_CRC32 | ENC_RSA_MD5);
459 333457 : uint32_t _available_enctypes = 0;
460 333457 : uint32_t *available_enctypes = p->available_enctypes;
461 333457 : uint32_t _returned_kvno = 0;
462 333457 : uint32_t *returned_kvno = p->returned_kvno;
463 333457 : uint32_t num_pkeys = p->num_pkeys;
464 333457 : uint32_t allocated_keys = num_pkeys;
465 10646 : uint32_t i;
466 10646 : int ret;
467 :
468 333457 : if (available_enctypes == NULL) {
469 8564 : available_enctypes = &_available_enctypes;
470 : }
471 :
472 333457 : *available_enctypes = 0;
473 :
474 333457 : if (returned_kvno == NULL) {
475 8564 : returned_kvno = &_returned_kvno;
476 : }
477 :
478 333457 : *returned_kvno = p->kvno;
479 :
480 333457 : if (p->nthash != NULL) {
481 303574 : allocated_keys += 1;
482 : }
483 :
484 333457 : allocated_keys = MAX(1, allocated_keys);
485 :
486 : /* allocate space to decode into */
487 333457 : p->skeys->len = 0;
488 333457 : p->skeys->val = calloc(allocated_keys, sizeof(struct sdb_key));
489 333457 : if (p->skeys->val == NULL) {
490 0 : return ENOMEM;
491 : }
492 :
493 1479681 : for (i=0; i < num_pkeys; i++) {
494 1146224 : struct sdb_key key = {};
495 41032 : uint32_t enctype_bit;
496 :
497 1146224 : if (p->pkeys[i].value == NULL) {
498 1146224 : continue;
499 : }
500 :
501 1146224 : enctype_bit = kerberos_enctype_to_bitmap(p->pkeys[i].keytype);
502 1146224 : if (!(enctype_bit & supported_enctypes)) {
503 584287 : continue;
504 : }
505 :
506 561937 : if (p->salt_string != NULL) {
507 20479 : DATA_BLOB salt;
508 :
509 561937 : salt = data_blob_string_const(p->salt_string);
510 :
511 561937 : key.salt = calloc(1, sizeof(*key.salt));
512 561937 : if (key.salt == NULL) {
513 0 : ret = ENOMEM;
514 0 : goto fail;
515 : }
516 :
517 561937 : key.salt->type = KRB5_PW_SALT;
518 :
519 582416 : ret = smb_krb5_copy_data_contents(&key.salt->salt,
520 561937 : salt.data,
521 : salt.length);
522 561937 : if (ret) {
523 0 : *key.salt = (struct sdb_salt) {};
524 0 : sdb_key_free(&key);
525 0 : goto fail;
526 : }
527 : }
528 :
529 582416 : ret = smb_krb5_keyblock_init_contents(context,
530 561937 : p->pkeys[i].keytype,
531 561937 : p->pkeys[i].value->data,
532 561937 : p->pkeys[i].value->length,
533 : &key.key);
534 561937 : if (ret == 0) {
535 561937 : p->skeys->val[p->skeys->len++] = key;
536 561937 : *available_enctypes |= enctype_bit;
537 561937 : continue;
538 : }
539 0 : ZERO_STRUCT(key.key);
540 0 : sdb_key_free(&key);
541 0 : if (ret == KRB5_PROG_ETYPE_NOSUPP) {
542 0 : DEBUG(2,("Unsupported keytype ignored - type %u\n",
543 : p->pkeys[i].keytype));
544 0 : ret = 0;
545 0 : continue;
546 : }
547 :
548 0 : goto fail;
549 : }
550 :
551 333457 : if (p->nthash != NULL && (supported_enctypes & ENC_RC4_HMAC_MD5)) {
552 298678 : struct sdb_key key = {};
553 :
554 308954 : ret = smb_krb5_keyblock_init_contents(context,
555 : ENCTYPE_ARCFOUR_HMAC,
556 298678 : p->nthash->hash,
557 : sizeof(p->nthash->hash),
558 : &key.key);
559 298678 : if (ret == 0) {
560 298678 : p->skeys->val[p->skeys->len++] = key;
561 :
562 298678 : *available_enctypes |= ENC_RC4_HMAC_MD5;
563 0 : } else if (ret == KRB5_PROG_ETYPE_NOSUPP) {
564 0 : DEBUG(2,("Unsupported keytype ignored - type %u\n",
565 : ENCTYPE_ARCFOUR_HMAC));
566 0 : ret = 0;
567 : }
568 298678 : if (ret != 0) {
569 0 : goto fail;
570 : }
571 : }
572 :
573 333457 : samba_kdc_sort_keys(p->skeys);
574 :
575 333457 : return 0;
576 0 : fail:
577 0 : sdb_keys_free(p->skeys);
578 0 : return ret;
579 : }
580 :
581 2 : static krb5_error_code samba_kdc_merge_keys(struct sdb_keys *keys,
582 : struct sdb_keys *old_keys)
583 : {
584 0 : unsigned num_keys;
585 0 : unsigned num_old_keys;
586 0 : unsigned total_keys;
587 0 : unsigned j;
588 2 : struct sdb_key *skeys = NULL;
589 :
590 2 : if (keys == NULL || old_keys == NULL) {
591 0 : return EINVAL;
592 : }
593 :
594 2 : num_keys = keys->len;
595 2 : num_old_keys = old_keys->len;
596 2 : total_keys = num_keys + num_old_keys;
597 :
598 2 : skeys = realloc(keys->val, total_keys * sizeof keys->val[0]);
599 2 : if (skeys == NULL) {
600 0 : return ENOMEM;
601 : }
602 2 : keys->val = skeys;
603 :
604 8 : for (j = 0; j < num_old_keys; ++j) {
605 6 : keys->val[num_keys + j] = old_keys->val[j];
606 : }
607 2 : keys->len = total_keys;
608 :
609 2 : old_keys->len = 0;
610 2 : SAFE_FREE(old_keys->val);
611 :
612 2 : return 0;
613 : }
614 :
615 325041 : krb5_error_code samba_kdc_message2entry_keys(krb5_context context,
616 : TALLOC_CTX *mem_ctx,
617 : struct ldb_context *ldb,
618 : const struct ldb_message *msg,
619 : bool is_krbtgt,
620 : bool is_rodc,
621 : uint32_t userAccountControl,
622 : enum samba_kdc_ent_type ent_type,
623 : unsigned flags,
624 : krb5_kvno requested_kvno,
625 : struct sdb_entry *entry,
626 : const uint32_t supported_enctypes_in,
627 : uint32_t *supported_enctypes_out)
628 : {
629 325041 : krb5_error_code ret = 0;
630 10379 : enum ndr_err_code ndr_err;
631 10379 : struct samr_Password *hash;
632 325041 : unsigned int num_ntPwdHistory = 0;
633 325041 : struct samr_Password *ntPwdHistory = NULL;
634 325041 : struct samr_Password *old_hash = NULL;
635 325041 : struct samr_Password *older_hash = NULL;
636 10379 : const struct ldb_val *sc_val;
637 10379 : struct supplementalCredentialsBlob scb;
638 325041 : struct supplementalCredentialsPackage *scpk = NULL;
639 10379 : struct package_PrimaryKerberosBlob _pkb;
640 325041 : struct package_PrimaryKerberosCtr4 *pkb4 = NULL;
641 325041 : int krbtgt_number = 0;
642 10379 : uint32_t current_kvno;
643 325041 : uint32_t old_kvno = 0;
644 325041 : uint32_t older_kvno = 0;
645 325041 : uint32_t returned_kvno = 0;
646 10379 : uint16_t i;
647 325041 : struct samba_kdc_user_keys keys = { .num_pkeys = 0, };
648 325041 : struct samba_kdc_user_keys old_keys = { .num_pkeys = 0, };
649 325041 : struct samba_kdc_user_keys older_keys = { .num_pkeys = 0, };
650 325041 : uint32_t available_enctypes = 0;
651 325041 : uint32_t supported_enctypes = supported_enctypes_in;
652 325041 : const bool exporting_keytab = flags & SDB_F_ADMIN_DATA;
653 :
654 325041 : *supported_enctypes_out = 0;
655 :
656 : /* Is this the krbtgt or a RODC krbtgt */
657 325041 : if (is_rodc) {
658 7026 : krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
659 :
660 7026 : if (krbtgt_number == -1) {
661 0 : return EINVAL;
662 : }
663 7026 : if (krbtgt_number == 0) {
664 0 : return EINVAL;
665 : }
666 : }
667 :
668 325041 : if (flags & SDB_F_USER2USER_PRINCIPAL) {
669 : /*
670 : * User2User uses the session key
671 : * from the additional ticket,
672 : * so we just provide random keys
673 : * here in order to make sure
674 : * we never expose the user password
675 : * keys.
676 : */
677 39 : ret = samba_kdc_set_random_keys(context,
678 : supported_enctypes,
679 : &entry->keys);
680 :
681 39 : *supported_enctypes_out = supported_enctypes & ENC_ALL_TYPES;
682 :
683 39 : goto out;
684 : }
685 :
686 325002 : if ((ent_type == SAMBA_KDC_ENT_TYPE_CLIENT)
687 120331 : && (userAccountControl & UF_SMARTCARD_REQUIRED)) {
688 57 : ret = samba_kdc_set_random_keys(context,
689 : supported_enctypes,
690 : &entry->keys);
691 :
692 57 : *supported_enctypes_out = supported_enctypes & ENC_ALL_TYPES;
693 :
694 57 : goto out;
695 : }
696 :
697 324945 : current_kvno = ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0);
698 324945 : if (current_kvno > 1) {
699 40076 : old_kvno = current_kvno - 1;
700 : }
701 324945 : if (current_kvno > 2) {
702 17791 : older_kvno = current_kvno - 2;
703 : }
704 324945 : if (is_krbtgt) {
705 : /*
706 : * Even for the main krbtgt account
707 : * we have to strictly split the kvno into
708 : * two 16-bit parts and the upper 16-bit
709 : * need to be all zero, even if
710 : * the msDS-KeyVersionNumber has a value
711 : * larger than 65535.
712 : *
713 : * See https://bugzilla.samba.org/show_bug.cgi?id=14951
714 : */
715 176649 : current_kvno = SAMBA_KVNO_GET_VALUE(current_kvno);
716 176649 : old_kvno = SAMBA_KVNO_GET_VALUE(old_kvno);
717 176649 : older_kvno = SAMBA_KVNO_GET_VALUE(older_kvno);
718 176649 : requested_kvno = SAMBA_KVNO_GET_VALUE(requested_kvno);
719 : }
720 :
721 : /* Get keys from the db */
722 :
723 324945 : hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
724 324945 : num_ntPwdHistory = samdb_result_hashes(mem_ctx, msg,
725 : "ntPwdHistory",
726 : &ntPwdHistory);
727 324945 : if (num_ntPwdHistory > 1) {
728 7507 : old_hash = &ntPwdHistory[1];
729 : }
730 324945 : if (num_ntPwdHistory > 2) {
731 3903 : older_hash = &ntPwdHistory[2];
732 : }
733 324945 : sc_val = ldb_msg_find_ldb_val(msg, "supplementalCredentials");
734 :
735 : /* supplementalCredentials if present */
736 324945 : if (sc_val) {
737 303418 : ndr_err = ndr_pull_struct_blob_all(sc_val, mem_ctx, &scb,
738 : (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
739 303418 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
740 0 : ret = EINVAL;
741 0 : goto out;
742 : }
743 :
744 303418 : if (scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
745 0 : if (scb.sub.num_packages != 0) {
746 0 : NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
747 0 : ret = EINVAL;
748 0 : goto out;
749 : }
750 : }
751 :
752 360289 : for (i=0; i < scb.sub.num_packages; i++) {
753 341332 : if (scb.sub.packages[i].name != NULL &&
754 341332 : strcmp("Primary:Kerberos-Newer-Keys", scb.sub.packages[i].name) == 0)
755 : {
756 284461 : scpk = &scb.sub.packages[i];
757 284461 : if (!scpk->data || !scpk->data[0]) {
758 0 : scpk = NULL;
759 0 : continue;
760 : }
761 274221 : break;
762 : }
763 : }
764 : }
765 : /*
766 : * Primary:Kerberos-Newer-Keys element
767 : * of supplementalCredentials
768 : *
769 : * The legacy Primary:Kerberos only contains
770 : * single DES keys, which are completely ignored
771 : * now.
772 : */
773 324806 : if (scpk) {
774 10240 : DATA_BLOB blob;
775 :
776 284461 : blob = strhex_to_data_blob(mem_ctx, scpk->data);
777 284461 : if (!blob.data) {
778 0 : ret = ENOMEM;
779 0 : goto out;
780 : }
781 :
782 : /* we cannot use ndr_pull_struct_blob_all() here, as w2k and w2k3 add padding bytes */
783 284461 : ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &_pkb,
784 : (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
785 284461 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
786 0 : ret = EINVAL;
787 0 : krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: could not parse package_PrimaryKerberosBlob");
788 0 : krb5_warnx(context, "samba_kdc_message2entry_keys: could not parse package_PrimaryKerberosBlob");
789 0 : goto out;
790 : }
791 :
792 284461 : if (_pkb.version != 4) {
793 0 : ret = EINVAL;
794 0 : krb5_set_error_message(context, ret, "samba_kdc_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4");
795 0 : krb5_warnx(context, "samba_kdc_message2entry_keys: Primary:Kerberos-Newer-Keys not version 4");
796 0 : goto out;
797 : }
798 :
799 284461 : pkb4 = &_pkb.ctr.ctr4;
800 : }
801 :
802 324945 : keys = (struct samba_kdc_user_keys) {
803 : .kvno = current_kvno,
804 : .supported_enctypes = supported_enctypes,
805 : .nthash = hash,
806 324945 : .salt_string = pkb4 != NULL ? pkb4->salt.string : NULL,
807 : .num_pkeys = pkb4 != NULL ? pkb4->num_keys : 0,
808 324945 : .pkeys = pkb4 != NULL ? pkb4->keys : NULL,
809 : };
810 :
811 324945 : old_keys = (struct samba_kdc_user_keys) {
812 : .kvno = old_kvno,
813 : .supported_enctypes = supported_enctypes,
814 : .nthash = old_hash,
815 324945 : .salt_string = pkb4 != NULL ? pkb4->salt.string : NULL,
816 : .num_pkeys = pkb4 != NULL ? pkb4->num_old_keys : 0,
817 324945 : .pkeys = pkb4 != NULL ? pkb4->old_keys : NULL,
818 : };
819 324945 : older_keys = (struct samba_kdc_user_keys) {
820 : .kvno = older_kvno,
821 : .supported_enctypes = supported_enctypes,
822 : .nthash = older_hash,
823 314566 : .salt_string = pkb4 != NULL ? pkb4->salt.string : NULL,
824 : .num_pkeys = pkb4 != NULL ? pkb4->num_older_keys : 0,
825 324945 : .pkeys = pkb4 != NULL ? pkb4->older_keys : NULL,
826 : };
827 :
828 324945 : if (flags & SDB_F_KVNO_SPECIFIED) {
829 52551 : if (requested_kvno == keys.kvno) {
830 : /*
831 : * The current kvno was requested,
832 : * so we return it.
833 : */
834 51893 : keys.skeys = &entry->keys;
835 51893 : keys.available_enctypes = &available_enctypes;
836 51893 : keys.returned_kvno = &returned_kvno;
837 658 : } else if (requested_kvno == 0) {
838 : /*
839 : * don't return any keys
840 : */
841 606 : } else if (requested_kvno == old_keys.kvno) {
842 : /*
843 : * return the old keys as default keys
844 : * with the requested kvno.
845 : */
846 416 : old_keys.skeys = &entry->keys;
847 416 : old_keys.available_enctypes = &available_enctypes;
848 416 : old_keys.returned_kvno = &returned_kvno;
849 190 : } else if (requested_kvno == older_keys.kvno) {
850 : /*
851 : * return the older keys as default keys
852 : * with the requested kvno.
853 : */
854 190 : older_keys.skeys = &entry->keys;
855 190 : older_keys.available_enctypes = &available_enctypes;
856 190 : older_keys.returned_kvno = &returned_kvno;
857 : } else {
858 : /*
859 : * don't return any keys
860 : */
861 : }
862 : } else {
863 272394 : bool include_history = false;
864 :
865 272394 : if ((flags & SDB_F_GET_CLIENT) && (flags & SDB_F_FOR_AS_REQ)) {
866 48864 : include_history = true;
867 221754 : } else if (exporting_keytab) {
868 264 : include_history = true;
869 : }
870 :
871 272394 : keys.skeys = &entry->keys;
872 272394 : keys.available_enctypes = &available_enctypes;
873 272394 : keys.returned_kvno = &returned_kvno;
874 :
875 272394 : if (include_history && old_keys.kvno != 0) {
876 6981 : old_keys.skeys = &entry->old_keys;
877 : }
878 272394 : if (include_history && older_keys.kvno != 0) {
879 1583 : older_keys.skeys = &entry->older_keys;
880 : }
881 : }
882 :
883 324945 : if (keys.skeys != NULL) {
884 324287 : ret = samba_kdc_fill_user_keys(context, &keys);
885 324287 : if (ret != 0) {
886 0 : goto out;
887 : }
888 : }
889 :
890 324945 : if (old_keys.skeys != NULL) {
891 7397 : ret = samba_kdc_fill_user_keys(context, &old_keys);
892 7397 : if (ret != 0) {
893 0 : goto out;
894 : }
895 :
896 7397 : if (keys.skeys != NULL && !exporting_keytab) {
897 249 : bool is_gmsa;
898 :
899 6863 : is_gmsa = dsdb_account_is_gmsa(ldb, msg);
900 6863 : if (is_gmsa) {
901 0 : NTTIME current_time;
902 0 : bool gmsa_key_is_recent;
903 0 : bool ok;
904 :
905 5 : ok = dsdb_gmsa_current_time(ldb, ¤t_time);
906 5 : if (!ok) {
907 0 : ret = EINVAL;
908 0 : goto out;
909 : }
910 :
911 5 : gmsa_key_is_recent = samdb_gmsa_key_is_recent(
912 : msg, current_time);
913 5 : if (gmsa_key_is_recent) {
914 : /*
915 : * As the current gMSA keys are less
916 : * than five minutes old, the previous
917 : * set of keys remains valid. The
918 : * Heimdal KDC will try each of the
919 : * current keys when decrypting a
920 : * client’s PA‐DATA, so by merging the
921 : * old set into the current set we can
922 : * cause both sets to be considered for
923 : * decryption.
924 : */
925 2 : ret = samba_kdc_merge_keys(
926 : keys.skeys, old_keys.skeys);
927 2 : if (ret) {
928 0 : goto out;
929 : }
930 : }
931 : }
932 : }
933 : }
934 :
935 324945 : if (older_keys.skeys != NULL) {
936 1773 : ret = samba_kdc_fill_user_keys(context, &older_keys);
937 1773 : if (ret != 0) {
938 0 : goto out;
939 : }
940 : }
941 :
942 324945 : *supported_enctypes_out |= available_enctypes;
943 :
944 324945 : if (is_krbtgt) {
945 : /*
946 : * Even for the main krbtgt account
947 : * we have to strictly split the kvno into
948 : * two 16-bit parts and the upper 16-bit
949 : * need to be all zero, even if
950 : * the msDS-KeyVersionNumber has a value
951 : * larger than 65535.
952 : *
953 : * See https://bugzilla.samba.org/show_bug.cgi?id=14951
954 : */
955 176649 : returned_kvno = SAMBA_KVNO_AND_KRBTGT(returned_kvno, krbtgt_number);
956 : }
957 324945 : entry->kvno = returned_kvno;
958 :
959 314662 : out:
960 314662 : return ret;
961 : }
962 :
963 53305 : static krb5_error_code is_principal_component_equal_impl(krb5_context context,
964 : krb5_const_principal principal,
965 : unsigned int component,
966 : const char *string,
967 : bool do_strcasecmp,
968 : bool *eq)
969 : {
970 1672 : const char *p;
971 :
972 : #if defined(HAVE_KRB5_PRINCIPAL_GET_COMP_STRING)
973 53027 : if (component >= krb5_princ_size(context, principal)) {
974 : /* A non‐existent component compares equal to no string. */
975 0 : *eq = false;
976 0 : return 0;
977 : }
978 53027 : p = krb5_principal_get_comp_string(context, principal, component);
979 53027 : if (p == NULL) {
980 0 : return ENOENT;
981 : }
982 53027 : if (do_strcasecmp) {
983 119 : *eq = strcasecmp(p, string) == 0;
984 : } else {
985 52908 : *eq = strcmp(p, string) == 0;
986 : }
987 51355 : return 0;
988 : #else
989 : size_t len;
990 : krb5_data d;
991 278 : krb5_error_code ret = 0;
992 :
993 278 : if (component > INT_MAX) {
994 0 : return EINVAL;
995 : }
996 :
997 278 : if (component >= krb5_princ_size(context, principal)) {
998 : /* A non‐existent component compares equal to no string. */
999 0 : *eq = false;
1000 0 : return 0;
1001 : }
1002 :
1003 278 : ret = smb_krb5_princ_component(context, principal, component, &d);
1004 278 : if (ret) {
1005 0 : return ret;
1006 : }
1007 :
1008 278 : p = d.data;
1009 :
1010 278 : len = strlen(string);
1011 278 : if (d.length != len) {
1012 2 : *eq = false;
1013 2 : return 0;
1014 : }
1015 :
1016 276 : if (do_strcasecmp) {
1017 0 : *eq = strncasecmp(p, string, len) == 0;
1018 : } else {
1019 276 : *eq = memcmp(p, string, len) == 0;
1020 : }
1021 276 : return 0;
1022 : #endif
1023 : }
1024 :
1025 119 : static krb5_error_code is_principal_component_equal_ignoring_case(krb5_context context,
1026 : krb5_const_principal principal,
1027 : unsigned int component,
1028 : const char *string,
1029 : bool *eq)
1030 : {
1031 119 : return is_principal_component_equal_impl(context,
1032 : principal,
1033 : component,
1034 : string,
1035 : true /* do_strcasecmp */,
1036 : eq);
1037 : }
1038 :
1039 53186 : static krb5_error_code is_principal_component_equal(krb5_context context,
1040 : krb5_const_principal principal,
1041 : unsigned int component,
1042 : const char *string,
1043 : bool *eq)
1044 : {
1045 53186 : return is_principal_component_equal_impl(context,
1046 : principal,
1047 : component,
1048 : string,
1049 : false /* do_strcasecmp */,
1050 : eq);
1051 : }
1052 :
1053 257 : static krb5_error_code is_kadmin_changepw(krb5_context context,
1054 : krb5_const_principal principal,
1055 : bool *is_changepw)
1056 : {
1057 257 : krb5_error_code ret = 0;
1058 257 : bool eq = false;
1059 :
1060 257 : if (krb5_princ_size(context, principal) != 2) {
1061 0 : *is_changepw = false;
1062 0 : return 0;
1063 : }
1064 :
1065 257 : ret = is_principal_component_equal(context, principal, 0, "kadmin", &eq);
1066 257 : if (ret) {
1067 0 : return ret;
1068 : }
1069 :
1070 257 : if (!eq) {
1071 0 : *is_changepw = false;
1072 0 : return 0;
1073 : }
1074 :
1075 257 : ret = is_principal_component_equal(context, principal, 1, "changepw", &eq);
1076 257 : if (ret) {
1077 0 : return ret;
1078 : }
1079 :
1080 257 : *is_changepw = eq;
1081 257 : return 0;
1082 : }
1083 :
1084 305574 : static krb5_error_code samba_kdc_get_entry_principal(
1085 : krb5_context context,
1086 : struct samba_kdc_db_context *kdc_db_ctx,
1087 : const char *samAccountName,
1088 : enum samba_kdc_ent_type ent_type,
1089 : unsigned flags,
1090 : bool is_kadmin_changepw,
1091 : krb5_const_principal in_princ,
1092 : krb5_principal *out_princ)
1093 : {
1094 305574 : struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
1095 305574 : krb5_error_code code = 0;
1096 305574 : bool canon = flags & (SDB_F_CANON|SDB_F_FORCE_CANON);
1097 :
1098 : /*
1099 : * If we are set to canonicalize, we get back the fixed UPPER
1100 : * case realm, and the real username (ie matching LDAP
1101 : * samAccountName)
1102 : *
1103 : * Otherwise, if we are set to enterprise, we
1104 : * get back the whole principal as-sent
1105 : *
1106 : * Finally, if we are not set to canonicalize, we get back the
1107 : * fixed UPPER case realm, but the as-sent username
1108 : */
1109 :
1110 : /*
1111 : * We need to ensure that the kadmin/changepw principal isn't able to
1112 : * issue krbtgt tickets, even if canonicalization is turned on.
1113 : */
1114 305574 : if (!is_kadmin_changepw) {
1115 305317 : if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT && canon) {
1116 : /*
1117 : * When requested to do so, ensure that both
1118 : * the realm values in the principal are set
1119 : * to the upper case, canonical realm
1120 : */
1121 42622 : code = smb_krb5_make_principal(context,
1122 : out_princ,
1123 : lpcfg_realm(lp_ctx),
1124 : "krbtgt",
1125 : lpcfg_realm(lp_ctx),
1126 : NULL);
1127 42622 : if (code != 0) {
1128 0 : return code;
1129 : }
1130 42622 : smb_krb5_principal_set_type(context,
1131 : *out_princ,
1132 : KRB5_NT_SRV_INST);
1133 :
1134 42622 : return 0;
1135 : }
1136 :
1137 262695 : if ((canon && flags & (SDB_F_FORCE_CANON|SDB_F_FOR_AS_REQ)) ||
1138 6814 : (ent_type == SAMBA_KDC_ENT_TYPE_ANY && in_princ == NULL)) {
1139 : /*
1140 : * SDB_F_CANON maps from the canonicalize flag in the
1141 : * packet, and has a different meaning between AS-REQ
1142 : * and TGS-REQ. We only change the principal in the
1143 : * AS-REQ case.
1144 : *
1145 : * The SDB_F_FORCE_CANON if for new MIT KDC code that
1146 : * wants the canonical name in all lookups, and takes
1147 : * care to canonicalize only when appropriate.
1148 : */
1149 51569 : code = smb_krb5_make_principal(context,
1150 : out_princ,
1151 : lpcfg_realm(lp_ctx),
1152 : samAccountName,
1153 : NULL);
1154 51569 : return code;
1155 : }
1156 : }
1157 :
1158 : /*
1159 : * For a krbtgt entry, this appears to be required regardless of the
1160 : * canonicalize flag from the client.
1161 : */
1162 211383 : code = krb5_copy_principal(context, in_princ, out_princ);
1163 211383 : if (code != 0) {
1164 0 : return code;
1165 : }
1166 :
1167 : /*
1168 : * While we have copied the client principal, tests show that Win2k3
1169 : * returns the 'corrected' realm, not the client-specified realm. This
1170 : * code attempts to replace the client principal's realm with the one
1171 : * we determine from our records
1172 : */
1173 211383 : code = smb_krb5_principal_set_realm(context,
1174 : *out_princ,
1175 : lpcfg_realm(lp_ctx));
1176 :
1177 211383 : return code;
1178 : }
1179 :
1180 : /*
1181 : * Construct an hdb_entry from a directory entry.
1182 : */
1183 306249 : static krb5_error_code samba_kdc_message2entry(krb5_context context,
1184 : struct samba_kdc_db_context *kdc_db_ctx,
1185 : TALLOC_CTX *mem_ctx,
1186 : krb5_const_principal principal,
1187 : enum samba_kdc_ent_type ent_type,
1188 : unsigned flags,
1189 : krb5_kvno kvno,
1190 : struct ldb_dn *realm_dn,
1191 : struct ldb_message *msg,
1192 : struct sdb_entry *entry)
1193 : {
1194 306249 : TALLOC_CTX *tmp_ctx = NULL;
1195 306249 : struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
1196 10240 : uint32_t userAccountControl;
1197 10240 : uint32_t msDS_User_Account_Control_Computed;
1198 306249 : krb5_error_code ret = 0;
1199 306249 : krb5_boolean is_computer = FALSE;
1200 10240 : struct samba_kdc_entry *p;
1201 10240 : NTTIME acct_expiry;
1202 10240 : NTSTATUS status;
1203 306249 : bool protected_user = false;
1204 10240 : struct dom_sid sid;
1205 10240 : uint32_t rid;
1206 306249 : bool is_krbtgt = false;
1207 306249 : bool is_rodc = false;
1208 306249 : bool force_rc4 = lpcfg_kdc_force_enable_rc4_weak_session_keys(lp_ctx);
1209 10240 : struct ldb_message_element *objectclasses;
1210 306249 : struct ldb_val computer_val = data_blob_string_const("computer");
1211 306249 : struct ldb_val gmsa_oc_val = data_blob_string_const("msDS-GroupManagedServiceAccount");
1212 306249 : uint32_t config_default_supported_enctypes = lpcfg_kdc_default_domain_supported_enctypes(lp_ctx);
1213 316489 : uint32_t default_supported_enctypes =
1214 : config_default_supported_enctypes != 0 ?
1215 306249 : config_default_supported_enctypes :
1216 : ENC_RC4_HMAC_MD5 | ENC_HMAC_SHA1_96_AES256_SK;
1217 10240 : uint32_t supported_enctypes
1218 306249 : = ldb_msg_find_attr_as_uint(msg,
1219 : "msDS-SupportedEncryptionTypes",
1220 : default_supported_enctypes);
1221 10240 : uint32_t pa_supported_enctypes;
1222 10240 : uint32_t supported_session_etypes;
1223 306249 : uint32_t available_enctypes = 0;
1224 : /*
1225 : * also legacy enctypes are announced,
1226 : * but effectively restricted by kdc_enctypes
1227 : */
1228 306249 : uint32_t domain_enctypes = ENC_RC4_HMAC_MD5 | ENC_RSA_MD5 | ENC_CRC32;
1229 306249 : uint32_t config_kdc_enctypes = lpcfg_kdc_supported_enctypes(lp_ctx);
1230 316489 : uint32_t kdc_enctypes =
1231 : config_kdc_enctypes != 0 ?
1232 306249 : config_kdc_enctypes :
1233 : ENC_ALL_TYPES;
1234 306249 : const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
1235 :
1236 306249 : const struct authn_kerberos_client_policy *authn_client_policy = NULL;
1237 306249 : const struct authn_server_policy *authn_server_policy = NULL;
1238 10240 : int64_t enforced_tgt_lifetime_raw;
1239 306249 : const bool user2user = (flags & SDB_F_USER2USER_PRINCIPAL);
1240 :
1241 306249 : *entry = (struct sdb_entry) {};
1242 :
1243 306249 : tmp_ctx = talloc_new(mem_ctx);
1244 306249 : if (tmp_ctx == NULL) {
1245 0 : return ENOMEM;
1246 : }
1247 :
1248 306249 : if (supported_enctypes == 0) {
1249 0 : supported_enctypes = default_supported_enctypes;
1250 : }
1251 :
1252 306249 : if (dsdb_functional_level(kdc_db_ctx->samdb) >= DS_DOMAIN_FUNCTION_2008) {
1253 287390 : domain_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
1254 : }
1255 :
1256 306249 : if (ldb_msg_find_element(msg, "msDS-SecondaryKrbTgtNumber")) {
1257 7026 : is_rodc = true;
1258 : }
1259 :
1260 306249 : if (!samAccountName) {
1261 0 : ret = ENOENT;
1262 0 : krb5_set_error_message(context, ret, "samba_kdc_message2entry: no samAccountName present");
1263 0 : goto out;
1264 : }
1265 :
1266 306249 : objectclasses = ldb_msg_find_element(msg, "objectClass");
1267 :
1268 306249 : if (objectclasses && ldb_msg_find_val(objectclasses, &computer_val)) {
1269 40076 : is_computer = TRUE;
1270 : }
1271 :
1272 306249 : p = talloc_zero(tmp_ctx, struct samba_kdc_entry);
1273 306249 : if (!p) {
1274 0 : ret = ENOMEM;
1275 0 : goto out;
1276 : }
1277 :
1278 306249 : if (objectclasses && ldb_msg_find_val(objectclasses, &gmsa_oc_val)) {
1279 37 : p->group_managed_service_account = true;
1280 : }
1281 :
1282 306249 : p->is_rodc = is_rodc;
1283 306249 : p->kdc_db_ctx = kdc_db_ctx;
1284 306249 : p->realm_dn = talloc_reference(p, realm_dn);
1285 306249 : if (!p->realm_dn) {
1286 0 : ret = ENOMEM;
1287 0 : goto out;
1288 : }
1289 :
1290 306249 : talloc_set_destructor(p, samba_kdc_entry_destructor);
1291 :
1292 306249 : entry->skdc_entry = p;
1293 :
1294 306249 : userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
1295 :
1296 10240 : msDS_User_Account_Control_Computed
1297 306249 : = ldb_msg_find_attr_as_uint(msg,
1298 : "msDS-User-Account-Control-Computed",
1299 : UF_ACCOUNTDISABLE);
1300 :
1301 : /*
1302 : * This brings in the lockout flag, block the account if not
1303 : * found. We need the weird UF_ACCOUNTDISABLE check because
1304 : * we do not want to fail open if the value is not returned,
1305 : * but 0 is a valid value (all OK)
1306 : */
1307 306249 : if (msDS_User_Account_Control_Computed == UF_ACCOUNTDISABLE) {
1308 0 : ret = EINVAL;
1309 0 : krb5_set_error_message(context, ret, "samba_kdc_message2entry: "
1310 : "no msDS-User-Account-Control-Computed present");
1311 0 : goto out;
1312 : } else {
1313 306249 : userAccountControl |= msDS_User_Account_Control_Computed;
1314 : }
1315 :
1316 306249 : if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT) {
1317 176383 : p->is_krbtgt = true;
1318 : }
1319 :
1320 : /* First try and figure out the flags based on the userAccountControl */
1321 306249 : entry->flags = uf2SDBFlags(context, userAccountControl, ent_type);
1322 :
1323 : /*
1324 : * Take control of the returned principal here, rather than
1325 : * allowing the Heimdal code to do it as we have specific
1326 : * behaviour around the forced realm to honour
1327 : */
1328 306249 : entry->flags.force_canonicalize = true;
1329 :
1330 : /*
1331 : * Windows 2008 seems to enforce this (very sensible) rule by
1332 : * default - don't allow offline attacks on a user's password
1333 : * by asking for a ticket to them as a service (encrypted with
1334 : * their probably pathetically insecure password)
1335 : *
1336 : * But user2user avoids using the keys based on the password,
1337 : * so we can allow it.
1338 : */
1339 :
1340 306249 : if (entry->flags.server && !user2user
1341 306210 : && lpcfg_parm_bool(lp_ctx, NULL, "kdc", "require spn for service", true)) {
1342 306210 : if (!is_computer && !ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL)) {
1343 90722 : entry->flags.server = 0;
1344 : }
1345 : }
1346 :
1347 : /*
1348 : * We restrict a 3-part SPN ending in my domain/realm to full
1349 : * domain controllers.
1350 : *
1351 : * This avoids any cases where (eg) a demoted DC still has
1352 : * these more restricted SPNs.
1353 : */
1354 306249 : if (krb5_princ_size(context, principal) > 2) {
1355 28 : char *third_part = NULL;
1356 0 : bool is_our_realm;
1357 0 : bool is_dc;
1358 :
1359 28 : ret = smb_krb5_principal_get_comp_string(tmp_ctx,
1360 : context,
1361 : principal,
1362 : 2,
1363 : &third_part);
1364 28 : if (ret) {
1365 0 : krb5_set_error_message(context, ret, "smb_krb5_principal_get_comp_string: out of memory");
1366 0 : goto out;
1367 : }
1368 :
1369 28 : is_our_realm = lpcfg_is_my_domain_or_realm(lp_ctx,
1370 : third_part);
1371 28 : is_dc = userAccountControl &
1372 : (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT);
1373 28 : if (is_our_realm && !is_dc) {
1374 3 : entry->flags.server = 0;
1375 : }
1376 : }
1377 : /*
1378 : * To give the correct type of error to the client, we must
1379 : * not just return the entry without .server set, we must
1380 : * pretend the principal does not exist. Otherwise we may
1381 : * return ERR_POLICY instead of
1382 : * KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN
1383 : */
1384 306249 : if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER && entry->flags.server == 0) {
1385 675 : ret = SDB_ERR_NOENTRY;
1386 675 : krb5_set_error_message(context, ret, "samba_kdc_message2entry: no servicePrincipalName present for this server, refusing with no-such-entry");
1387 675 : goto out;
1388 : }
1389 305574 : if (flags & SDB_F_ADMIN_DATA) {
1390 : /* These (created_by, modified_by) parts of the entry are not relevant for Samba4's use
1391 : * of the Heimdal KDC. They are stored in the traditional
1392 : * DB for audit purposes, and still form part of the structure
1393 : * we must return */
1394 :
1395 : /* use 'whenCreated' */
1396 264 : entry->created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
1397 : /* use 'kadmin' for now (needed by mit_samba) */
1398 :
1399 264 : ret = smb_krb5_make_principal(context,
1400 : &entry->created_by.principal,
1401 : lpcfg_realm(lp_ctx), "kadmin", NULL);
1402 264 : if (ret) {
1403 0 : krb5_clear_error_message(context);
1404 0 : goto out;
1405 : }
1406 :
1407 264 : entry->modified_by = calloc(1, sizeof(struct sdb_event));
1408 264 : if (entry->modified_by == NULL) {
1409 0 : ret = ENOMEM;
1410 0 : krb5_set_error_message(context, ret, "calloc: out of memory");
1411 0 : goto out;
1412 : }
1413 :
1414 : /* use 'whenChanged' */
1415 264 : entry->modified_by->time = ldb_msg_find_krb5time_ldap_time(msg, "whenChanged", 0);
1416 : /* use 'kadmin' for now (needed by mit_samba) */
1417 264 : ret = smb_krb5_make_principal(context,
1418 264 : &entry->modified_by->principal,
1419 : lpcfg_realm(lp_ctx), "kadmin", NULL);
1420 264 : if (ret) {
1421 0 : krb5_clear_error_message(context);
1422 0 : goto out;
1423 : }
1424 : }
1425 :
1426 :
1427 : /* The lack of password controls etc applies to krbtgt by
1428 : * virtue of being that particular RID */
1429 305574 : ret = samdb_result_dom_sid_buf(msg, "objectSid", &sid);
1430 305574 : if (ret) {
1431 0 : goto out;
1432 : }
1433 305574 : status = dom_sid_split_rid(NULL, &sid, NULL, &rid);
1434 305574 : if (!NT_STATUS_IS_OK(status)) {
1435 0 : ret = EINVAL;
1436 0 : goto out;
1437 : }
1438 :
1439 305574 : if (rid == DOMAIN_RID_KRBTGT) {
1440 169624 : char *realm = NULL;
1441 :
1442 169624 : entry->valid_end = NULL;
1443 169624 : entry->pw_end = NULL;
1444 :
1445 169624 : entry->flags.invalid = 0;
1446 169624 : entry->flags.server = 1;
1447 :
1448 169624 : realm = smb_krb5_principal_get_realm(
1449 : tmp_ctx, context, principal);
1450 169624 : if (realm == NULL) {
1451 0 : ret = ENOMEM;
1452 0 : goto out;
1453 : }
1454 :
1455 : /* Don't mark all requests for the krbtgt/realm as
1456 : * 'change password', as otherwise we could get into
1457 : * trouble, and not enforce the password expiry.
1458 : * Instead, only do it when request is for the kpasswd service */
1459 169624 : if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
1460 257 : bool is_changepw = false;
1461 :
1462 257 : ret = is_kadmin_changepw(context, principal, &is_changepw);
1463 257 : if (ret) {
1464 0 : goto out;
1465 : }
1466 :
1467 257 : if (is_changepw && lpcfg_is_my_domain_or_realm(lp_ctx, realm)) {
1468 257 : entry->flags.change_pw = 1;
1469 : }
1470 : }
1471 :
1472 169624 : TALLOC_FREE(realm);
1473 :
1474 169624 : entry->flags.client = 0;
1475 169624 : entry->flags.forwardable = 1;
1476 169624 : entry->flags.ok_as_delegate = 1;
1477 135950 : } else if (is_rodc) {
1478 : /* The RODC krbtgt account is like the main krbtgt,
1479 : * but it does not have a changepw or kadmin
1480 : * service */
1481 :
1482 7026 : entry->valid_end = NULL;
1483 7026 : entry->pw_end = NULL;
1484 :
1485 : /* Also don't allow the RODC krbtgt to be a client (it should not be needed) */
1486 7026 : entry->flags.client = 0;
1487 7026 : entry->flags.invalid = 0;
1488 7026 : entry->flags.server = 1;
1489 :
1490 7026 : entry->flags.client = 0;
1491 7026 : entry->flags.forwardable = 1;
1492 7026 : entry->flags.ok_as_delegate = 0;
1493 128924 : } else if (entry->flags.server && ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
1494 : /* The account/password expiry only applies when the account is used as a
1495 : * client (ie password login), not when used as a server */
1496 :
1497 : /* Make very well sure we don't use this for a client,
1498 : * it could bypass the password restrictions */
1499 27320 : entry->flags.client = 0;
1500 :
1501 27320 : entry->valid_end = NULL;
1502 27320 : entry->pw_end = NULL;
1503 :
1504 : } else {
1505 3448 : NTTIME must_change_time
1506 101604 : = samdb_result_nttime(msg,
1507 : "msDS-UserPasswordExpiryTimeComputed",
1508 : 0);
1509 101604 : if (must_change_time == 0x7FFFFFFFFFFFFFFFULL) {
1510 17675 : entry->pw_end = NULL;
1511 : } else {
1512 83929 : entry->pw_end = malloc(sizeof(*entry->pw_end));
1513 83929 : if (entry->pw_end == NULL) {
1514 0 : ret = ENOMEM;
1515 0 : goto out;
1516 : }
1517 83929 : *entry->pw_end = nt_time_to_unix(must_change_time);
1518 : }
1519 :
1520 101604 : acct_expiry = samdb_result_account_expires(msg);
1521 101604 : if (acct_expiry == 0x7FFFFFFFFFFFFFFFULL) {
1522 101604 : entry->valid_end = NULL;
1523 : } else {
1524 0 : entry->valid_end = malloc(sizeof(*entry->valid_end));
1525 0 : if (entry->valid_end == NULL) {
1526 0 : ret = ENOMEM;
1527 0 : goto out;
1528 : }
1529 0 : *entry->valid_end = nt_time_to_unix(acct_expiry);
1530 : }
1531 : }
1532 :
1533 315814 : ret = samba_kdc_get_entry_principal(context,
1534 : kdc_db_ctx,
1535 : samAccountName,
1536 : ent_type,
1537 : flags,
1538 305574 : entry->flags.change_pw,
1539 : principal,
1540 : &entry->principal);
1541 305574 : if (ret != 0) {
1542 0 : krb5_clear_error_message(context);
1543 0 : goto out;
1544 : }
1545 :
1546 305574 : entry->valid_start = NULL;
1547 :
1548 305574 : entry->max_life = malloc(sizeof(*entry->max_life));
1549 305574 : if (entry->max_life == NULL) {
1550 0 : ret = ENOMEM;
1551 0 : goto out;
1552 : }
1553 :
1554 305574 : if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
1555 27577 : *entry->max_life = kdc_db_ctx->policy.svc_tkt_lifetime;
1556 277997 : } else if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT || ent_type == SAMBA_KDC_ENT_TYPE_CLIENT) {
1557 277871 : *entry->max_life = kdc_db_ctx->policy.usr_tkt_lifetime;
1558 : } else {
1559 126 : *entry->max_life = MIN(kdc_db_ctx->policy.svc_tkt_lifetime,
1560 : kdc_db_ctx->policy.usr_tkt_lifetime);
1561 : }
1562 :
1563 305574 : if (entry->flags.change_pw) {
1564 : /* Limit lifetime of kpasswd tickets to two minutes or less. */
1565 257 : *entry->max_life = MIN(*entry->max_life, CHANGEPW_LIFETIME);
1566 : }
1567 :
1568 305574 : entry->max_renew = malloc(sizeof(*entry->max_renew));
1569 305574 : if (entry->max_renew == NULL) {
1570 0 : ret = ENOMEM;
1571 0 : goto out;
1572 : }
1573 :
1574 305574 : *entry->max_renew = kdc_db_ctx->policy.renewal_lifetime;
1575 :
1576 : /*
1577 : * A principal acting as a client that is not being looked up as the
1578 : * principal of an armor ticket may have an authentication policy apply
1579 : * to it.
1580 : *
1581 : * We won’t get an authentication policy for the client of an S4U2Self
1582 : * or S4U2Proxy request. Those clients are looked up with
1583 : * SDB_F_FOR_TGS_REQ instead of with SDB_F_FOR_AS_REQ.
1584 : */
1585 305574 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT &&
1586 101488 : (flags & SDB_F_FOR_AS_REQ) &&
1587 48894 : !(flags & SDB_F_ARMOR_PRINCIPAL))
1588 : {
1589 50202 : ret = authn_policy_kerberos_client(kdc_db_ctx->samdb, tmp_ctx, msg,
1590 : &authn_client_policy);
1591 50202 : if (ret) {
1592 0 : goto out;
1593 : }
1594 : }
1595 :
1596 : /*
1597 : * A principal acting as a server may have an authentication policy
1598 : * apply to it.
1599 : */
1600 305574 : if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
1601 27577 : ret = authn_policy_server(kdc_db_ctx->samdb, tmp_ctx, msg,
1602 : &authn_server_policy);
1603 27577 : if (ret) {
1604 0 : goto out;
1605 : }
1606 : }
1607 :
1608 305574 : enforced_tgt_lifetime_raw = authn_policy_enforced_tgt_lifetime_raw(authn_client_policy);
1609 305574 : if (enforced_tgt_lifetime_raw != 0) {
1610 30 : int64_t lifetime_secs = enforced_tgt_lifetime_raw;
1611 :
1612 30 : lifetime_secs /= INT64_C(1000) * 1000 * 10;
1613 30 : lifetime_secs = MIN(lifetime_secs, INT_MAX);
1614 30 : lifetime_secs = MAX(lifetime_secs, INT_MIN);
1615 :
1616 : /*
1617 : * Set both lifetime and renewal time based only on the
1618 : * configured maximum lifetime — not on the configured renewal
1619 : * time. Yes, this is what Windows does.
1620 : */
1621 30 : lifetime_secs = MIN(*entry->max_life, lifetime_secs);
1622 30 : *entry->max_life = lifetime_secs;
1623 30 : *entry->max_renew = lifetime_secs;
1624 : }
1625 :
1626 305574 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT && (flags & SDB_F_FOR_AS_REQ)) {
1627 1776 : int result;
1628 50670 : const struct auth_user_info_dc *user_info_dc = NULL;
1629 : /*
1630 : * These protections only apply to clients, so servers in the
1631 : * Protected Users group may still have service tickets to them
1632 : * encrypted with RC4. For accounts looked up as servers, note
1633 : * that 'msg' does not contain the 'memberOf' attribute for
1634 : * determining whether the account is a member of Protected
1635 : * Users.
1636 : *
1637 : * Additionally, Microsoft advises that accounts for services
1638 : * and computers should never be members of Protected Users, or
1639 : * they may fail to authenticate.
1640 : */
1641 50670 : ret = samba_kdc_get_user_info_from_db(tmp_ctx,
1642 : kdc_db_ctx->samdb,
1643 : p,
1644 : msg,
1645 : &user_info_dc);
1646 50670 : if (ret) {
1647 0 : goto out;
1648 : }
1649 :
1650 52446 : result = dsdb_is_protected_user(kdc_db_ctx->samdb,
1651 50670 : user_info_dc->sids,
1652 50670 : user_info_dc->num_sids);
1653 50670 : if (result == -1) {
1654 0 : ret = EINVAL;
1655 0 : goto out;
1656 : }
1657 :
1658 50670 : protected_user = result;
1659 :
1660 50670 : if (protected_user) {
1661 57 : entry->flags.forwardable = 0;
1662 57 : entry->flags.proxiable = 0;
1663 :
1664 57 : if (enforced_tgt_lifetime_raw == 0) {
1665 : /*
1666 : * If a TGT lifetime hasn’t been set, Protected
1667 : * Users enforces a four hour TGT lifetime.
1668 : */
1669 52 : *entry->max_life = MIN(*entry->max_life, 4 * 60 * 60);
1670 52 : *entry->max_renew = MIN(*entry->max_renew, 4 * 60 * 60);
1671 : }
1672 : }
1673 : }
1674 :
1675 305574 : if (rid == DOMAIN_RID_KRBTGT || is_rodc) {
1676 6162 : bool enable_fast;
1677 :
1678 176650 : is_krbtgt = true;
1679 :
1680 : /*
1681 : * KDCs (and KDCs on RODCs)
1682 : * ignore msDS-SupportedEncryptionTypes completely
1683 : * but support all supported enctypes by the domain.
1684 : */
1685 176650 : supported_enctypes = domain_enctypes;
1686 :
1687 176650 : enable_fast = lpcfg_kdc_enable_fast(kdc_db_ctx->lp_ctx);
1688 176650 : if (enable_fast) {
1689 164908 : supported_enctypes |= ENC_FAST_SUPPORTED;
1690 : }
1691 :
1692 176650 : supported_enctypes |= ENC_CLAIMS_SUPPORTED;
1693 176650 : supported_enctypes |= ENC_COMPOUND_IDENTITY_SUPPORTED;
1694 :
1695 : /*
1696 : * Resource SID compression is enabled implicitly, unless
1697 : * disabled in msDS-SupportedEncryptionTypes.
1698 : */
1699 :
1700 128924 : } else if (userAccountControl & (UF_PARTIAL_SECRETS_ACCOUNT|UF_SERVER_TRUST_ACCOUNT)) {
1701 : /*
1702 : * DCs and RODCs computer accounts take
1703 : * msDS-SupportedEncryptionTypes unmodified, but
1704 : * force all enctypes supported by the domain.
1705 : */
1706 29950 : supported_enctypes |= domain_enctypes;
1707 :
1708 98974 : } else if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT ||
1709 3119 : (ent_type == SAMBA_KDC_ENT_TYPE_ANY)) {
1710 : /*
1711 : * for AS-REQ the client chooses the enc types it
1712 : * supports, and this will vary between computers a
1713 : * user logs in from. Therefore, so that we accept any
1714 : * of the client's keys for decrypting padata,
1715 : * supported_enctypes should not restrict etype usage.
1716 : *
1717 : * likewise for 'any' return as much as is supported,
1718 : * to export into a keytab.
1719 : */
1720 91829 : supported_enctypes |= ENC_ALL_TYPES;
1721 : }
1722 :
1723 : /* If UF_USE_DES_KEY_ONLY has been set, then don't allow use of the newer enc types */
1724 305574 : if (userAccountControl & UF_USE_DES_KEY_ONLY) {
1725 0 : supported_enctypes &= ~ENC_ALL_TYPES;
1726 : }
1727 :
1728 305574 : if (protected_user) {
1729 57 : supported_enctypes &= ~ENC_RC4_HMAC_MD5;
1730 : }
1731 :
1732 305574 : pa_supported_enctypes = supported_enctypes;
1733 305574 : supported_session_etypes = supported_enctypes;
1734 305574 : if (supported_session_etypes & ENC_HMAC_SHA1_96_AES256_SK) {
1735 96775 : supported_session_etypes |= ENC_HMAC_SHA1_96_AES256;
1736 96775 : supported_session_etypes |= ENC_HMAC_SHA1_96_AES128;
1737 : }
1738 305574 : if (force_rc4) {
1739 26531 : supported_session_etypes |= ENC_RC4_HMAC_MD5;
1740 : }
1741 : /*
1742 : * now that we remembered what to announce in pa_supported_enctypes
1743 : * and normalized ENC_HMAC_SHA1_96_AES256_SK, we restrict the
1744 : * rest to the enc types the local kdc supports.
1745 : */
1746 305574 : supported_enctypes &= kdc_enctypes;
1747 305574 : supported_session_etypes &= kdc_enctypes;
1748 :
1749 : /* Get keys from the db */
1750 305574 : ret = samba_kdc_message2entry_keys(context, p,
1751 : kdc_db_ctx->samdb, msg,
1752 : is_krbtgt, is_rodc,
1753 : userAccountControl,
1754 : ent_type, flags, kvno, entry,
1755 : supported_enctypes,
1756 : &available_enctypes);
1757 305574 : if (ret) {
1758 : /* Could be bogus data in the entry, or out of memory */
1759 0 : goto out;
1760 : }
1761 :
1762 : /*
1763 : * If we only have a nthash stored,
1764 : * but a better session key would be
1765 : * available, we fallback to fetching the
1766 : * RC4_HMAC_MD5, which implicitly also
1767 : * would allow an RC4_HMAC_MD5 session key.
1768 : * But only if the kdc actually supports
1769 : * RC4_HMAC_MD5.
1770 : */
1771 305574 : if (available_enctypes == 0 &&
1772 2666 : (supported_enctypes & ENC_RC4_HMAC_MD5) == 0 &&
1773 984 : (supported_enctypes & ~ENC_RC4_HMAC_MD5) != 0 &&
1774 624 : (kdc_enctypes & ENC_RC4_HMAC_MD5) != 0)
1775 : {
1776 624 : supported_enctypes = ENC_RC4_HMAC_MD5;
1777 624 : ret = samba_kdc_message2entry_keys(context, p,
1778 : kdc_db_ctx->samdb, msg,
1779 : is_krbtgt, is_rodc,
1780 : userAccountControl,
1781 : ent_type, flags, kvno, entry,
1782 : supported_enctypes,
1783 : &available_enctypes);
1784 624 : if (ret) {
1785 : /* Could be bogus data in the entry, or out of memory */
1786 0 : goto out;
1787 : }
1788 : }
1789 :
1790 : /*
1791 : * We need to support all session keys enctypes for
1792 : * all keys we provide
1793 : */
1794 305574 : supported_session_etypes |= available_enctypes;
1795 :
1796 305574 : ret = sdb_entry_set_etypes(entry);
1797 305574 : if (ret) {
1798 0 : goto out;
1799 : }
1800 :
1801 305574 : if (entry->flags.server) {
1802 222550 : bool add_aes256 =
1803 222550 : supported_session_etypes & KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96;
1804 222550 : bool add_aes128 =
1805 222550 : supported_session_etypes & KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96;
1806 222550 : bool add_rc4 =
1807 222550 : supported_session_etypes & ENC_RC4_HMAC_MD5;
1808 222550 : ret = sdb_entry_set_session_etypes(entry,
1809 : add_aes256,
1810 : add_aes128,
1811 : add_rc4);
1812 222550 : if (ret) {
1813 0 : goto out;
1814 : }
1815 : }
1816 :
1817 305574 : if (entry->keys.len != 0) {
1818 : /*
1819 : * FIXME: Currently limited to Heimdal so as not to
1820 : * break MIT KDCs, for which no fix is available.
1821 : */
1822 : #ifdef SAMBA4_USES_HEIMDAL
1823 303298 : if (is_krbtgt) {
1824 : /*
1825 : * The krbtgt account, having no reason to
1826 : * issue tickets encrypted in weaker keys,
1827 : * shall only make available its strongest
1828 : * key. All weaker keys are stripped out. This
1829 : * makes it impossible for an RC4-encrypted
1830 : * TGT to be accepted when AES KDC keys exist.
1831 : *
1832 : * This controls the ticket key and so the PAC
1833 : * signature algorithms indirectly, preventing
1834 : * a weak KDC checksum from being accepted
1835 : * when we verify the signatures for an
1836 : * S4U2Proxy evidence ticket. As such, this is
1837 : * indispensable for addressing
1838 : * CVE-2022-37966.
1839 : *
1840 : * Being strict here also provides protection
1841 : * against possible future attacks on weak
1842 : * keys.
1843 : */
1844 :
1845 : /*
1846 : * The krbtgt account is never a Group Managed Service
1847 : * Account, but a similar system might well be
1848 : * implemented as a means of having the krbtgt’s keys
1849 : * roll over automatically. In that case, thought might
1850 : * be given as to how this security measure — of
1851 : * stripping out weaker keys — would interact with key
1852 : * management.
1853 : */
1854 :
1855 176493 : entry->keys.len = 1;
1856 176493 : if (entry->etypes != NULL) {
1857 176493 : entry->etypes->len = MIN(entry->etypes->len, 1);
1858 : }
1859 176493 : entry->old_keys.len = MIN(entry->old_keys.len, 1);
1860 176493 : entry->older_keys.len = MIN(entry->older_keys.len, 1);
1861 : }
1862 : #endif
1863 2042 : } else if (kdc_db_ctx->rodc) {
1864 : /*
1865 : * We are on an RODC, but don't have keys for this
1866 : * account. Signal this to the caller
1867 : */
1868 1670 : auth_sam_trigger_repl_secret(kdc_db_ctx,
1869 : kdc_db_ctx->msg_ctx,
1870 : kdc_db_ctx->ev_ctx,
1871 : msg->dn);
1872 1670 : ret = SDB_ERR_NOT_FOUND_HERE;
1873 1670 : goto out;
1874 : } else {
1875 : /*
1876 : * oh, no password. Apparently (comment in
1877 : * hdb-ldap.c) this violates the ASN.1, but this
1878 : * allows an entry with no keys (yet).
1879 : */
1880 10240 : }
1881 :
1882 303904 : p->msg = talloc_steal(p, msg);
1883 303904 : p->supported_enctypes = pa_supported_enctypes;
1884 :
1885 303904 : p->client_policy = talloc_steal(p, authn_client_policy);
1886 303904 : p->server_policy = talloc_steal(p, authn_server_policy);
1887 :
1888 303904 : talloc_steal(kdc_db_ctx, p);
1889 :
1890 306249 : out:
1891 306249 : if (ret != 0) {
1892 : /* This doesn't free ent itself, that is for the eventual caller to do */
1893 2345 : sdb_entry_free(entry);
1894 : }
1895 :
1896 306249 : talloc_free(tmp_ctx);
1897 306249 : return ret;
1898 : }
1899 :
1900 : struct samba_kdc_trust_keys {
1901 : struct sdb_keys *skeys;
1902 : uint32_t kvno;
1903 : uint32_t *returned_kvno;
1904 : uint32_t supported_enctypes;
1905 : uint32_t *available_enctypes;
1906 : krb5_const_principal salt_principal;
1907 : const struct AuthenticationInformationArray *auth_array;
1908 : };
1909 :
1910 2105 : static krb5_error_code samba_kdc_fill_trust_keys(krb5_context context,
1911 : struct samba_kdc_trust_keys *p)
1912 : {
1913 : /*
1914 : * Make sure we'll never reveal DES keys
1915 : */
1916 2105 : uint32_t supported_enctypes = p->supported_enctypes &= ~(ENC_CRC32 | ENC_RSA_MD5);
1917 2105 : uint32_t _available_enctypes = 0;
1918 2105 : uint32_t *available_enctypes = p->available_enctypes;
1919 2105 : uint32_t _returned_kvno = 0;
1920 2105 : uint32_t *returned_kvno = p->returned_kvno;
1921 2105 : TALLOC_CTX *frame = talloc_stackframe();
1922 2105 : const struct AuthenticationInformationArray *aa = p->auth_array;
1923 2105 : DATA_BLOB password_utf16 = { .length = 0, };
1924 2105 : DATA_BLOB password_utf8 = { .length = 0, };
1925 2105 : struct samr_Password _password_hash = { .hash = { 0,}, };
1926 2105 : const struct samr_Password *password_hash = NULL;
1927 2105 : uint32_t allocated_keys = 0;
1928 0 : uint32_t i;
1929 0 : int ret;
1930 :
1931 2105 : if (available_enctypes == NULL) {
1932 0 : available_enctypes = &_available_enctypes;
1933 : }
1934 :
1935 2105 : *available_enctypes = 0;
1936 :
1937 2105 : if (returned_kvno == NULL) {
1938 0 : returned_kvno = &_returned_kvno;
1939 : }
1940 :
1941 2105 : *returned_kvno = p->kvno;
1942 :
1943 2105 : for (i=0; i < aa->count; i++) {
1944 2105 : if (aa->array[i].AuthType == TRUST_AUTH_TYPE_CLEAR) {
1945 2105 : const struct AuthInfoClear *clear =
1946 2105 : &aa->array[i].AuthInfo.clear;
1947 0 : bool ok;
1948 :
1949 2105 : password_utf16 = data_blob_const(clear->password,
1950 2105 : clear->size);
1951 2105 : if (password_utf16.length == 0) {
1952 0 : break;
1953 : }
1954 :
1955 2105 : if (supported_enctypes & ENC_RC4_HMAC_MD5) {
1956 102 : mdfour(_password_hash.hash,
1957 102 : password_utf16.data,
1958 102 : password_utf16.length);
1959 102 : if (password_hash == NULL) {
1960 102 : allocated_keys += 1;
1961 : }
1962 102 : password_hash = &_password_hash;
1963 : }
1964 :
1965 2105 : if (!(supported_enctypes & (ENC_HMAC_SHA1_96_AES128|ENC_HMAC_SHA1_96_AES256))) {
1966 102 : break;
1967 : }
1968 :
1969 2003 : ok = convert_string_talloc(frame,
1970 : CH_UTF16MUNGED, CH_UTF8,
1971 2003 : password_utf16.data,
1972 : password_utf16.length,
1973 : &password_utf8.data,
1974 : &password_utf8.length);
1975 2003 : if (!ok) {
1976 0 : krb5_clear_error_message(context);
1977 0 : ret = ENOMEM;
1978 0 : goto fail;
1979 : }
1980 :
1981 2003 : if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
1982 131 : allocated_keys += 1;
1983 : }
1984 2003 : if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
1985 2003 : allocated_keys += 1;
1986 : }
1987 2003 : break;
1988 0 : } else if (aa->array[i].AuthType == TRUST_AUTH_TYPE_NT4OWF) {
1989 0 : const struct AuthInfoNT4Owf *nt4owf =
1990 0 : &aa->array[i].AuthInfo.nt4owf;
1991 :
1992 0 : if (supported_enctypes & ENC_RC4_HMAC_MD5) {
1993 0 : password_hash = &nt4owf->password;
1994 0 : allocated_keys += 1;
1995 : }
1996 : }
1997 : }
1998 :
1999 2105 : allocated_keys = MAX(1, allocated_keys);
2000 :
2001 : /* allocate space to decode into */
2002 2105 : p->skeys->len = 0;
2003 2105 : p->skeys->val = calloc(allocated_keys, sizeof(struct sdb_key));
2004 2105 : if (p->skeys->val == NULL) {
2005 0 : krb5_clear_error_message(context);
2006 0 : ret = ENOMEM;
2007 0 : goto fail;
2008 : }
2009 :
2010 2105 : if (password_utf8.length != 0) {
2011 2003 : struct sdb_key key = {};
2012 0 : krb5_data salt;
2013 0 : krb5_data cleartext_data;
2014 :
2015 2003 : cleartext_data.data = discard_const_p(char, password_utf8.data);
2016 2003 : cleartext_data.length = password_utf8.length;
2017 :
2018 2003 : ret = smb_krb5_get_pw_salt(context,
2019 : p->salt_principal,
2020 : &salt);
2021 2003 : if (ret != 0) {
2022 0 : goto fail;
2023 : }
2024 :
2025 2003 : if (supported_enctypes & ENC_HMAC_SHA1_96_AES256) {
2026 2003 : key.salt = calloc(1, sizeof(*key.salt));
2027 2003 : if (key.salt == NULL) {
2028 0 : smb_krb5_free_data_contents(context, &salt);
2029 0 : ret = ENOMEM;
2030 0 : goto fail;
2031 : }
2032 :
2033 2003 : key.salt->type = KRB5_PW_SALT;
2034 :
2035 2003 : ret = smb_krb5_copy_data_contents(&key.salt->salt,
2036 2003 : salt.data,
2037 0 : salt.length);
2038 2003 : if (ret) {
2039 0 : *key.salt = (struct sdb_salt) {};
2040 0 : sdb_key_free(&key);
2041 0 : smb_krb5_free_data_contents(context, &salt);
2042 0 : goto fail;
2043 : }
2044 :
2045 2003 : ret = smb_krb5_create_key_from_string(context,
2046 : p->salt_principal,
2047 : &salt,
2048 : &cleartext_data,
2049 : ENCTYPE_AES256_CTS_HMAC_SHA1_96,
2050 : &key.key);
2051 2003 : if (ret == 0) {
2052 2003 : p->skeys->val[p->skeys->len++] = key;
2053 2003 : *available_enctypes |= ENC_HMAC_SHA1_96_AES256;
2054 0 : } else if (ret == KRB5_PROG_ETYPE_NOSUPP) {
2055 0 : DBG_NOTICE("Unsupported keytype ignored - type %u\n",
2056 : ENCTYPE_AES256_CTS_HMAC_SHA1_96);
2057 0 : ZERO_STRUCT(key.key);
2058 0 : sdb_key_free(&key);
2059 0 : ret = 0;
2060 : }
2061 2003 : if (ret != 0) {
2062 0 : ZERO_STRUCT(key.key);
2063 0 : sdb_key_free(&key);
2064 0 : smb_krb5_free_data_contents(context, &salt);
2065 0 : goto fail;
2066 : }
2067 : }
2068 :
2069 2003 : if (supported_enctypes & ENC_HMAC_SHA1_96_AES128) {
2070 131 : key.salt = calloc(1, sizeof(*key.salt));
2071 131 : if (key.salt == NULL) {
2072 0 : smb_krb5_free_data_contents(context, &salt);
2073 0 : ret = ENOMEM;
2074 0 : goto fail;
2075 : }
2076 :
2077 131 : key.salt->type = KRB5_PW_SALT;
2078 :
2079 131 : ret = smb_krb5_copy_data_contents(&key.salt->salt,
2080 131 : salt.data,
2081 0 : salt.length);
2082 131 : if (ret) {
2083 0 : *key.salt = (struct sdb_salt) {};
2084 0 : sdb_key_free(&key);
2085 0 : smb_krb5_free_data_contents(context, &salt);
2086 0 : goto fail;
2087 : }
2088 :
2089 131 : ret = smb_krb5_create_key_from_string(context,
2090 : p->salt_principal,
2091 : &salt,
2092 : &cleartext_data,
2093 : ENCTYPE_AES128_CTS_HMAC_SHA1_96,
2094 : &key.key);
2095 131 : if (ret == 0) {
2096 131 : p->skeys->val[p->skeys->len++] = key;
2097 131 : *available_enctypes |= ENC_HMAC_SHA1_96_AES128;
2098 0 : } else if (ret == KRB5_PROG_ETYPE_NOSUPP) {
2099 0 : DBG_NOTICE("Unsupported keytype ignored - type %u\n",
2100 : ENCTYPE_AES128_CTS_HMAC_SHA1_96);
2101 0 : ZERO_STRUCT(key.key);
2102 0 : sdb_key_free(&key);
2103 0 : ret = 0;
2104 : }
2105 131 : if (ret != 0) {
2106 0 : ZERO_STRUCT(key.key);
2107 0 : sdb_key_free(&key);
2108 0 : smb_krb5_free_data_contents(context, &salt);
2109 0 : goto fail;
2110 : }
2111 : }
2112 :
2113 2003 : smb_krb5_free_data_contents(context, &salt);
2114 : }
2115 :
2116 2105 : if (password_hash != NULL) {
2117 102 : struct sdb_key key = {};
2118 :
2119 102 : ret = smb_krb5_keyblock_init_contents(context,
2120 : ENCTYPE_ARCFOUR_HMAC,
2121 102 : password_hash->hash,
2122 : sizeof(password_hash->hash),
2123 : &key.key);
2124 102 : if (ret == 0) {
2125 102 : p->skeys->val[p->skeys->len++] = key;
2126 :
2127 102 : *available_enctypes |= ENC_RC4_HMAC_MD5;
2128 0 : } else if (ret == KRB5_PROG_ETYPE_NOSUPP) {
2129 0 : DEBUG(2,("Unsupported keytype ignored - type %u\n",
2130 : ENCTYPE_ARCFOUR_HMAC));
2131 0 : ZERO_STRUCT(key.key);
2132 0 : sdb_key_free(&key);
2133 0 : ret = 0;
2134 : }
2135 102 : if (ret != 0) {
2136 0 : ZERO_STRUCT(key.key);
2137 0 : sdb_key_free(&key);
2138 0 : goto fail;
2139 : }
2140 : }
2141 :
2142 2105 : samba_kdc_sort_keys(p->skeys);
2143 :
2144 2105 : return 0;
2145 0 : fail:
2146 0 : sdb_keys_free(p->skeys);
2147 0 : TALLOC_FREE(frame);
2148 0 : return ret;
2149 : }
2150 :
2151 : /*
2152 : * Construct an hdb_entry from a directory entry.
2153 : * The kvno is what the remote client asked for
2154 : */
2155 2107 : static krb5_error_code samba_kdc_trust_message2entry(krb5_context context,
2156 : struct samba_kdc_db_context *kdc_db_ctx,
2157 : TALLOC_CTX *mem_ctx,
2158 : enum trust_direction direction,
2159 : struct ldb_dn *realm_dn,
2160 : unsigned flags,
2161 : uint32_t kvno,
2162 : struct ldb_message *msg,
2163 : struct sdb_entry *entry)
2164 : {
2165 2107 : TALLOC_CTX *tmp_ctx = NULL;
2166 2107 : struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
2167 2107 : const char *our_realm = lpcfg_realm(lp_ctx);
2168 2107 : char *partner_realm = NULL;
2169 2107 : const char *realm = NULL;
2170 2107 : const char *krbtgt_realm = NULL;
2171 0 : const struct ldb_val *password_val;
2172 0 : struct trustAuthInOutBlob password_blob;
2173 0 : struct samba_kdc_entry *p;
2174 2107 : bool use_previous = false;
2175 2107 : bool include_previous = false;
2176 0 : uint32_t current_kvno;
2177 0 : uint32_t previous_kvno;
2178 2107 : struct samba_kdc_trust_keys current_keys = {};
2179 2107 : struct samba_kdc_trust_keys previous_keys = {};
2180 0 : enum ndr_err_code ndr_err;
2181 0 : int ret;
2182 0 : unsigned int i;
2183 0 : struct timeval tv;
2184 0 : NTTIME an_hour_ago;
2185 2107 : bool prefer_current = false;
2186 2107 : bool force_rc4 = lpcfg_kdc_force_enable_rc4_weak_session_keys(lp_ctx);
2187 2107 : uint32_t supported_enctypes = ENC_RC4_HMAC_MD5;
2188 0 : uint32_t pa_supported_enctypes;
2189 0 : uint32_t supported_session_etypes;
2190 2107 : uint32_t config_kdc_enctypes = lpcfg_kdc_supported_enctypes(lp_ctx);
2191 2107 : uint32_t kdc_enctypes =
2192 : config_kdc_enctypes != 0 ?
2193 2107 : config_kdc_enctypes :
2194 : ENC_ALL_TYPES;
2195 2107 : struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
2196 0 : NTSTATUS status;
2197 2107 : uint32_t returned_kvno = 0;
2198 2107 : uint32_t available_enctypes = 0;
2199 :
2200 2107 : *entry = (struct sdb_entry) {};
2201 :
2202 2107 : tmp_ctx = talloc_new(mem_ctx);
2203 2107 : if (tmp_ctx == NULL) {
2204 0 : return ENOMEM;
2205 : }
2206 :
2207 2107 : if (dsdb_functional_level(kdc_db_ctx->samdb) >= DS_DOMAIN_FUNCTION_2008) {
2208 : /* If not told otherwise, Windows now assumes that trusts support AES. */
2209 2054 : supported_enctypes = ldb_msg_find_attr_as_uint(msg,
2210 : "msDS-SupportedEncryptionTypes",
2211 : ENC_HMAC_SHA1_96_AES256);
2212 : }
2213 :
2214 2107 : pa_supported_enctypes = supported_enctypes;
2215 2107 : supported_session_etypes = supported_enctypes;
2216 2107 : if (supported_session_etypes & ENC_HMAC_SHA1_96_AES256_SK) {
2217 0 : supported_session_etypes |= ENC_HMAC_SHA1_96_AES256;
2218 0 : supported_session_etypes |= ENC_HMAC_SHA1_96_AES128;
2219 : }
2220 2107 : if (force_rc4) {
2221 0 : supported_session_etypes |= ENC_RC4_HMAC_MD5;
2222 : }
2223 : /*
2224 : * now that we remembered what to announce in pa_supported_enctypes
2225 : * and normalized ENC_HMAC_SHA1_96_AES256_SK, we restrict the
2226 : * rest to the enc types the local kdc supports.
2227 : */
2228 2107 : supported_enctypes &= kdc_enctypes;
2229 2107 : supported_session_etypes &= kdc_enctypes;
2230 :
2231 2107 : status = dsdb_trust_parse_tdo_info(tmp_ctx, msg, &tdo);
2232 2107 : if (!NT_STATUS_IS_OK(status)) {
2233 0 : krb5_clear_error_message(context);
2234 0 : ret = ENOMEM;
2235 0 : goto out;
2236 : }
2237 :
2238 2107 : if (!(tdo->trust_direction & direction)) {
2239 2 : krb5_clear_error_message(context);
2240 2 : ret = SDB_ERR_NOENTRY;
2241 2 : goto out;
2242 : }
2243 :
2244 2105 : if (tdo->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
2245 : /*
2246 : * Only UPLEVEL domains support kerberos here,
2247 : * as we don't support LSA_TRUST_TYPE_MIT.
2248 : */
2249 0 : krb5_clear_error_message(context);
2250 0 : ret = SDB_ERR_NOENTRY;
2251 0 : goto out;
2252 : }
2253 :
2254 2105 : if (tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_CROSS_ORGANIZATION) {
2255 : /*
2256 : * We don't support selective authentication yet.
2257 : */
2258 0 : krb5_clear_error_message(context);
2259 0 : ret = SDB_ERR_NOENTRY;
2260 0 : goto out;
2261 : }
2262 :
2263 2105 : if (tdo->domain_name.string == NULL) {
2264 0 : krb5_clear_error_message(context);
2265 0 : ret = SDB_ERR_NOENTRY;
2266 0 : goto out;
2267 : }
2268 2105 : partner_realm = strupper_talloc(tmp_ctx, tdo->domain_name.string);
2269 2105 : if (partner_realm == NULL) {
2270 0 : krb5_clear_error_message(context);
2271 0 : ret = ENOMEM;
2272 0 : goto out;
2273 : }
2274 :
2275 2105 : if (direction == INBOUND) {
2276 1986 : realm = our_realm;
2277 1986 : krbtgt_realm = partner_realm;
2278 :
2279 1986 : password_val = ldb_msg_find_ldb_val(msg, "trustAuthIncoming");
2280 : } else { /* OUTBOUND */
2281 119 : realm = partner_realm;
2282 119 : krbtgt_realm = our_realm;
2283 :
2284 119 : password_val = ldb_msg_find_ldb_val(msg, "trustAuthOutgoing");
2285 : }
2286 :
2287 2105 : if (password_val == NULL) {
2288 0 : krb5_clear_error_message(context);
2289 0 : ret = SDB_ERR_NOENTRY;
2290 0 : goto out;
2291 : }
2292 :
2293 2105 : ndr_err = ndr_pull_struct_blob(password_val, tmp_ctx, &password_blob,
2294 : (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
2295 2105 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2296 0 : krb5_clear_error_message(context);
2297 0 : ret = EINVAL;
2298 0 : goto out;
2299 : }
2300 :
2301 2105 : p = talloc_zero(tmp_ctx, struct samba_kdc_entry);
2302 2105 : if (!p) {
2303 0 : ret = ENOMEM;
2304 0 : goto out;
2305 : }
2306 :
2307 2105 : p->is_trust = true;
2308 2105 : p->kdc_db_ctx = kdc_db_ctx;
2309 2105 : p->realm_dn = realm_dn;
2310 2105 : p->supported_enctypes = pa_supported_enctypes;
2311 :
2312 2105 : talloc_set_destructor(p, samba_kdc_entry_destructor);
2313 :
2314 2105 : entry->skdc_entry = p;
2315 :
2316 : /* use 'whenCreated' */
2317 2105 : entry->created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
2318 : /* use 'kadmin' for now (needed by mit_samba) */
2319 2105 : ret = smb_krb5_make_principal(context,
2320 : &entry->created_by.principal,
2321 : realm, "kadmin", NULL);
2322 2105 : if (ret) {
2323 0 : krb5_clear_error_message(context);
2324 0 : goto out;
2325 : }
2326 :
2327 : /*
2328 : * We always need to generate the canonicalized principal
2329 : * with the values of our database.
2330 : */
2331 2105 : ret = smb_krb5_make_principal(context, &entry->principal, realm,
2332 : "krbtgt", krbtgt_realm, NULL);
2333 2105 : if (ret) {
2334 0 : krb5_clear_error_message(context);
2335 0 : goto out;
2336 : }
2337 2105 : smb_krb5_principal_set_type(context, entry->principal,
2338 : KRB5_NT_SRV_INST);
2339 :
2340 2105 : entry->valid_start = NULL;
2341 :
2342 : /* we need to work out if we are going to use the current or
2343 : * the previous password hash.
2344 : * We base this on the kvno the client passes in. If the kvno
2345 : * passed in is equal to the current kvno in our database then
2346 : * we use the current structure. If it is the current kvno-1,
2347 : * then we use the previous substructure.
2348 : */
2349 :
2350 : /*
2351 : * Windows prefers the previous key for one hour.
2352 : */
2353 2105 : tv = timeval_current();
2354 2105 : if (tv.tv_sec > 3600) {
2355 2105 : tv.tv_sec -= 3600;
2356 : }
2357 2105 : an_hour_ago = timeval_to_nttime(&tv);
2358 :
2359 : /* first work out the current kvno */
2360 2105 : current_kvno = 0;
2361 5900 : for (i=0; i < password_blob.count; i++) {
2362 3795 : struct AuthenticationInformation *a =
2363 3795 : &password_blob.current.array[i];
2364 :
2365 3795 : if (a->LastUpdateTime <= an_hour_ago) {
2366 0 : prefer_current = true;
2367 : }
2368 :
2369 3795 : if (a->AuthType == TRUST_AUTH_TYPE_VERSION) {
2370 1690 : current_kvno = a->AuthInfo.version.version;
2371 : }
2372 : }
2373 2105 : if (current_kvno == 0) {
2374 415 : previous_kvno = 255;
2375 : } else {
2376 1690 : previous_kvno = current_kvno - 1;
2377 : }
2378 5900 : for (i=0; i < password_blob.count; i++) {
2379 3795 : struct AuthenticationInformation *a =
2380 3795 : &password_blob.previous.array[i];
2381 :
2382 3795 : if (a->AuthType == TRUST_AUTH_TYPE_VERSION) {
2383 624 : previous_kvno = a->AuthInfo.version.version;
2384 : }
2385 : }
2386 :
2387 : /* work out whether we will use the previous or current
2388 : password */
2389 2105 : if (password_blob.previous.count == 0) {
2390 : /* there is no previous password */
2391 0 : use_previous = false;
2392 2105 : } else if (!(flags & SDB_F_KVNO_SPECIFIED)) {
2393 : /*
2394 : * If not specified we use the lowest kvno
2395 : * for the first hour after an update.
2396 : */
2397 2105 : if (prefer_current) {
2398 0 : use_previous = false;
2399 2105 : } else if (previous_kvno < current_kvno) {
2400 1690 : use_previous = true;
2401 : } else {
2402 415 : use_previous = false;
2403 : }
2404 :
2405 2105 : if (flags & SDB_F_ADMIN_DATA) {
2406 : /*
2407 : * let admin tool
2408 : * get to all keys
2409 : */
2410 0 : use_previous = false;
2411 0 : include_previous = true;
2412 : }
2413 0 : } else if (kvno == current_kvno) {
2414 : /*
2415 : * Exact match ...
2416 : */
2417 0 : use_previous = false;
2418 0 : } else if (kvno == previous_kvno) {
2419 : /*
2420 : * Exact match ...
2421 : */
2422 0 : use_previous = true;
2423 : } else {
2424 : /*
2425 : * Fallback to the current one for anything else
2426 : */
2427 0 : use_previous = false;
2428 : }
2429 :
2430 2105 : current_keys = (struct samba_kdc_trust_keys) {
2431 : .kvno = current_kvno,
2432 : .supported_enctypes = supported_enctypes,
2433 2105 : .salt_principal = entry->principal,
2434 : .auth_array = &password_blob.current,
2435 : };
2436 :
2437 2105 : previous_keys = (struct samba_kdc_trust_keys) {
2438 : .kvno = previous_kvno,
2439 : .supported_enctypes = supported_enctypes,
2440 2105 : .salt_principal = entry->principal,
2441 : .auth_array = &password_blob.previous,
2442 : };
2443 :
2444 2105 : if (use_previous) {
2445 : /*
2446 : * return the old keys as default keys
2447 : * with the requested kvno.
2448 : */
2449 1690 : previous_keys.skeys = &entry->keys;
2450 1690 : previous_keys.available_enctypes = &available_enctypes;
2451 1690 : previous_keys.returned_kvno = &returned_kvno;
2452 : } else {
2453 : /*
2454 : * return the current keys as default keys
2455 : * with the requested kvno.
2456 : */
2457 415 : current_keys.skeys = &entry->keys;
2458 415 : current_keys.available_enctypes = &available_enctypes;
2459 415 : current_keys.returned_kvno = &returned_kvno;
2460 :
2461 415 : if (include_previous) {
2462 : /*
2463 : * return the old keys in addition.
2464 : */
2465 0 : previous_keys.skeys = &entry->old_keys;
2466 : }
2467 : }
2468 :
2469 2105 : if (current_keys.skeys != NULL) {
2470 415 : ret = samba_kdc_fill_trust_keys(context, ¤t_keys);
2471 415 : if (ret != 0) {
2472 0 : goto out;
2473 : }
2474 : }
2475 :
2476 2105 : if (previous_keys.skeys != NULL) {
2477 1690 : ret = samba_kdc_fill_trust_keys(context, &previous_keys);
2478 1690 : if (ret != 0) {
2479 0 : goto out;
2480 : }
2481 : }
2482 :
2483 : /* use the kvno the client specified, if available */
2484 2105 : if (flags & SDB_F_KVNO_SPECIFIED) {
2485 0 : returned_kvno = kvno;
2486 : }
2487 :
2488 : /* Must have found a cleartext or MD4 password */
2489 2105 : if (entry->keys.len == 0) {
2490 0 : DBG_WARNING("no usable key found\n");
2491 0 : krb5_clear_error_message(context);
2492 0 : ret = SDB_ERR_NOENTRY;
2493 0 : goto out;
2494 : }
2495 :
2496 2105 : entry->flags = (struct SDBFlags) {};
2497 2105 : entry->flags.immutable = 1;
2498 2105 : entry->flags.invalid = 0;
2499 2105 : entry->flags.server = 1;
2500 2105 : entry->flags.require_preauth = 1;
2501 :
2502 2105 : entry->pw_end = NULL;
2503 :
2504 2105 : entry->max_life = NULL;
2505 :
2506 2105 : entry->max_renew = NULL;
2507 :
2508 : /* Match Windows behavior and allow forwardable flag in cross-realm. */
2509 2105 : entry->flags.forwardable = 1;
2510 :
2511 2105 : entry->kvno = returned_kvno;
2512 :
2513 : /*
2514 : * We need to support all session keys enctypes for
2515 : * all keys we provide
2516 : */
2517 2105 : supported_session_etypes |= available_enctypes;
2518 :
2519 2105 : ret = sdb_entry_set_etypes(entry);
2520 2105 : if (ret) {
2521 0 : goto out;
2522 : }
2523 :
2524 : {
2525 2105 : bool add_aes256 =
2526 2105 : supported_session_etypes & KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96;
2527 2105 : bool add_aes128 =
2528 2105 : supported_session_etypes & KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96;
2529 2105 : bool add_rc4 =
2530 2105 : supported_session_etypes & ENC_RC4_HMAC_MD5;
2531 2105 : ret = sdb_entry_set_session_etypes(entry,
2532 : add_aes256,
2533 : add_aes128,
2534 : add_rc4);
2535 2105 : if (ret) {
2536 0 : goto out;
2537 : }
2538 : }
2539 :
2540 2105 : p->msg = talloc_steal(p, msg);
2541 :
2542 2105 : talloc_steal(kdc_db_ctx, p);
2543 :
2544 2107 : out:
2545 2107 : TALLOC_FREE(partner_realm);
2546 :
2547 2107 : if (ret != 0) {
2548 : /* This doesn't free ent itself, that is for the eventual caller to do */
2549 2 : sdb_entry_free(entry);
2550 : }
2551 :
2552 2107 : talloc_free(tmp_ctx);
2553 2107 : return ret;
2554 :
2555 : }
2556 :
2557 2115 : static krb5_error_code samba_kdc_lookup_trust(krb5_context context, struct ldb_context *ldb_ctx,
2558 : TALLOC_CTX *mem_ctx,
2559 : const char *realm,
2560 : struct ldb_dn *realm_dn,
2561 : struct ldb_message **pmsg)
2562 : {
2563 0 : NTSTATUS status;
2564 2115 : const char * const *attrs = trust_attrs;
2565 :
2566 2115 : status = dsdb_trust_search_tdo(ldb_ctx, realm, realm,
2567 : attrs, mem_ctx, pmsg);
2568 2115 : if (NT_STATUS_IS_OK(status)) {
2569 2107 : return 0;
2570 8 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
2571 8 : return SDB_ERR_NOENTRY;
2572 0 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) {
2573 0 : int ret = ENOMEM;
2574 0 : krb5_set_error_message(context, ret, "samba_kdc_lookup_trust: out of memory");
2575 0 : return ret;
2576 : } else {
2577 0 : int ret = EINVAL;
2578 0 : krb5_set_error_message(context, ret, "samba_kdc_lookup_trust: %s", nt_errstr(status));
2579 0 : return ret;
2580 : }
2581 : }
2582 :
2583 102909 : static krb5_error_code samba_kdc_lookup_client(krb5_context context,
2584 : struct samba_kdc_db_context *kdc_db_ctx,
2585 : TALLOC_CTX *mem_ctx,
2586 : krb5_const_principal principal,
2587 : const char **attrs,
2588 : const uint32_t dsdb_flags,
2589 : struct ldb_dn **realm_dn,
2590 : struct ldb_message **msg)
2591 : {
2592 3448 : NTSTATUS nt_status;
2593 102909 : char *principal_string = NULL;
2594 :
2595 102909 : if (smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
2596 2758 : krb5_error_code ret = 0;
2597 :
2598 2758 : ret = smb_krb5_principal_get_comp_string(mem_ctx, context,
2599 : principal, 0, &principal_string);
2600 2758 : if (ret) {
2601 0 : return ret;
2602 : }
2603 : } else {
2604 100151 : char *principal_string_m = NULL;
2605 3448 : krb5_error_code ret;
2606 :
2607 100151 : ret = krb5_unparse_name(context, principal, &principal_string_m);
2608 100151 : if (ret != 0) {
2609 0 : return ret;
2610 : }
2611 :
2612 100151 : principal_string = talloc_strdup(mem_ctx, principal_string_m);
2613 100151 : SAFE_FREE(principal_string_m);
2614 100151 : if (principal_string == NULL) {
2615 0 : return ENOMEM;
2616 : }
2617 : }
2618 :
2619 102909 : nt_status = sam_get_results_principal(kdc_db_ctx->samdb,
2620 : mem_ctx, principal_string, attrs, dsdb_flags,
2621 : realm_dn, msg);
2622 102909 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
2623 2725 : krb5_principal fallback_principal = NULL;
2624 0 : unsigned int num_comp;
2625 2725 : char *fallback_realm = NULL;
2626 2725 : char *fallback_account = NULL;
2627 0 : krb5_error_code ret;
2628 :
2629 2725 : ret = krb5_parse_name(context, principal_string,
2630 : &fallback_principal);
2631 2725 : TALLOC_FREE(principal_string);
2632 2725 : if (ret != 0) {
2633 0 : return ret;
2634 : }
2635 :
2636 2725 : num_comp = krb5_princ_size(context, fallback_principal);
2637 2725 : fallback_realm = smb_krb5_principal_get_realm(
2638 : mem_ctx, context, fallback_principal);
2639 2725 : if (fallback_realm == NULL) {
2640 0 : krb5_free_principal(context, fallback_principal);
2641 0 : return ENOMEM;
2642 : }
2643 :
2644 2725 : if (num_comp == 1) {
2645 0 : size_t len;
2646 :
2647 2292 : ret = smb_krb5_principal_get_comp_string(mem_ctx,
2648 : context, fallback_principal, 0, &fallback_account);
2649 2292 : if (ret) {
2650 0 : krb5_free_principal(context, fallback_principal);
2651 0 : TALLOC_FREE(fallback_realm);
2652 0 : return ret;
2653 : }
2654 :
2655 2292 : len = strlen(fallback_account);
2656 2292 : if (len >= 2 && fallback_account[len - 1] == '$') {
2657 18 : TALLOC_FREE(fallback_account);
2658 : }
2659 : }
2660 2725 : krb5_free_principal(context, fallback_principal);
2661 2725 : fallback_principal = NULL;
2662 :
2663 2725 : if (fallback_account != NULL) {
2664 0 : char *with_dollar;
2665 :
2666 2274 : with_dollar = talloc_asprintf(mem_ctx, "%s$",
2667 : fallback_account);
2668 2274 : if (with_dollar == NULL) {
2669 0 : TALLOC_FREE(fallback_realm);
2670 0 : return ENOMEM;
2671 : }
2672 2274 : TALLOC_FREE(fallback_account);
2673 :
2674 2274 : ret = smb_krb5_make_principal(context,
2675 : &fallback_principal,
2676 : fallback_realm,
2677 : with_dollar, NULL);
2678 2274 : TALLOC_FREE(with_dollar);
2679 2274 : if (ret != 0) {
2680 0 : TALLOC_FREE(fallback_realm);
2681 0 : return ret;
2682 : }
2683 : }
2684 2725 : TALLOC_FREE(fallback_realm);
2685 :
2686 2725 : if (fallback_principal != NULL) {
2687 2274 : char *fallback_string = NULL;
2688 :
2689 2274 : ret = krb5_unparse_name(context,
2690 : fallback_principal,
2691 : &fallback_string);
2692 2274 : if (ret != 0) {
2693 0 : krb5_free_principal(context, fallback_principal);
2694 0 : return ret;
2695 : }
2696 :
2697 2274 : nt_status = sam_get_results_principal(kdc_db_ctx->samdb,
2698 : mem_ctx,
2699 : fallback_string,
2700 : attrs, dsdb_flags,
2701 : realm_dn, msg);
2702 2274 : SAFE_FREE(fallback_string);
2703 : }
2704 2725 : krb5_free_principal(context, fallback_principal);
2705 2725 : fallback_principal = NULL;
2706 : }
2707 102909 : TALLOC_FREE(principal_string);
2708 :
2709 102909 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
2710 510 : return SDB_ERR_NOENTRY;
2711 102399 : } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
2712 0 : return ENOMEM;
2713 102399 : } else if (!NT_STATUS_IS_OK(nt_status)) {
2714 0 : return EINVAL;
2715 : }
2716 :
2717 98951 : return 0;
2718 : }
2719 :
2720 101998 : static krb5_error_code samba_kdc_fetch_client(krb5_context context,
2721 : struct samba_kdc_db_context *kdc_db_ctx,
2722 : TALLOC_CTX *mem_ctx,
2723 : krb5_const_principal principal,
2724 : unsigned flags,
2725 : krb5_kvno kvno,
2726 : struct sdb_entry *entry)
2727 : {
2728 3448 : struct ldb_dn *realm_dn;
2729 3448 : krb5_error_code ret;
2730 101998 : struct ldb_message *msg = NULL;
2731 :
2732 101998 : ret = samba_kdc_lookup_client(context, kdc_db_ctx,
2733 : mem_ctx, principal, user_attrs, DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS,
2734 : &realm_dn, &msg);
2735 101998 : if (ret != 0) {
2736 510 : return ret;
2737 : }
2738 :
2739 101488 : ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
2740 : principal, SAMBA_KDC_ENT_TYPE_CLIENT,
2741 : flags, kvno,
2742 : realm_dn, msg, entry);
2743 101488 : return ret;
2744 : }
2745 :
2746 208667 : static krb5_error_code samba_kdc_fetch_krbtgt(krb5_context context,
2747 : struct samba_kdc_db_context *kdc_db_ctx,
2748 : TALLOC_CTX *mem_ctx,
2749 : krb5_const_principal principal,
2750 : unsigned flags,
2751 : uint32_t kvno,
2752 : struct sdb_entry *entry)
2753 : {
2754 208667 : TALLOC_CTX *tmp_ctx = NULL;
2755 208667 : struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
2756 208667 : krb5_error_code ret = 0;
2757 6792 : int is_krbtgt;
2758 208667 : struct ldb_message *msg = NULL;
2759 208667 : struct ldb_dn *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
2760 6792 : char *realm_from_princ;
2761 208667 : char *realm_princ_comp = NULL;
2762 :
2763 208667 : tmp_ctx = talloc_new(mem_ctx);
2764 208667 : if (tmp_ctx == NULL) {
2765 0 : ret = ENOMEM;
2766 0 : goto out;
2767 : }
2768 :
2769 208667 : realm_from_princ = smb_krb5_principal_get_realm(
2770 : tmp_ctx, context, principal);
2771 208667 : if (realm_from_princ == NULL) {
2772 : /* can't happen */
2773 0 : ret = SDB_ERR_NOENTRY;
2774 0 : goto out;
2775 : }
2776 :
2777 208667 : is_krbtgt = smb_krb5_principal_is_tgs(context, principal);
2778 208667 : if (is_krbtgt == -1) {
2779 0 : ret = ENOMEM;
2780 0 : goto out;
2781 208667 : } else if (!is_krbtgt) {
2782 : /* Not a krbtgt */
2783 28818 : ret = SDB_ERR_NOENTRY;
2784 28818 : goto out;
2785 : }
2786 :
2787 : /* krbtgt case. Either us or a trusted realm */
2788 :
2789 179849 : ret = smb_krb5_principal_get_comp_string(tmp_ctx, context, principal, 1, &realm_princ_comp);
2790 179849 : if (ret == ENOENT) {
2791 : /* OK. */
2792 179812 : } else if (ret) {
2793 0 : goto out;
2794 : }
2795 :
2796 179849 : if (lpcfg_is_my_domain_or_realm(lp_ctx, realm_from_princ)
2797 349951 : && (realm_princ_comp == NULL || lpcfg_is_my_domain_or_realm(lp_ctx, realm_princ_comp))) {
2798 : /* us, or someone quite like us */
2799 : /* Kludge, kludge, kludge. If the realm part of krbtgt/realm,
2800 : * is in our db, then direct the caller at our primary
2801 : * krbtgt */
2802 :
2803 6162 : int lret;
2804 6162 : unsigned int krbtgt_number;
2805 : /* w2k8r2 sometimes gives us a kvno of 255 for inter-domain
2806 : trust tickets. We don't yet know what this means, but we do
2807 : seem to need to treat it as unspecified */
2808 177734 : if (flags & (SDB_F_KVNO_SPECIFIED|SDB_F_RODC_NUMBER_SPECIFIED)) {
2809 53248 : krbtgt_number = SAMBA_KVNO_GET_KRBTGT(kvno);
2810 53248 : if (kdc_db_ctx->rodc) {
2811 3980 : if (krbtgt_number != kdc_db_ctx->my_krbtgt_number) {
2812 1351 : ret = SDB_ERR_NOT_FOUND_HERE;
2813 1351 : goto out;
2814 : }
2815 : }
2816 : } else {
2817 124486 : krbtgt_number = kdc_db_ctx->my_krbtgt_number;
2818 : }
2819 :
2820 176383 : if (krbtgt_number == kdc_db_ctx->my_krbtgt_number) {
2821 176161 : lret = dsdb_search_one(kdc_db_ctx->samdb, tmp_ctx,
2822 : &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
2823 : krbtgt_attrs, DSDB_SEARCH_NO_GLOBAL_CATALOG | DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS,
2824 : "(objectClass=user)");
2825 : } else {
2826 : /* We need to look up an RODC krbtgt (perhaps
2827 : * ours, if we are an RODC, perhaps another
2828 : * RODC if we are a read-write DC */
2829 222 : lret = dsdb_search_one(kdc_db_ctx->samdb, tmp_ctx,
2830 : &msg, realm_dn, LDB_SCOPE_SUBTREE,
2831 : krbtgt_attrs,
2832 : DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG | DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS,
2833 : "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=%u))", (unsigned)(krbtgt_number));
2834 : }
2835 :
2836 176383 : if (lret == LDB_ERR_NO_SUCH_OBJECT) {
2837 0 : krb5_warnx(context, "samba_kdc_fetch_krbtgt: could not find KRBTGT number %u in DB!",
2838 : (unsigned)(krbtgt_number));
2839 0 : krb5_set_error_message(context, SDB_ERR_NOENTRY,
2840 : "samba_kdc_fetch_krbtgt: could not find KRBTGT number %u in DB!",
2841 : (unsigned)(krbtgt_number));
2842 0 : ret = SDB_ERR_NOENTRY;
2843 0 : goto out;
2844 176383 : } else if (lret != LDB_SUCCESS) {
2845 0 : krb5_warnx(context, "samba_kdc_fetch_krbtgt: could not find KRBTGT number %u in DB!",
2846 : (unsigned)(krbtgt_number));
2847 0 : krb5_set_error_message(context, SDB_ERR_NOENTRY,
2848 : "samba_kdc_fetch_krbtgt: could not find KRBTGT number %u in DB!",
2849 : (unsigned)(krbtgt_number));
2850 0 : ret = SDB_ERR_NOENTRY;
2851 0 : goto out;
2852 : }
2853 :
2854 176383 : ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
2855 : principal, SAMBA_KDC_ENT_TYPE_KRBTGT,
2856 : flags, kvno, realm_dn, msg, entry);
2857 176383 : if (ret != 0) {
2858 0 : krb5_warnx(context, "samba_kdc_fetch_krbtgt: self krbtgt message2entry failed");
2859 : }
2860 : } else {
2861 2115 : enum trust_direction direction = UNKNOWN;
2862 2115 : const char *realm = NULL;
2863 :
2864 : /* Either an inbound or outbound trust */
2865 :
2866 2115 : if (strcasecmp(lpcfg_realm(lp_ctx), realm_from_princ) == 0) {
2867 : /* look for inbound trust */
2868 1996 : direction = INBOUND;
2869 1996 : realm = realm_princ_comp;
2870 : } else {
2871 119 : bool eq = false;
2872 :
2873 119 : ret = is_principal_component_equal_ignoring_case(context, principal, 1, lpcfg_realm(lp_ctx), &eq);
2874 119 : if (ret) {
2875 0 : goto out;
2876 : }
2877 :
2878 119 : if (eq) {
2879 : /* look for outbound trust */
2880 119 : direction = OUTBOUND;
2881 119 : realm = realm_from_princ;
2882 : } else {
2883 0 : krb5_warnx(context, "samba_kdc_fetch_krbtgt: not our realm for trusts ('%s', '%s')",
2884 : realm_from_princ,
2885 : realm_princ_comp);
2886 0 : krb5_set_error_message(context, SDB_ERR_NOENTRY, "samba_kdc_fetch_krbtgt: not our realm for trusts ('%s', '%s')",
2887 : realm_from_princ,
2888 : realm_princ_comp);
2889 0 : ret = SDB_ERR_NOENTRY;
2890 0 : goto out;
2891 : }
2892 : }
2893 :
2894 : /* Trusted domains are under CN=system */
2895 :
2896 2115 : ret = samba_kdc_lookup_trust(context, kdc_db_ctx->samdb,
2897 : tmp_ctx,
2898 : realm, realm_dn, &msg);
2899 :
2900 2115 : if (ret != 0) {
2901 8 : krb5_warnx(context, "samba_kdc_fetch_krbtgt: could not find principal in DB");
2902 8 : krb5_set_error_message(context, ret, "samba_kdc_fetch_krbtgt: could not find principal in DB");
2903 8 : goto out;
2904 : }
2905 :
2906 2107 : ret = samba_kdc_trust_message2entry(context, kdc_db_ctx, mem_ctx,
2907 : direction,
2908 : realm_dn, flags, kvno, msg, entry);
2909 2107 : if (ret != 0) {
2910 2 : krb5_warnx(context, "samba_kdc_fetch_krbtgt: trust_message2entry failed for %s",
2911 2 : ldb_dn_get_linearized(msg->dn));
2912 2 : krb5_set_error_message(context, ret, "samba_kdc_fetch_krbtgt: "
2913 : "trust_message2entry failed for %s",
2914 2 : ldb_dn_get_linearized(msg->dn));
2915 : }
2916 : }
2917 :
2918 2105 : out:
2919 208667 : talloc_free(tmp_ctx);
2920 208667 : return ret;
2921 : }
2922 :
2923 28824 : static krb5_error_code samba_kdc_lookup_server(krb5_context context,
2924 : struct samba_kdc_db_context *kdc_db_ctx,
2925 : TALLOC_CTX *mem_ctx,
2926 : krb5_const_principal principal,
2927 : unsigned flags,
2928 : struct ldb_dn **realm_dn,
2929 : struct ldb_message **msg)
2930 : {
2931 630 : krb5_error_code ret;
2932 28824 : if ((smb_krb5_principal_get_type(context, principal) != KRB5_NT_ENTERPRISE_PRINCIPAL)
2933 27832 : && krb5_princ_size(context, principal) >= 2) {
2934 : /* 'normal server' case */
2935 630 : int ldb_ret;
2936 630 : NTSTATUS nt_status;
2937 630 : struct ldb_dn *user_dn;
2938 630 : char *principal_string;
2939 :
2940 26202 : ret = krb5_unparse_name_flags(context, principal,
2941 : KRB5_PRINCIPAL_UNPARSE_NO_REALM,
2942 : &principal_string);
2943 26202 : if (ret != 0) {
2944 0 : return ret;
2945 : }
2946 :
2947 : /* At this point we may find the host is known to be
2948 : * in a different realm, so we should generate a
2949 : * referral instead */
2950 26202 : nt_status = crack_service_principal_name(kdc_db_ctx->samdb,
2951 : mem_ctx, principal_string,
2952 : &user_dn, realm_dn);
2953 26202 : free(principal_string);
2954 :
2955 26202 : if (!NT_STATUS_IS_OK(nt_status)) {
2956 380 : return SDB_ERR_NOENTRY;
2957 : }
2958 :
2959 25822 : ldb_ret = dsdb_search_one(kdc_db_ctx->samdb,
2960 : mem_ctx,
2961 : msg, user_dn, LDB_SCOPE_BASE,
2962 : server_attrs,
2963 : DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG | DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS,
2964 : "(objectClass=*)");
2965 25822 : if (ldb_ret != LDB_SUCCESS) {
2966 0 : return SDB_ERR_NOENTRY;
2967 : }
2968 25822 : return 0;
2969 2622 : } else if (!(flags & SDB_F_FOR_AS_REQ)
2970 2257 : && smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
2971 : /*
2972 : * The behaviour of accepting an
2973 : * KRB5_NT_ENTERPRISE_PRINCIPAL server principal
2974 : * containing a UPN only applies to TGS-REQ packets,
2975 : * not AS-REQ packets.
2976 : */
2977 864 : return samba_kdc_lookup_client(context, kdc_db_ctx,
2978 : mem_ctx, principal, server_attrs, DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS,
2979 : realm_dn, msg);
2980 : } else {
2981 : /*
2982 : * This case is for:
2983 : * - the AS-REQ, where we only accept
2984 : * samAccountName based lookups for the server, no
2985 : * matter if the name is an
2986 : * KRB5_NT_ENTERPRISE_PRINCIPAL or not
2987 : * - for the TGS-REQ when we are not given an
2988 : * KRB5_NT_ENTERPRISE_PRINCIPAL, which also must
2989 : * only lookup samAccountName based names.
2990 : */
2991 0 : int lret;
2992 0 : char *short_princ;
2993 1758 : krb5_principal enterprise_principal = NULL;
2994 1758 : krb5_const_principal used_principal = NULL;
2995 1758 : char *name1 = NULL;
2996 1758 : size_t len1 = 0;
2997 1758 : char *filter = NULL;
2998 :
2999 1758 : if (smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
3000 128 : char *str = NULL;
3001 : /* Need to reparse the enterprise principal to find the real target */
3002 128 : if (krb5_princ_size(context, principal) != 1) {
3003 0 : ret = KRB5_PARSE_MALFORMED;
3004 0 : krb5_set_error_message(context, ret, "samba_kdc_lookup_server: request for an "
3005 : "enterprise principal with wrong (%d) number of components",
3006 0 : krb5_princ_size(context, principal));
3007 0 : return ret;
3008 : }
3009 128 : ret = smb_krb5_principal_get_comp_string(mem_ctx, context, principal, 0, &str);
3010 128 : if (ret) {
3011 0 : return KRB5_PARSE_MALFORMED;
3012 : }
3013 128 : ret = krb5_parse_name(context, str,
3014 : &enterprise_principal);
3015 128 : talloc_free(str);
3016 128 : if (ret) {
3017 0 : return ret;
3018 : }
3019 128 : used_principal = enterprise_principal;
3020 : } else {
3021 1630 : used_principal = principal;
3022 : }
3023 :
3024 : /* server as client principal case, but we must not lookup userPrincipalNames */
3025 1758 : *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
3026 :
3027 : /* TODO: Check if it is our realm, otherwise give referral */
3028 :
3029 1758 : ret = krb5_unparse_name_flags(context, used_principal,
3030 : KRB5_PRINCIPAL_UNPARSE_NO_REALM |
3031 : KRB5_PRINCIPAL_UNPARSE_DISPLAY,
3032 : &short_princ);
3033 1758 : used_principal = NULL;
3034 1758 : krb5_free_principal(context, enterprise_principal);
3035 1758 : enterprise_principal = NULL;
3036 :
3037 1758 : if (ret != 0) {
3038 0 : krb5_set_error_message(context, ret, "samba_kdc_lookup_server: could not parse principal");
3039 0 : krb5_warnx(context, "samba_kdc_lookup_server: could not parse principal");
3040 0 : return ret;
3041 : }
3042 :
3043 1758 : name1 = ldb_binary_encode_string(mem_ctx, short_princ);
3044 1758 : SAFE_FREE(short_princ);
3045 1758 : if (name1 == NULL) {
3046 0 : return ENOMEM;
3047 : }
3048 1758 : len1 = strlen(name1);
3049 1758 : if (len1 >= 1 && name1[len1 - 1] != '$') {
3050 1189 : filter = talloc_asprintf(mem_ctx,
3051 : "(&(objectClass=user)(|(samAccountName=%s)(samAccountName=%s$)))",
3052 : name1, name1);
3053 1189 : if (filter == NULL) {
3054 0 : return ENOMEM;
3055 : }
3056 : } else {
3057 569 : filter = talloc_asprintf(mem_ctx,
3058 : "(&(objectClass=user)(samAccountName=%s))",
3059 : name1);
3060 569 : if (filter == NULL) {
3061 0 : return ENOMEM;
3062 : }
3063 : }
3064 :
3065 1758 : lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx, msg,
3066 : *realm_dn, LDB_SCOPE_SUBTREE,
3067 : server_attrs,
3068 : DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG | DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS,
3069 : "%s", filter);
3070 1758 : if (lret == LDB_ERR_NO_SUCH_OBJECT) {
3071 192 : DBG_DEBUG("Failed to find an entry for %s filter:%s\n",
3072 : name1, filter);
3073 192 : return SDB_ERR_NOENTRY;
3074 : }
3075 1566 : if (lret == LDB_ERR_CONSTRAINT_VIOLATION) {
3076 0 : DBG_DEBUG("Failed to find unique entry for %s filter:%s\n",
3077 : name1, filter);
3078 0 : return SDB_ERR_NOENTRY;
3079 : }
3080 1566 : if (lret != LDB_SUCCESS) {
3081 0 : DBG_ERR("Failed single search for %s - %s\n",
3082 : name1, ldb_errstring(kdc_db_ctx->samdb));
3083 0 : return SDB_ERR_NOENTRY;
3084 : }
3085 1566 : return 0;
3086 : }
3087 : return SDB_ERR_NOENTRY;
3088 : }
3089 :
3090 :
3091 :
3092 28824 : static krb5_error_code samba_kdc_fetch_server(krb5_context context,
3093 : struct samba_kdc_db_context *kdc_db_ctx,
3094 : TALLOC_CTX *mem_ctx,
3095 : krb5_const_principal principal,
3096 : unsigned flags,
3097 : krb5_kvno kvno,
3098 : struct sdb_entry *entry)
3099 : {
3100 630 : krb5_error_code ret;
3101 630 : struct ldb_dn *realm_dn;
3102 630 : struct ldb_message *msg;
3103 :
3104 28824 : ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, principal,
3105 : flags, &realm_dn, &msg);
3106 28824 : if (ret != 0) {
3107 572 : return ret;
3108 : }
3109 :
3110 28252 : ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
3111 : principal, SAMBA_KDC_ENT_TYPE_SERVER,
3112 : flags, kvno,
3113 : realm_dn, msg, entry);
3114 28252 : if (ret != 0) {
3115 718 : char *client_name = NULL;
3116 0 : krb5_error_code code;
3117 :
3118 718 : code = krb5_unparse_name(context, principal, &client_name);
3119 718 : if (code == 0) {
3120 718 : krb5_warnx(context,
3121 : "samba_kdc_fetch_server: message2entry failed for "
3122 : "%s",
3123 : client_name);
3124 : } else {
3125 0 : krb5_warnx(context,
3126 : "samba_kdc_fetch_server: message2entry and "
3127 : "krb5_unparse_name failed");
3128 : }
3129 718 : SAFE_FREE(client_name);
3130 : }
3131 :
3132 27622 : return ret;
3133 : }
3134 :
3135 312352 : static krb5_error_code samba_kdc_lookup_realm(krb5_context context,
3136 : struct samba_kdc_db_context *kdc_db_ctx,
3137 : krb5_const_principal principal,
3138 : unsigned flags,
3139 : struct sdb_entry *entry)
3140 : {
3141 312352 : TALLOC_CTX *frame = talloc_stackframe();
3142 10240 : NTSTATUS status;
3143 10240 : krb5_error_code ret;
3144 312352 : bool check_realm = false;
3145 312352 : const char *realm = NULL;
3146 312352 : struct dsdb_trust_routing_table *trt = NULL;
3147 312352 : const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
3148 10240 : unsigned int num_comp;
3149 10240 : bool ok;
3150 312352 : char *upper = NULL;
3151 :
3152 312352 : *entry = (struct sdb_entry) {};
3153 :
3154 312352 : num_comp = krb5_princ_size(context, principal);
3155 :
3156 312352 : if (flags & SDB_F_GET_CLIENT) {
3157 102536 : if (flags & SDB_F_FOR_AS_REQ) {
3158 51651 : check_realm = true;
3159 : }
3160 : }
3161 312352 : if (flags & SDB_F_GET_SERVER) {
3162 101358 : if (flags & SDB_F_FOR_TGS_REQ) {
3163 50997 : check_realm = true;
3164 : }
3165 : }
3166 :
3167 310680 : if (!check_realm) {
3168 208032 : TALLOC_FREE(frame);
3169 208032 : return 0;
3170 : }
3171 :
3172 104320 : realm = smb_krb5_principal_get_realm(frame, context, principal);
3173 104320 : if (realm == NULL) {
3174 0 : TALLOC_FREE(frame);
3175 0 : return ENOMEM;
3176 : }
3177 :
3178 : /*
3179 : * The requested realm needs to be our own
3180 : */
3181 104320 : ok = lpcfg_is_my_domain_or_realm(kdc_db_ctx->lp_ctx, realm);
3182 104320 : if (!ok) {
3183 : /*
3184 : * The request is not for us...
3185 : */
3186 1 : TALLOC_FREE(frame);
3187 1 : return SDB_ERR_NOENTRY;
3188 : }
3189 :
3190 104319 : if (smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
3191 3097 : char *principal_string = NULL;
3192 3097 : krb5_principal enterprise_principal = NULL;
3193 3097 : char *enterprise_realm = NULL;
3194 :
3195 3097 : if (num_comp != 1) {
3196 0 : TALLOC_FREE(frame);
3197 0 : return SDB_ERR_NOENTRY;
3198 : }
3199 :
3200 3097 : ret = smb_krb5_principal_get_comp_string(frame, context,
3201 : principal, 0, &principal_string);
3202 3097 : if (ret) {
3203 0 : TALLOC_FREE(frame);
3204 0 : return ret;
3205 : }
3206 :
3207 3097 : ret = krb5_parse_name(context, principal_string,
3208 : &enterprise_principal);
3209 3097 : TALLOC_FREE(principal_string);
3210 3097 : if (ret) {
3211 0 : TALLOC_FREE(frame);
3212 0 : return ret;
3213 : }
3214 :
3215 3097 : enterprise_realm = smb_krb5_principal_get_realm(
3216 : frame, context, enterprise_principal);
3217 3097 : krb5_free_principal(context, enterprise_principal);
3218 3097 : if (enterprise_realm != NULL) {
3219 3097 : realm = enterprise_realm;
3220 : }
3221 : }
3222 :
3223 104319 : if (flags & SDB_F_GET_SERVER) {
3224 52672 : bool is_krbtgt = false;
3225 :
3226 52672 : ret = is_principal_component_equal(context, principal, 0, KRB5_TGS_NAME, &is_krbtgt);
3227 52672 : if (ret) {
3228 0 : TALLOC_FREE(frame);
3229 28142 : return ret;
3230 : }
3231 :
3232 52672 : if (is_krbtgt) {
3233 : /*
3234 : * we need to search krbtgt/ locally
3235 : */
3236 28142 : TALLOC_FREE(frame);
3237 28142 : return 0;
3238 : }
3239 :
3240 : /*
3241 : * We need to check the last component against the routing table.
3242 : *
3243 : * Note this works only with 2 or 3 component principals, e.g:
3244 : *
3245 : * servicePrincipalName: ldap/W2K8R2-219.bla.base
3246 : * servicePrincipalName: ldap/W2K8R2-219.bla.base/bla.base
3247 : * servicePrincipalName: ldap/W2K8R2-219.bla.base/ForestDnsZones.bla.base
3248 : * servicePrincipalName: ldap/W2K8R2-219.bla.base/DomainDnsZones.bla.base
3249 : */
3250 :
3251 24530 : if (num_comp == 2 || num_comp == 3) {
3252 21981 : char *service_realm = NULL;
3253 :
3254 21981 : ret = smb_krb5_principal_get_comp_string(frame,
3255 : context,
3256 : principal,
3257 : num_comp - 1,
3258 : &service_realm);
3259 21981 : if (ret) {
3260 0 : TALLOC_FREE(frame);
3261 0 : return ret;
3262 : } else {
3263 21981 : realm = service_realm;
3264 : }
3265 : }
3266 : }
3267 :
3268 76177 : ok = lpcfg_is_my_domain_or_realm(kdc_db_ctx->lp_ctx, realm);
3269 76177 : if (ok) {
3270 : /*
3271 : * skip the expensive routing lookup
3272 : */
3273 53451 : TALLOC_FREE(frame);
3274 53451 : return 0;
3275 : }
3276 :
3277 22726 : status = dsdb_trust_routing_table_load(kdc_db_ctx->samdb,
3278 : frame, &trt);
3279 22726 : if (!NT_STATUS_IS_OK(status)) {
3280 0 : TALLOC_FREE(frame);
3281 0 : return EINVAL;
3282 : }
3283 :
3284 22726 : tdo = dsdb_trust_routing_by_name(trt, realm);
3285 22726 : if (tdo == NULL) {
3286 : /*
3287 : * This principal has to be local
3288 : */
3289 19016 : TALLOC_FREE(frame);
3290 19016 : return 0;
3291 : }
3292 :
3293 3710 : if (tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3294 : /*
3295 : * TODO: handle the routing within the forest
3296 : *
3297 : * This should likely be handled in
3298 : * samba_kdc_message2entry() in case we're
3299 : * a global catalog. We'd need to check
3300 : * if realm_dn is our own domain and derive
3301 : * the dns domain name from realm_dn and check that
3302 : * against the routing table or fallback to
3303 : * the tdo we found here.
3304 : *
3305 : * But for now we don't support multiple domains
3306 : * in our forest correctly anyway.
3307 : *
3308 : * Just search in our local database.
3309 : */
3310 2020 : TALLOC_FREE(frame);
3311 2020 : return 0;
3312 : }
3313 :
3314 1690 : ret = krb5_copy_principal(context, principal,
3315 : &entry->principal);
3316 1690 : if (ret) {
3317 0 : TALLOC_FREE(frame);
3318 0 : return ret;
3319 : }
3320 :
3321 1690 : upper = strupper_talloc(frame, tdo->domain_name.string);
3322 1690 : if (upper == NULL) {
3323 0 : TALLOC_FREE(frame);
3324 0 : return ENOMEM;
3325 : }
3326 :
3327 1690 : ret = smb_krb5_principal_set_realm(context,
3328 : entry->principal,
3329 : upper);
3330 1690 : if (ret) {
3331 0 : TALLOC_FREE(frame);
3332 0 : return ret;
3333 : }
3334 :
3335 1690 : TALLOC_FREE(frame);
3336 1690 : return SDB_ERR_WRONG_REALM;
3337 : }
3338 :
3339 312352 : krb5_error_code samba_kdc_fetch(krb5_context context,
3340 : struct samba_kdc_db_context *kdc_db_ctx,
3341 : krb5_const_principal principal,
3342 : unsigned flags,
3343 : krb5_kvno kvno,
3344 : struct sdb_entry *entry)
3345 : {
3346 312352 : krb5_error_code ret = SDB_ERR_NOENTRY;
3347 10240 : TALLOC_CTX *mem_ctx;
3348 :
3349 312352 : mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
3350 312352 : if (!mem_ctx) {
3351 0 : ret = ENOMEM;
3352 0 : krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
3353 0 : return ret;
3354 : }
3355 :
3356 312352 : ret = samba_kdc_lookup_realm(context, kdc_db_ctx,
3357 : principal, flags, entry);
3358 312352 : if (ret != 0) {
3359 1691 : goto done;
3360 : }
3361 :
3362 310661 : ret = SDB_ERR_NOENTRY;
3363 :
3364 310661 : if (flags & SDB_F_GET_CLIENT) {
3365 101998 : ret = samba_kdc_fetch_client(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry);
3366 101998 : if (ret != SDB_ERR_NOENTRY) goto done;
3367 : }
3368 209173 : if (flags & SDB_F_GET_SERVER) {
3369 : /* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
3370 100159 : ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry);
3371 100159 : if (ret != SDB_ERR_NOENTRY) goto done;
3372 :
3373 : /* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
3374 28824 : ret = samba_kdc_fetch_server(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry);
3375 28824 : if (ret != SDB_ERR_NOENTRY) goto done;
3376 : }
3377 110261 : if (flags & SDB_F_GET_KRBTGT) {
3378 108508 : ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry);
3379 108508 : if (ret != SDB_ERR_NOENTRY) goto done;
3380 : }
3381 :
3382 1757 : done:
3383 312352 : talloc_free(mem_ctx);
3384 312352 : return ret;
3385 : }
3386 :
3387 : struct samba_kdc_seq {
3388 : unsigned int index;
3389 : unsigned int count;
3390 : struct ldb_message **msgs;
3391 : enum trust_direction trust_direction;
3392 : unsigned int trust_index;
3393 : unsigned int trust_count;
3394 : struct ldb_message **trust_msgs;
3395 : struct ldb_dn *realm_dn;
3396 : };
3397 :
3398 136 : static krb5_error_code samba_kdc_seq(krb5_context context,
3399 : struct samba_kdc_db_context *kdc_db_ctx,
3400 : const unsigned sdb_flags,
3401 : struct sdb_entry *entry)
3402 : {
3403 0 : krb5_error_code ret;
3404 136 : struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
3405 136 : const char *realm = lpcfg_realm(kdc_db_ctx->lp_ctx);
3406 136 : struct ldb_message *msg = NULL;
3407 136 : const char *sAMAccountName = NULL;
3408 136 : krb5_principal principal = NULL;
3409 0 : TALLOC_CTX *mem_ctx;
3410 :
3411 136 : if (!priv) {
3412 0 : return SDB_ERR_NOENTRY;
3413 : }
3414 :
3415 136 : mem_ctx = talloc_named(priv, 0, "samba_kdc_seq context");
3416 :
3417 136 : if (!mem_ctx) {
3418 0 : ret = ENOMEM;
3419 0 : krb5_set_error_message(context, ret, "samba_kdc_seq: talloc_named() failed!");
3420 0 : goto out;
3421 : }
3422 :
3423 136 : if (priv->index == priv->count) {
3424 10 : goto trusts;
3425 : }
3426 :
3427 126 : while (priv->index < priv->count) {
3428 126 : msg = priv->msgs[priv->index++];
3429 :
3430 126 : sAMAccountName = ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL);
3431 126 : if (sAMAccountName != NULL) {
3432 126 : break;
3433 : }
3434 : }
3435 :
3436 126 : if (sAMAccountName == NULL) {
3437 : /*
3438 : * This is not really possible,
3439 : * but instead returning
3440 : * SDB_ERR_NOENTRY, we
3441 : * go on with trusts
3442 : */
3443 0 : goto trusts;
3444 : }
3445 :
3446 126 : ret = smb_krb5_make_principal(context, &principal,
3447 : realm, sAMAccountName, NULL);
3448 126 : if (ret != 0) {
3449 0 : goto out;
3450 : }
3451 :
3452 126 : ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
3453 : principal, SAMBA_KDC_ENT_TYPE_ANY,
3454 : sdb_flags|SDB_F_GET_ANY,
3455 : 0 /* kvno */,
3456 : priv->realm_dn, msg, entry);
3457 126 : krb5_free_principal(context, principal);
3458 :
3459 136 : out:
3460 136 : if (ret != 0) {
3461 10 : TALLOC_FREE(priv);
3462 10 : kdc_db_ctx->seq_ctx = NULL;
3463 : } else {
3464 126 : talloc_free(mem_ctx);
3465 : }
3466 :
3467 136 : return ret;
3468 :
3469 10 : trusts:
3470 10 : while (priv->trust_index < priv->trust_count) {
3471 0 : enum trust_direction trust_direction = priv->trust_direction;
3472 :
3473 0 : msg = priv->trust_msgs[priv->trust_index];
3474 :
3475 0 : if (trust_direction == INBOUND) {
3476 : /*
3477 : * This time we try INBOUND keys,
3478 : * next time we'll do OUTBOUND
3479 : * for the same trust.
3480 : */
3481 0 : priv->trust_direction = OUTBOUND;
3482 :
3483 : /*
3484 : * samba_kdc_trust_message2entry()
3485 : * will likely steal msg from us,
3486 : * so we need to make a copy for
3487 : * the first run with INBOUND,
3488 : * and let it steal without
3489 : * a copy in the OUTBOUND run.
3490 : */
3491 0 : msg = ldb_msg_copy(priv->trust_msgs, msg);
3492 0 : if (msg == NULL) {
3493 0 : return ENOMEM;
3494 : }
3495 : } else {
3496 : /*
3497 : * This time we try OUTBOUND keys,
3498 : * next time we'll do INBOUND for
3499 : * the next trust.
3500 : */
3501 0 : priv->trust_direction = INBOUND;
3502 0 : priv->trust_index++;
3503 : }
3504 :
3505 0 : ret = samba_kdc_trust_message2entry(context,
3506 : kdc_db_ctx,
3507 : mem_ctx,
3508 : trust_direction,
3509 : priv->realm_dn,
3510 : sdb_flags|SDB_F_GET_ANY,
3511 : 0, /* kvno */
3512 : msg,
3513 : entry);
3514 0 : if (ret == SDB_ERR_NOENTRY) {
3515 0 : continue;
3516 : }
3517 0 : goto out;
3518 : }
3519 :
3520 10 : ret = SDB_ERR_NOENTRY;
3521 10 : goto out;
3522 : }
3523 :
3524 10 : krb5_error_code samba_kdc_firstkey(krb5_context context,
3525 : struct samba_kdc_db_context *kdc_db_ctx,
3526 : const unsigned sdb_flags,
3527 : struct sdb_entry *entry)
3528 : {
3529 10 : struct ldb_context *ldb_ctx = kdc_db_ctx->samdb;
3530 10 : struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
3531 0 : char *realm;
3532 10 : struct ldb_result *res = NULL;
3533 0 : krb5_error_code ret;
3534 0 : int lret;
3535 0 : NTSTATUS status;
3536 :
3537 10 : if (priv) {
3538 0 : TALLOC_FREE(priv);
3539 0 : kdc_db_ctx->seq_ctx = NULL;
3540 : }
3541 :
3542 10 : priv = talloc_zero(kdc_db_ctx, struct samba_kdc_seq);
3543 10 : if (!priv) {
3544 0 : ret = ENOMEM;
3545 0 : krb5_set_error_message(context, ret, "talloc: out of memory");
3546 0 : return ret;
3547 : }
3548 :
3549 10 : priv->realm_dn = ldb_get_default_basedn(ldb_ctx);
3550 :
3551 10 : ret = krb5_get_default_realm(context, &realm);
3552 10 : if (ret != 0) {
3553 0 : TALLOC_FREE(priv);
3554 0 : return ret;
3555 : }
3556 10 : krb5_free_default_realm(context, realm);
3557 :
3558 10 : lret = dsdb_search(ldb_ctx, priv, &res,
3559 : priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs,
3560 : DSDB_SEARCH_NO_GLOBAL_CATALOG | DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS,
3561 : "(objectClass=user)");
3562 :
3563 10 : if (lret != LDB_SUCCESS) {
3564 0 : TALLOC_FREE(priv);
3565 0 : return SDB_ERR_NOENTRY;
3566 : }
3567 :
3568 10 : priv->count = res->count;
3569 10 : priv->msgs = talloc_move(priv, &res->msgs);
3570 10 : TALLOC_FREE(res);
3571 :
3572 10 : status = dsdb_trust_search_tdos(ldb_ctx,
3573 : NULL, /* exclude */
3574 : trust_attrs,
3575 : priv,
3576 : &res);
3577 10 : if (!NT_STATUS_IS_OK(status)) {
3578 0 : DBG_ERR("dsdb_trust_search_tdos() - %s\n",
3579 : nt_errstr(status));
3580 0 : TALLOC_FREE(priv);
3581 0 : return SDB_ERR_NOENTRY;
3582 : }
3583 :
3584 10 : priv->trust_direction = INBOUND;
3585 10 : priv->trust_count = res->count;
3586 10 : priv->trust_msgs = talloc_move(priv, &res->msgs);
3587 10 : TALLOC_FREE(res);
3588 :
3589 10 : kdc_db_ctx->seq_ctx = priv;
3590 :
3591 10 : ret = samba_kdc_seq(context, kdc_db_ctx, sdb_flags, entry);
3592 :
3593 10 : if (ret != 0) {
3594 0 : TALLOC_FREE(priv);
3595 0 : kdc_db_ctx->seq_ctx = NULL;
3596 : }
3597 10 : return ret;
3598 : }
3599 :
3600 126 : krb5_error_code samba_kdc_nextkey(krb5_context context,
3601 : struct samba_kdc_db_context *kdc_db_ctx,
3602 : const unsigned sdb_flags,
3603 : struct sdb_entry *entry)
3604 : {
3605 126 : return samba_kdc_seq(context, kdc_db_ctx, sdb_flags, entry);
3606 : }
3607 :
3608 : /* Check if a given entry may delegate or do s4u2self to this target principal
3609 : *
3610 : * The safest way to determine 'self' is to check the DB record made at
3611 : * the time the principal was presented to the KDC.
3612 : */
3613 : krb5_error_code
3614 950 : samba_kdc_check_client_matches_target_service(krb5_context context,
3615 : struct samba_kdc_entry *skdc_entry_client,
3616 : struct samba_kdc_entry *skdc_entry_server_target)
3617 : {
3618 0 : struct dom_sid *orig_sid;
3619 0 : struct dom_sid *target_sid;
3620 950 : TALLOC_CTX *frame = talloc_stackframe();
3621 :
3622 950 : orig_sid = samdb_result_dom_sid(frame,
3623 950 : skdc_entry_client->msg,
3624 : "objectSid");
3625 950 : target_sid = samdb_result_dom_sid(frame,
3626 950 : skdc_entry_server_target->msg,
3627 : "objectSid");
3628 :
3629 : /*
3630 : * Allow delegation to the same record (representing a
3631 : * principal), even if by a different name. The easy and safe
3632 : * way to prove this is by SID comparison
3633 : */
3634 950 : if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
3635 6 : talloc_free(frame);
3636 6 : return KRB5KRB_AP_ERR_BADMATCH;
3637 : }
3638 :
3639 944 : talloc_free(frame);
3640 944 : return 0;
3641 : }
3642 :
3643 : /* Certificates printed by the Certificate Authority might have a
3644 : * slightly different form of the user principal name to that in the
3645 : * database. Allow a mismatch where they both refer to the same
3646 : * SID */
3647 :
3648 : krb5_error_code
3649 47 : samba_kdc_check_pkinit_ms_upn_match(krb5_context context,
3650 : struct samba_kdc_db_context *kdc_db_ctx,
3651 : struct samba_kdc_entry *skdc_entry,
3652 : krb5_const_principal certificate_principal)
3653 : {
3654 0 : krb5_error_code ret;
3655 0 : struct ldb_dn *realm_dn;
3656 0 : struct ldb_message *msg;
3657 0 : struct dom_sid *orig_sid;
3658 0 : struct dom_sid *target_sid;
3659 47 : const char *ms_upn_check_attrs[] = {
3660 : "objectSid", NULL
3661 : };
3662 :
3663 47 : TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_pkinit_ms_upn_match");
3664 :
3665 47 : if (!mem_ctx) {
3666 0 : ret = ENOMEM;
3667 0 : krb5_set_error_message(context, ret, "samba_kdc_check_pkinit_ms_upn_match: talloc_named() failed!");
3668 0 : return ret;
3669 : }
3670 :
3671 47 : ret = samba_kdc_lookup_client(context, kdc_db_ctx,
3672 : mem_ctx, certificate_principal,
3673 : ms_upn_check_attrs, 0, &realm_dn, &msg);
3674 :
3675 47 : if (ret != 0) {
3676 0 : talloc_free(mem_ctx);
3677 0 : return ret;
3678 : }
3679 :
3680 47 : orig_sid = samdb_result_dom_sid(mem_ctx, skdc_entry->msg, "objectSid");
3681 47 : target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
3682 :
3683 : /* Consider these to be the same principal, even if by a different
3684 : * name. The easy and safe way to prove this is by SID
3685 : * comparison */
3686 47 : if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
3687 2 : talloc_free(mem_ctx);
3688 : #if defined(KRB5KDC_ERR_CLIENT_NAME_MISMATCH) /* MIT */
3689 0 : return KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
3690 : #else /* Heimdal (where this is an enum) */
3691 2 : return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
3692 : #endif
3693 : }
3694 :
3695 45 : talloc_free(mem_ctx);
3696 45 : return ret;
3697 : }
3698 :
3699 : /*
3700 : * Check if a given entry may delegate to this target principal
3701 : * with S4U2Proxy.
3702 : */
3703 : krb5_error_code
3704 146 : samba_kdc_check_s4u2proxy(krb5_context context,
3705 : struct samba_kdc_db_context *kdc_db_ctx,
3706 : struct samba_kdc_entry *skdc_entry,
3707 : krb5_const_principal target_principal)
3708 : {
3709 0 : krb5_error_code ret;
3710 146 : char *tmp = NULL;
3711 146 : const char *client_dn = NULL;
3712 146 : const char *target_principal_name = NULL;
3713 0 : struct ldb_message_element *el;
3714 0 : struct ldb_val val;
3715 0 : unsigned int i;
3716 146 : bool found = false;
3717 :
3718 146 : TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2proxy");
3719 :
3720 146 : if (!mem_ctx) {
3721 0 : ret = ENOMEM;
3722 0 : krb5_set_error_message(context, ret,
3723 : "samba_kdc_check_s4u2proxy:"
3724 : " talloc_named() failed!");
3725 0 : return ret;
3726 : }
3727 :
3728 146 : client_dn = ldb_dn_get_linearized(skdc_entry->msg->dn);
3729 146 : if (!client_dn) {
3730 0 : if (errno == 0) {
3731 0 : errno = ENOMEM;
3732 : }
3733 0 : ret = errno;
3734 0 : krb5_set_error_message(context, ret,
3735 : "samba_kdc_check_s4u2proxy:"
3736 : " ldb_dn_get_linearized() failed!");
3737 0 : talloc_free(mem_ctx);
3738 0 : return ret;
3739 : }
3740 :
3741 146 : el = ldb_msg_find_element(skdc_entry->msg, "msDS-AllowedToDelegateTo");
3742 146 : if (el == NULL) {
3743 29 : ret = ENOENT;
3744 29 : goto bad_option;
3745 : }
3746 117 : SMB_ASSERT(el->num_values != 0);
3747 :
3748 : /*
3749 : * This is the Microsoft forwardable flag behavior.
3750 : *
3751 : * If the proxy (target) principal is NULL, and we have any authorized
3752 : * delegation target, allow to forward.
3753 : */
3754 117 : if (target_principal == NULL) {
3755 0 : talloc_free(mem_ctx);
3756 0 : return 0;
3757 : }
3758 :
3759 :
3760 : /*
3761 : * The main heimdal code already checked that the target_principal
3762 : * belongs to the same realm as the client.
3763 : *
3764 : * So we just need the principal without the realm,
3765 : * as that is what is configured in the "msDS-AllowedToDelegateTo"
3766 : * attribute.
3767 : */
3768 117 : ret = krb5_unparse_name_flags(context, target_principal,
3769 : KRB5_PRINCIPAL_UNPARSE_NO_REALM, &tmp);
3770 117 : if (ret) {
3771 0 : talloc_free(mem_ctx);
3772 0 : krb5_set_error_message(context, ret,
3773 : "samba_kdc_check_s4u2proxy:"
3774 : " krb5_unparse_name_flags() failed!");
3775 0 : return ret;
3776 : }
3777 117 : DBG_DEBUG("client[%s] for target[%s]\n",
3778 : client_dn, tmp);
3779 :
3780 117 : target_principal_name = talloc_strdup(mem_ctx, tmp);
3781 117 : SAFE_FREE(tmp);
3782 117 : if (target_principal_name == NULL) {
3783 0 : ret = ENOMEM;
3784 0 : krb5_set_error_message(context, ret,
3785 : "samba_kdc_check_s4u2proxy:"
3786 : " talloc_strdup() failed!");
3787 0 : talloc_free(mem_ctx);
3788 0 : return ret;
3789 : }
3790 :
3791 117 : val = data_blob_string_const(target_principal_name);
3792 :
3793 118 : for (i=0; i<el->num_values; i++) {
3794 117 : struct ldb_val *val1 = &val;
3795 117 : struct ldb_val *val2 = &el->values[i];
3796 0 : int cmp;
3797 :
3798 117 : if (val1->length != val2->length) {
3799 1 : continue;
3800 : }
3801 :
3802 116 : cmp = strncasecmp((const char *)val1->data,
3803 116 : (const char *)val2->data,
3804 : val1->length);
3805 116 : if (cmp != 0) {
3806 0 : continue;
3807 : }
3808 :
3809 116 : found = true;
3810 116 : break;
3811 : }
3812 :
3813 117 : if (!found) {
3814 1 : ret = ENOENT;
3815 1 : goto bad_option;
3816 : }
3817 :
3818 116 : DBG_DEBUG("client[%s] allowed target[%s]\n",
3819 : client_dn, target_principal_name);
3820 116 : talloc_free(mem_ctx);
3821 116 : return 0;
3822 :
3823 30 : bad_option:
3824 30 : krb5_set_error_message(context, ret,
3825 : "samba_kdc_check_s4u2proxy: client[%s] "
3826 : "not allowed for delegation to target[%s]",
3827 : client_dn,
3828 : target_principal_name);
3829 30 : talloc_free(mem_ctx);
3830 30 : return KRB5KDC_ERR_BADOPTION;
3831 : }
3832 :
3833 : /*
3834 : * This method is called for S4U2Proxy requests and implements the
3835 : * resource-based constrained delegation variant, which can support
3836 : * cross-realm delegation.
3837 : */
3838 136 : krb5_error_code samba_kdc_check_s4u2proxy_rbcd(
3839 : krb5_context context,
3840 : struct samba_kdc_db_context *kdc_db_ctx,
3841 : krb5_const_principal client_principal,
3842 : krb5_const_principal server_principal,
3843 : const struct auth_user_info_dc *user_info_dc,
3844 : const struct auth_user_info_dc *device_info_dc,
3845 : const struct auth_claims auth_claims,
3846 : struct samba_kdc_entry *proxy_skdc_entry)
3847 : {
3848 0 : krb5_error_code code;
3849 0 : enum ndr_err_code ndr_err;
3850 136 : char *client_name = NULL;
3851 136 : char *server_name = NULL;
3852 136 : const char *proxy_dn = NULL;
3853 136 : const DATA_BLOB *data = NULL;
3854 136 : struct security_descriptor *rbcd_security_descriptor = NULL;
3855 136 : struct security_token *security_token = NULL;
3856 136 : uint32_t session_info_flags =
3857 : AUTH_SESSION_INFO_DEFAULT_GROUPS |
3858 : AUTH_SESSION_INFO_DEVICE_DEFAULT_GROUPS |
3859 : AUTH_SESSION_INFO_SIMPLE_PRIVILEGES |
3860 : AUTH_SESSION_INFO_FORCE_COMPOUNDED_AUTHENTICATION;
3861 : /*
3862 : * Testing shows that although Windows grants SEC_ADS_GENERIC_ALL access
3863 : * in security descriptors it creates for RBCD, its KDC only requires
3864 : * SEC_ADS_CONTROL_ACCESS for the access check to succeed.
3865 : */
3866 136 : uint32_t access_desired = SEC_ADS_CONTROL_ACCESS;
3867 136 : uint32_t access_granted = 0;
3868 0 : NTSTATUS nt_status;
3869 136 : TALLOC_CTX *mem_ctx = NULL;
3870 :
3871 136 : mem_ctx = talloc_named(kdc_db_ctx,
3872 : 0,
3873 : "samba_kdc_check_s4u2proxy_rbcd");
3874 136 : if (mem_ctx == NULL) {
3875 0 : errno = ENOMEM;
3876 0 : code = errno;
3877 :
3878 0 : return code;
3879 : }
3880 :
3881 136 : proxy_dn = ldb_dn_get_linearized(proxy_skdc_entry->msg->dn);
3882 136 : if (proxy_dn == NULL) {
3883 0 : DBG_ERR("ldb_dn_get_linearized failed for proxy_dn!\n");
3884 0 : if (errno == 0) {
3885 0 : errno = ENOMEM;
3886 : }
3887 0 : code = errno;
3888 :
3889 0 : goto out;
3890 : }
3891 :
3892 136 : rbcd_security_descriptor = talloc_zero(mem_ctx,
3893 : struct security_descriptor);
3894 136 : if (rbcd_security_descriptor == NULL) {
3895 0 : errno = ENOMEM;
3896 0 : code = errno;
3897 :
3898 0 : goto out;
3899 : }
3900 :
3901 136 : code = krb5_unparse_name_flags(context,
3902 : client_principal,
3903 : KRB5_PRINCIPAL_UNPARSE_DISPLAY,
3904 : &client_name);
3905 136 : if (code != 0) {
3906 0 : DBG_ERR("Unable to parse client_principal!\n");
3907 0 : goto out;
3908 : }
3909 :
3910 136 : code = krb5_unparse_name_flags(context,
3911 : server_principal,
3912 : KRB5_PRINCIPAL_UNPARSE_DISPLAY,
3913 : &server_name);
3914 136 : if (code != 0) {
3915 0 : DBG_ERR("Unable to parse server_principal!\n");
3916 0 : goto out;
3917 : }
3918 :
3919 136 : DBG_INFO("Check delegation from client[%s] to server[%s] via "
3920 : "proxy[%s]\n",
3921 : client_name,
3922 : server_name,
3923 : proxy_dn);
3924 :
3925 136 : if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
3926 136 : session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
3927 : }
3928 :
3929 136 : if (device_info_dc != NULL && !(device_info_dc->info->user_flags & NETLOGON_GUEST)) {
3930 90 : session_info_flags |= AUTH_SESSION_INFO_DEVICE_AUTHENTICATED;
3931 : }
3932 :
3933 136 : nt_status = auth_generate_security_token(mem_ctx,
3934 : kdc_db_ctx->lp_ctx,
3935 : kdc_db_ctx->samdb,
3936 : user_info_dc,
3937 : device_info_dc,
3938 : auth_claims,
3939 : session_info_flags,
3940 : &security_token);
3941 136 : if (!NT_STATUS_IS_OK(nt_status)) {
3942 0 : code = map_errno_from_nt_status(nt_status);
3943 0 : goto out;
3944 : }
3945 :
3946 136 : data = ldb_msg_find_ldb_val(proxy_skdc_entry->msg,
3947 : "msDS-AllowedToActOnBehalfOfOtherIdentity");
3948 136 : if (data == NULL) {
3949 5 : DBG_WARNING("Could not find security descriptor "
3950 : "msDS-AllowedToActOnBehalfOfOtherIdentity in "
3951 : "proxy[%s]\n",
3952 : proxy_dn);
3953 5 : code = KRB5KDC_ERR_BADOPTION;
3954 5 : goto out;
3955 : }
3956 :
3957 131 : ndr_err = ndr_pull_struct_blob(
3958 : data,
3959 : mem_ctx,
3960 : rbcd_security_descriptor,
3961 : (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
3962 131 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3963 0 : errno = ndr_map_error2errno(ndr_err);
3964 0 : DBG_ERR("Failed to unmarshall "
3965 : "msDS-AllowedToActOnBehalfOfOtherIdentity "
3966 : "security descriptor of proxy[%s]\n",
3967 : proxy_dn);
3968 0 : code = KRB5KDC_ERR_BADOPTION;
3969 0 : goto out;
3970 : }
3971 :
3972 131 : if (DEBUGLEVEL >= 10) {
3973 0 : NDR_PRINT_DEBUG(security_token, security_token);
3974 0 : NDR_PRINT_DEBUG(security_descriptor, rbcd_security_descriptor);
3975 : }
3976 :
3977 131 : nt_status = sec_access_check_ds(rbcd_security_descriptor,
3978 : security_token,
3979 : access_desired,
3980 : &access_granted,
3981 : NULL,
3982 : NULL);
3983 :
3984 131 : if (!NT_STATUS_IS_OK(nt_status)) {
3985 22 : DBG_WARNING("RBCD: sec_access_check_ds(access_desired=%#08x, "
3986 : "access_granted:%#08x) failed with: %s\n",
3987 : access_desired,
3988 : access_granted,
3989 : nt_errstr(nt_status));
3990 :
3991 22 : code = KRB5KDC_ERR_BADOPTION;
3992 22 : goto out;
3993 : }
3994 :
3995 109 : DBG_NOTICE("RBCD: Access granted for client[%s]\n", client_name);
3996 :
3997 109 : code = 0;
3998 136 : out:
3999 136 : SAFE_FREE(client_name);
4000 136 : SAFE_FREE(server_name);
4001 :
4002 136 : TALLOC_FREE(mem_ctx);
4003 136 : return code;
4004 : }
4005 :
4006 259 : NTSTATUS samba_kdc_setup_db_ctx(TALLOC_CTX *mem_ctx, struct samba_kdc_base_context *base_ctx,
4007 : struct samba_kdc_db_context **kdc_db_ctx_out)
4008 : {
4009 8 : int ldb_ret;
4010 259 : struct ldb_message *msg = NULL;
4011 259 : struct samba_kdc_db_context *kdc_db_ctx = NULL;
4012 : /* The idea here is very simple. Using Kerberos to
4013 : * authenticate the KDC to the LDAP server is highly likely to
4014 : * be circular.
4015 : *
4016 : * In future we may set this up to use EXTERNAL and SSL
4017 : * certificates, for now it will almost certainly be NTLMSSP_SET_USERNAME
4018 : */
4019 :
4020 259 : kdc_db_ctx = talloc_zero(mem_ctx, struct samba_kdc_db_context);
4021 259 : if (kdc_db_ctx == NULL) {
4022 0 : return NT_STATUS_NO_MEMORY;
4023 : }
4024 259 : kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
4025 259 : kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
4026 259 : kdc_db_ctx->msg_ctx = base_ctx->msg_ctx;
4027 :
4028 : /* get default kdc policy */
4029 259 : lpcfg_default_kdc_policy(mem_ctx,
4030 : base_ctx->lp_ctx,
4031 : &kdc_db_ctx->policy.svc_tkt_lifetime,
4032 : &kdc_db_ctx->policy.usr_tkt_lifetime,
4033 : &kdc_db_ctx->policy.renewal_lifetime);
4034 :
4035 : /* This is to allow "samba-tool domain exportkeytab to take a -H */
4036 259 : if (base_ctx->samdb != NULL) {
4037 : /*
4038 : * Caller is responsible for lifetimes. In reality
4039 : * the whole thing is destroyed before leaving the
4040 : * function the samdb was passed into
4041 : */
4042 24 : kdc_db_ctx->samdb = base_ctx->samdb;
4043 : } else {
4044 235 : struct auth_session_info *session_info = NULL;
4045 235 : session_info = system_session(kdc_db_ctx->lp_ctx);
4046 235 : if (session_info == NULL) {
4047 0 : talloc_free(kdc_db_ctx);
4048 0 : return NT_STATUS_INTERNAL_ERROR;
4049 : }
4050 :
4051 : /* Setup the link to LDB */
4052 235 : kdc_db_ctx->samdb = samdb_connect(kdc_db_ctx,
4053 : base_ctx->ev_ctx,
4054 : base_ctx->lp_ctx,
4055 : session_info,
4056 : NULL,
4057 : 0);
4058 235 : if (kdc_db_ctx->samdb == NULL) {
4059 0 : DBG_WARNING("Cannot open samdb for KDC backend!\n");
4060 0 : talloc_free(kdc_db_ctx);
4061 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
4062 : }
4063 : }
4064 :
4065 : /* Find out our own krbtgt kvno */
4066 259 : ldb_ret = samdb_rodc(kdc_db_ctx->samdb, &kdc_db_ctx->rodc);
4067 259 : if (ldb_ret != LDB_SUCCESS) {
4068 0 : DBG_WARNING("Cannot determine if we are an RODC in KDC backend: %s\n",
4069 : ldb_errstring(kdc_db_ctx->samdb));
4070 0 : talloc_free(kdc_db_ctx);
4071 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
4072 : }
4073 259 : if (kdc_db_ctx->rodc) {
4074 0 : int my_krbtgt_number;
4075 1 : const char *secondary_keytab[] = { "msDS-SecondaryKrbTgtNumber", NULL };
4076 1 : struct ldb_dn *account_dn = NULL;
4077 1 : struct ldb_dn *server_dn = samdb_server_dn(kdc_db_ctx->samdb, kdc_db_ctx);
4078 1 : if (!server_dn) {
4079 0 : DBG_WARNING("Cannot determine server DN in KDC backend: %s\n",
4080 : ldb_errstring(kdc_db_ctx->samdb));
4081 0 : talloc_free(kdc_db_ctx);
4082 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
4083 : }
4084 :
4085 1 : ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, server_dn,
4086 : "serverReference", &account_dn);
4087 1 : if (ldb_ret != LDB_SUCCESS) {
4088 0 : DBG_WARNING("Cannot determine server account in KDC backend: %s\n",
4089 : ldb_errstring(kdc_db_ctx->samdb));
4090 0 : talloc_free(kdc_db_ctx);
4091 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
4092 : }
4093 :
4094 1 : ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, account_dn,
4095 : "msDS-KrbTgtLink", &kdc_db_ctx->krbtgt_dn);
4096 1 : talloc_free(account_dn);
4097 1 : if (ldb_ret != LDB_SUCCESS) {
4098 0 : DBG_WARNING("Cannot determine RODC krbtgt account in KDC backend: %s\n",
4099 : ldb_errstring(kdc_db_ctx->samdb));
4100 0 : talloc_free(kdc_db_ctx);
4101 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
4102 : }
4103 :
4104 1 : ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
4105 : &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
4106 : secondary_keytab,
4107 : DSDB_SEARCH_NO_GLOBAL_CATALOG,
4108 : "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=*))");
4109 1 : if (ldb_ret != LDB_SUCCESS) {
4110 0 : DBG_WARNING("Cannot read krbtgt account %s in KDC backend to get msDS-SecondaryKrbTgtNumber: %s: %s\n",
4111 : ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
4112 : ldb_errstring(kdc_db_ctx->samdb),
4113 : ldb_strerror(ldb_ret));
4114 0 : talloc_free(kdc_db_ctx);
4115 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
4116 : }
4117 1 : my_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
4118 1 : if (my_krbtgt_number == -1) {
4119 0 : DBG_WARNING("Cannot read msDS-SecondaryKrbTgtNumber from krbtgt account %s in KDC backend: got %d\n",
4120 : ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
4121 : my_krbtgt_number);
4122 0 : talloc_free(kdc_db_ctx);
4123 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
4124 : }
4125 1 : kdc_db_ctx->my_krbtgt_number = my_krbtgt_number;
4126 :
4127 : } else {
4128 258 : kdc_db_ctx->my_krbtgt_number = 0;
4129 258 : ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
4130 : &msg,
4131 : ldb_get_default_basedn(kdc_db_ctx->samdb),
4132 : LDB_SCOPE_SUBTREE,
4133 : krbtgt_attrs,
4134 : DSDB_SEARCH_NO_GLOBAL_CATALOG | DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS,
4135 : "(&(objectClass=user)(samAccountName=krbtgt))");
4136 :
4137 258 : if (ldb_ret != LDB_SUCCESS) {
4138 0 : DBG_WARNING("could not find own KRBTGT in DB: %s\n", ldb_errstring(kdc_db_ctx->samdb));
4139 0 : talloc_free(kdc_db_ctx);
4140 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
4141 : }
4142 258 : kdc_db_ctx->krbtgt_dn = talloc_steal(kdc_db_ctx, msg->dn);
4143 258 : kdc_db_ctx->my_krbtgt_number = 0;
4144 258 : talloc_free(msg);
4145 : }
4146 259 : *kdc_db_ctx_out = kdc_db_ctx;
4147 259 : return NT_STATUS_OK;
4148 : }
4149 :
4150 18843 : krb5_error_code dsdb_extract_aes_256_key(krb5_context context,
4151 : TALLOC_CTX *mem_ctx,
4152 : struct ldb_context *ldb,
4153 : const struct ldb_message *msg,
4154 : uint32_t user_account_control,
4155 : const uint32_t *kvno,
4156 : uint32_t *kvno_out,
4157 : DATA_BLOB *aes_256_key,
4158 : DATA_BLOB *salt)
4159 : {
4160 139 : krb5_error_code krb5_ret;
4161 139 : uint32_t supported_enctypes;
4162 18843 : unsigned flags = SDB_F_GET_CLIENT;
4163 18843 : struct sdb_entry sentry = {};
4164 :
4165 18843 : if (kvno != NULL) {
4166 658 : flags |= SDB_F_KVNO_SPECIFIED;
4167 : }
4168 :
4169 19331 : krb5_ret = samba_kdc_message2entry_keys(context,
4170 : mem_ctx,
4171 : ldb,
4172 : msg,
4173 : false, /* is_krbtgt */
4174 : false, /* is_rodc */
4175 : user_account_control,
4176 : SAMBA_KDC_ENT_TYPE_CLIENT,
4177 : flags,
4178 488 : (kvno != NULL) ? *kvno : 0,
4179 : &sentry,
4180 : ENC_HMAC_SHA1_96_AES256,
4181 : &supported_enctypes);
4182 18843 : if (krb5_ret != 0) {
4183 0 : const char *krb5_err = krb5_get_error_message(context, krb5_ret);
4184 :
4185 0 : DBG_ERR("Failed to parse supplementalCredentials "
4186 : "of %s with %s kvno using "
4187 : "ENCTYPE_HMAC_SHA1_96_AES256 "
4188 : "Kerberos Key: %s\n",
4189 : ldb_dn_get_linearized(msg->dn),
4190 : (kvno != NULL) ? "previous" : "current",
4191 : krb5_err != NULL ? krb5_err : "<unknown>");
4192 :
4193 0 : krb5_free_error_message(context, krb5_err);
4194 :
4195 0 : return krb5_ret;
4196 : }
4197 :
4198 18843 : if ((supported_enctypes & ENC_HMAC_SHA1_96_AES256) == 0 ||
4199 3071 : sentry.keys.len != 1) {
4200 15772 : DBG_INFO("Failed to find a ENCTYPE_HMAC_SHA1_96_AES256 "
4201 : "key in supplementalCredentials "
4202 : "of %s at KVNO %u (got %u keys, expected 1)\n",
4203 : ldb_dn_get_linearized(msg->dn),
4204 : sentry.kvno,
4205 : sentry.keys.len);
4206 15772 : sdb_entry_free(&sentry);
4207 15772 : return ENOENT;
4208 : }
4209 :
4210 3071 : if (sentry.keys.val[0].salt == NULL) {
4211 0 : DBG_INFO("Failed to find a salt in "
4212 : "supplementalCredentials "
4213 : "of %s at KVNO %u\n",
4214 : ldb_dn_get_linearized(msg->dn),
4215 : sentry.kvno);
4216 0 : sdb_entry_free(&sentry);
4217 0 : return ENOENT;
4218 : }
4219 :
4220 3071 : if (aes_256_key != NULL) {
4221 3071 : *aes_256_key = data_blob_talloc(mem_ctx,
4222 : KRB5_KEY_DATA(&sentry.keys.val[0].key),
4223 : KRB5_KEY_LENGTH(&sentry.keys.val[0].key));
4224 3071 : if (aes_256_key->data == NULL) {
4225 0 : sdb_entry_free(&sentry);
4226 0 : return ENOMEM;
4227 : }
4228 3071 : talloc_keep_secret(aes_256_key->data);
4229 : }
4230 :
4231 3071 : if (salt != NULL) {
4232 2711 : *salt = data_blob_talloc(mem_ctx,
4233 : sentry.keys.val[0].salt->salt.data,
4234 : sentry.keys.val[0].salt->salt.length);
4235 2711 : if (salt->data == NULL) {
4236 0 : sdb_entry_free(&sentry);
4237 0 : return ENOMEM;
4238 : }
4239 : }
4240 :
4241 3071 : if (kvno_out != NULL) {
4242 2689 : *kvno_out = sentry.kvno;
4243 : }
4244 :
4245 3071 : sdb_entry_free(&sentry);
4246 :
4247 3071 : return 0;
4248 : }
|