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