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 1669 : 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 1669 : tmp_ctx = talloc_new(mem_ctx);
97 1669 : if (tmp_ctx == NULL) {
98 0 : return;
99 : }
100 :
101 1669 : irpc_handle = irpc_binding_handle_by_name(tmp_ctx, msg_ctx,
102 : "dreplsrv",
103 : &ndr_table_irpc);
104 1669 : 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 1669 : r.in.user_dn = ldb_dn_get_linearized(user_dn);
111 1669 : 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 1669 : 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 1669 : talloc_free(req);
131 1669 : TALLOC_FREE(tmp_ctx);
132 : }
133 :
134 1473 : static time_t ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const char *attr, time_t default_val)
135 : {
136 1473 : const struct ldb_val *gentime = NULL;
137 0 : time_t t;
138 0 : int ret;
139 :
140 1473 : gentime = ldb_msg_find_ldb_val(msg, attr);
141 1473 : ret = ldb_val_to_time(gentime, &t);
142 1473 : if (ret) {
143 324 : return default_val;
144 : }
145 :
146 1149 : return t;
147 : }
148 :
149 300340 : static struct SDBFlags uf2SDBFlags(krb5_context context, uint32_t userAccountControl, enum samba_kdc_ent_type ent_type)
150 : {
151 300340 : struct SDBFlags flags = {};
152 :
153 : /* we don't allow kadmin deletes */
154 300340 : flags.immutable = 1;
155 :
156 : /* mark the principal as invalid to start with */
157 300340 : flags.invalid = 1;
158 :
159 300340 : flags.renewable = 1;
160 :
161 : /* All accounts are servers, but this may be disabled again in the caller */
162 300340 : flags.server = 1;
163 :
164 : /* Account types - clear the invalid bit if it turns out to be valid */
165 300340 : if (userAccountControl & UF_NORMAL_ACCOUNT) {
166 258550 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
167 83128 : flags.client = 1;
168 : }
169 249634 : flags.invalid = 0;
170 : }
171 :
172 300340 : 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 300340 : if (userAccountControl & UF_WORKSTATION_TRUST_ACCOUNT) {
179 13017 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
180 6519 : flags.client = 1;
181 : }
182 12743 : flags.invalid = 0;
183 : }
184 300340 : if (userAccountControl & UF_SERVER_TRUST_ACCOUNT) {
185 27232 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT || ent_type == SAMBA_KDC_ENT_TYPE_ANY) {
186 8406 : flags.client = 1;
187 : }
188 26280 : flags.invalid = 0;
189 : }
190 :
191 : /* Not permitted to act as a client if disabled */
192 300340 : if (userAccountControl & UF_ACCOUNTDISABLE) {
193 172979 : flags.client = 0;
194 : }
195 300340 : 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 300340 : 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 300340 : if (userAccountControl & UF_SMARTCARD_REQUIRED) {
218 53 : flags.require_hwauth = 1;
219 : }
220 300340 : if (userAccountControl & UF_TRUSTED_FOR_DELEGATION) {
221 21935 : flags.ok_as_delegate = 1;
222 : }
223 300340 : 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 3600 : flags.trusted_for_delegation = 1;
236 : }
237 300340 : if (!(userAccountControl & UF_NOT_DELEGATED)) {
238 300332 : flags.forwardable = 1;
239 300332 : flags.proxiable = 1;
240 : }
241 :
242 300340 : if (userAccountControl & UF_DONT_REQUIRE_PREAUTH) {
243 0 : flags.require_preauth = 0;
244 : } else {
245 300340 : flags.require_preauth = 1;
246 : }
247 :
248 300340 : if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
249 30 : flags.no_auth_data_reqd = 1;
250 : }
251 :
252 300340 : return flags;
253 : }
254 :
255 602709 : static int samba_kdc_entry_destructor(struct samba_kdc_entry *p)
256 : {
257 602709 : if (p->db_entry != NULL) {
258 : /*
259 : * A sdb_entry still has a reference
260 : */
261 0 : return -1;
262 : }
263 :
264 602709 : if (p->kdc_entry != NULL) {
265 : /*
266 : * hdb_entry or krb5_db_entry still
267 : * have a reference...
268 : */
269 301661 : return -1;
270 : }
271 :
272 290906 : 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 1077832 : 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 2415462 : for (i = 0; i < ARRAY_SIZE(etype_list); i++) {
304 2415462 : if (etype == etype_list[i]) {
305 1037340 : break;
306 : }
307 : }
308 :
309 1077832 : return ARRAY_SIZE(etype_list) - i;
310 : }
311 :
312 538916 : static int sdb_key_strength_cmp(const struct sdb_key *k1, const struct sdb_key *k2)
313 : {
314 538916 : int p1 = sdb_key_strength_priority(KRB5_KEY_TYPE(&k1->key));
315 538916 : int p2 = sdb_key_strength_priority(KRB5_KEY_TYPE(&k2->key));
316 :
317 538916 : if (p1 == p2) {
318 0 : return 0;
319 : }
320 :
321 538916 : if (p1 > p2) {
322 : /*
323 : * Higher priority comes first
324 : */
325 518670 : return -1;
326 : } else {
327 0 : return 1;
328 : }
329 : }
330 :
331 327745 : static void samba_kdc_sort_keys(struct sdb_keys *keys)
332 : {
333 327745 : if (keys == NULL) {
334 0 : return;
335 : }
336 :
337 327745 : 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 326596 : 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 326596 : uint32_t supported_enctypes = p->supported_enctypes &= ~(ENC_CRC32 | ENC_RSA_MD5);
456 326596 : uint32_t _available_enctypes = 0;
457 326596 : uint32_t *available_enctypes = p->available_enctypes;
458 326596 : uint32_t _returned_kvno = 0;
459 326596 : uint32_t *returned_kvno = p->returned_kvno;
460 326596 : uint32_t num_pkeys = p->num_pkeys;
461 326596 : uint32_t allocated_keys = num_pkeys;
462 10548 : uint32_t i;
463 10548 : int ret;
464 :
465 326596 : if (available_enctypes == NULL) {
466 7817 : available_enctypes = &_available_enctypes;
467 : }
468 :
469 326596 : *available_enctypes = 0;
470 :
471 326596 : if (returned_kvno == NULL) {
472 7817 : returned_kvno = &_returned_kvno;
473 : }
474 :
475 326596 : *returned_kvno = p->kvno;
476 :
477 326596 : if (p->nthash != NULL) {
478 297163 : allocated_keys += 1;
479 : }
480 :
481 326596 : allocated_keys = MAX(1, allocated_keys);
482 :
483 : /* allocate space to decode into */
484 326596 : p->skeys->len = 0;
485 326596 : p->skeys->val = calloc(allocated_keys, sizeof(struct sdb_key));
486 326596 : if (p->skeys->val == NULL) {
487 0 : return ENOMEM;
488 : }
489 :
490 1446196 : for (i=0; i < num_pkeys; i++) {
491 1119600 : struct sdb_key key = {};
492 40640 : uint32_t enctype_bit;
493 :
494 1119600 : if (p->pkeys[i].value == NULL) {
495 1119600 : continue;
496 : }
497 :
498 1119600 : enctype_bit = kerberos_enctype_to_bitmap(p->pkeys[i].keytype);
499 1119600 : if (!(enctype_bit & supported_enctypes)) {
500 570798 : continue;
501 : }
502 :
503 548802 : if (p->salt_string != NULL) {
504 20283 : DATA_BLOB salt;
505 :
506 548802 : salt = data_blob_string_const(p->salt_string);
507 :
508 548802 : key.salt = calloc(1, sizeof(*key.salt));
509 548802 : if (key.salt == NULL) {
510 0 : ret = ENOMEM;
511 0 : goto fail;
512 : }
513 :
514 548802 : key.salt->type = KRB5_PW_SALT;
515 :
516 569085 : ret = smb_krb5_copy_data_contents(&key.salt->salt,
517 548802 : salt.data,
518 : salt.length);
519 548802 : if (ret) {
520 0 : *key.salt = (struct sdb_salt) {};
521 0 : sdb_key_free(&key);
522 0 : goto fail;
523 : }
524 : }
525 :
526 569085 : ret = smb_krb5_keyblock_init_contents(context,
527 548802 : p->pkeys[i].keytype,
528 548802 : p->pkeys[i].value->data,
529 548802 : p->pkeys[i].value->length,
530 : &key.key);
531 548802 : if (ret == 0) {
532 548802 : p->skeys->val[p->skeys->len++] = key;
533 548802 : *available_enctypes |= enctype_bit;
534 548802 : 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 326596 : if (p->nthash != NULL && (supported_enctypes & ENC_RC4_HMAC_MD5)) {
549 292386 : struct sdb_key key = {};
550 :
551 302564 : ret = smb_krb5_keyblock_init_contents(context,
552 : ENCTYPE_ARCFOUR_HMAC,
553 292386 : p->nthash->hash,
554 : sizeof(p->nthash->hash),
555 : &key.key);
556 292386 : if (ret == 0) {
557 292386 : p->skeys->val[p->skeys->len++] = key;
558 :
559 292386 : *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 292386 : if (ret != 0) {
566 0 : goto fail;
567 : }
568 : }
569 :
570 326596 : samba_kdc_sort_keys(p->skeys);
571 :
572 326596 : return 0;
573 0 : fail:
574 0 : sdb_keys_free(p->skeys);
575 0 : return ret;
576 : }
577 :
578 318923 : 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 318923 : krb5_error_code ret = 0;
592 10281 : enum ndr_err_code ndr_err;
593 10281 : struct samr_Password *hash;
594 318923 : unsigned int num_ntPwdHistory = 0;
595 318923 : struct samr_Password *ntPwdHistory = NULL;
596 318923 : struct samr_Password *old_hash = NULL;
597 318923 : struct samr_Password *older_hash = NULL;
598 10281 : const struct ldb_val *sc_val;
599 10281 : struct supplementalCredentialsBlob scb;
600 318923 : struct supplementalCredentialsPackage *scpk = NULL;
601 10281 : struct package_PrimaryKerberosBlob _pkb;
602 318923 : struct package_PrimaryKerberosCtr4 *pkb4 = NULL;
603 318923 : int krbtgt_number = 0;
604 10281 : uint32_t current_kvno;
605 318923 : uint32_t old_kvno = 0;
606 318923 : uint32_t older_kvno = 0;
607 318923 : uint32_t returned_kvno = 0;
608 10281 : uint16_t i;
609 318923 : struct samba_kdc_user_keys keys = { .num_pkeys = 0, };
610 318923 : struct samba_kdc_user_keys old_keys = { .num_pkeys = 0, };
611 318923 : struct samba_kdc_user_keys older_keys = { .num_pkeys = 0, };
612 318923 : uint32_t available_enctypes = 0;
613 318923 : uint32_t supported_enctypes = supported_enctypes_in;
614 :
615 318923 : *supported_enctypes_out = 0;
616 :
617 : /* Is this the krbtgt or a RODC krbtgt */
618 318923 : if (is_rodc) {
619 7018 : krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
620 :
621 7018 : if (krbtgt_number == -1) {
622 0 : return EINVAL;
623 : }
624 7018 : if (krbtgt_number == 0) {
625 0 : return EINVAL;
626 : }
627 : }
628 :
629 318923 : 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 318884 : if ((ent_type == SAMBA_KDC_ENT_TYPE_CLIENT)
648 118174 : && (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 318831 : current_kvno = ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0);
659 318831 : if (current_kvno > 1) {
660 39343 : old_kvno = current_kvno - 1;
661 : }
662 318831 : if (current_kvno > 2) {
663 17657 : older_kvno = current_kvno - 2;
664 : }
665 318831 : 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 172969 : current_kvno = SAMBA_KVNO_GET_VALUE(current_kvno);
677 172969 : old_kvno = SAMBA_KVNO_GET_VALUE(old_kvno);
678 172969 : older_kvno = SAMBA_KVNO_GET_VALUE(older_kvno);
679 172969 : requested_kvno = SAMBA_KVNO_GET_VALUE(requested_kvno);
680 : }
681 :
682 : /* Get keys from the db */
683 :
684 318831 : hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
685 318831 : num_ntPwdHistory = samdb_result_hashes(mem_ctx, msg,
686 : "ntPwdHistory",
687 : &ntPwdHistory);
688 318831 : if (num_ntPwdHistory > 1) {
689 6153 : old_hash = &ntPwdHistory[1];
690 : }
691 318831 : if (num_ntPwdHistory > 2) {
692 3121 : older_hash = &ntPwdHistory[1];
693 : }
694 318831 : sc_val = ldb_msg_find_ldb_val(msg, "supplementalCredentials");
695 :
696 : /* supplementalCredentials if present */
697 318831 : if (sc_val) {
698 297403 : ndr_err = ndr_pull_struct_blob_all(sc_val, mem_ctx, &scb,
699 : (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
700 297403 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
701 0 : ret = EINVAL;
702 0 : goto out;
703 : }
704 :
705 297403 : 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 354244 : for (i=0; i < scb.sub.num_packages; i++) {
714 335297 : if (scb.sub.packages[i].name != NULL &&
715 335297 : strcmp("Primary:Kerberos-Newer-Keys", scb.sub.packages[i].name) == 0)
716 : {
717 278456 : scpk = &scb.sub.packages[i];
718 278456 : if (!scpk->data || !scpk->data[0]) {
719 0 : scpk = NULL;
720 0 : continue;
721 : }
722 268314 : 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 318692 : if (scpk) {
735 10142 : DATA_BLOB blob;
736 :
737 278456 : blob = strhex_to_data_blob(mem_ctx, scpk->data);
738 278456 : 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 278456 : ndr_err = ndr_pull_struct_blob(&blob, mem_ctx, &_pkb,
745 : (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
746 278456 : 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 278456 : 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 278456 : pkb4 = &_pkb.ctr.ctr4;
761 : }
762 :
763 318831 : keys = (struct samba_kdc_user_keys) {
764 : .kvno = current_kvno,
765 : .supported_enctypes = supported_enctypes,
766 : .nthash = hash,
767 318831 : .salt_string = pkb4 != NULL ? pkb4->salt.string : NULL,
768 : .num_pkeys = pkb4 != NULL ? pkb4->num_keys : 0,
769 318831 : .pkeys = pkb4 != NULL ? pkb4->keys : NULL,
770 : };
771 :
772 318831 : old_keys = (struct samba_kdc_user_keys) {
773 : .kvno = old_kvno,
774 : .supported_enctypes = supported_enctypes,
775 : .nthash = old_hash,
776 318831 : .salt_string = pkb4 != NULL ? pkb4->salt.string : NULL,
777 : .num_pkeys = pkb4 != NULL ? pkb4->num_old_keys : 0,
778 318831 : .pkeys = pkb4 != NULL ? pkb4->old_keys : NULL,
779 : };
780 318831 : older_keys = (struct samba_kdc_user_keys) {
781 : .kvno = older_kvno,
782 : .supported_enctypes = supported_enctypes,
783 : .nthash = older_hash,
784 308550 : .salt_string = pkb4 != NULL ? pkb4->salt.string : NULL,
785 : .num_pkeys = pkb4 != NULL ? pkb4->num_older_keys : 0,
786 318831 : .pkeys = pkb4 != NULL ? pkb4->older_keys : NULL,
787 : };
788 :
789 318831 : if (flags & SDB_F_KVNO_SPECIFIED) {
790 51017 : if (requested_kvno == keys.kvno) {
791 : /*
792 : * The current kvno was requested,
793 : * so we return it.
794 : */
795 50355 : keys.skeys = &entry->keys;
796 50355 : keys.available_enctypes = &available_enctypes;
797 50355 : keys.returned_kvno = &returned_kvno;
798 662 : } else if (requested_kvno == 0) {
799 : /*
800 : * don't return any keys
801 : */
802 610 : } else if (requested_kvno == old_keys.kvno) {
803 : /*
804 : * return the old keys as default keys
805 : * with the requested kvno.
806 : */
807 418 : old_keys.skeys = &entry->keys;
808 418 : old_keys.available_enctypes = &available_enctypes;
809 418 : old_keys.returned_kvno = &returned_kvno;
810 192 : } else if (requested_kvno == older_keys.kvno) {
811 : /*
812 : * return the older keys as default keys
813 : * with the requested kvno.
814 : */
815 192 : older_keys.skeys = &entry->keys;
816 192 : older_keys.available_enctypes = &available_enctypes;
817 192 : older_keys.returned_kvno = &returned_kvno;
818 : } else {
819 : /*
820 : * don't return any keys
821 : */
822 : }
823 : } else {
824 267814 : bool include_history = false;
825 :
826 267814 : if ((flags & SDB_F_GET_CLIENT) && (flags & SDB_F_FOR_AS_REQ)) {
827 48343 : include_history = true;
828 217716 : } else if (flags & SDB_F_ADMIN_DATA) {
829 162 : include_history = true;
830 : }
831 :
832 267814 : keys.skeys = &entry->keys;
833 267814 : keys.available_enctypes = &available_enctypes;
834 267814 : keys.returned_kvno = &returned_kvno;
835 :
836 267814 : if (include_history && old_keys.kvno != 0) {
837 6491 : old_keys.skeys = &entry->old_keys;
838 : }
839 267814 : if (include_history && older_keys.kvno != 0) {
840 1326 : older_keys.skeys = &entry->older_keys;
841 : }
842 : }
843 :
844 318831 : if (keys.skeys != NULL) {
845 318169 : ret = samba_kdc_fill_user_keys(context, &keys);
846 318169 : if (ret != 0) {
847 0 : goto out;
848 : }
849 : }
850 :
851 318831 : if (old_keys.skeys != NULL) {
852 6909 : ret = samba_kdc_fill_user_keys(context, &old_keys);
853 6909 : if (ret != 0) {
854 0 : goto out;
855 : }
856 : }
857 :
858 318831 : if (older_keys.skeys != NULL) {
859 1518 : ret = samba_kdc_fill_user_keys(context, &older_keys);
860 1518 : if (ret != 0) {
861 0 : goto out;
862 : }
863 : }
864 :
865 318831 : *supported_enctypes_out |= available_enctypes;
866 :
867 318831 : 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 172969 : returned_kvno = SAMBA_KVNO_AND_KRBTGT(returned_kvno, krbtgt_number);
879 : }
880 318831 : entry->kvno = returned_kvno;
881 :
882 308642 : out:
883 308642 : return ret;
884 : }
885 :
886 51190 : 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 50914 : 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 50914 : p = krb5_principal_get_comp_string(context, principal, component);
902 50914 : if (p == NULL) {
903 0 : return ENOENT;
904 : }
905 50914 : if (do_strcasecmp) {
906 109 : *eq = strcasecmp(p, string) == 0;
907 : } else {
908 50805 : *eq = strcmp(p, string) == 0;
909 : }
910 49256 : 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 51081 : 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 51081 : 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 299665 : 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 299665 : struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
1018 299665 : krb5_error_code code = 0;
1019 299665 : 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 299665 : if (!is_kadmin_changepw) {
1038 299408 : 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 42428 : code = smb_krb5_make_principal(context,
1045 : out_princ,
1046 : lpcfg_realm(lp_ctx),
1047 : "krbtgt",
1048 : lpcfg_realm(lp_ctx),
1049 : NULL);
1050 42428 : if (code != 0) {
1051 0 : return code;
1052 : }
1053 42428 : smb_krb5_principal_set_type(context,
1054 : *out_princ,
1055 : KRB5_NT_SRV_INST);
1056 :
1057 42428 : return 0;
1058 : }
1059 :
1060 256980 : if ((canon && flags & (SDB_F_FORCE_CANON|SDB_F_FOR_AS_REQ)) ||
1061 6686 : (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 51344 : code = smb_krb5_make_principal(context,
1073 : out_princ,
1074 : lpcfg_realm(lp_ctx),
1075 : samAccountName,
1076 : NULL);
1077 51344 : 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 205893 : code = krb5_copy_principal(context, in_princ, out_princ);
1086 205893 : 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 205893 : code = smb_krb5_principal_set_realm(context,
1097 : *out_princ,
1098 : lpcfg_realm(lp_ctx));
1099 :
1100 205893 : return code;
1101 : }
1102 :
1103 : /*
1104 : * Construct an hdb_entry from a directory entry.
1105 : */
1106 300340 : 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 300340 : TALLOC_CTX *tmp_ctx = NULL;
1118 300340 : 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 300340 : krb5_error_code ret = 0;
1122 300340 : krb5_boolean is_computer = FALSE;
1123 10142 : struct samba_kdc_entry *p;
1124 10142 : NTTIME acct_expiry;
1125 10142 : NTSTATUS status;
1126 300340 : bool protected_user = false;
1127 10142 : struct dom_sid sid;
1128 10142 : uint32_t rid;
1129 300340 : bool is_krbtgt = false;
1130 300340 : bool is_rodc = false;
1131 300340 : bool force_rc4 = lpcfg_kdc_force_enable_rc4_weak_session_keys(lp_ctx);
1132 10142 : struct ldb_message_element *objectclasses;
1133 300340 : struct ldb_val computer_val = data_blob_string_const("computer");
1134 300340 : uint32_t config_default_supported_enctypes = lpcfg_kdc_default_domain_supported_enctypes(lp_ctx);
1135 310482 : uint32_t default_supported_enctypes =
1136 : config_default_supported_enctypes != 0 ?
1137 300340 : config_default_supported_enctypes :
1138 : ENC_RC4_HMAC_MD5 | ENC_HMAC_SHA1_96_AES256_SK;
1139 10142 : uint32_t supported_enctypes
1140 300340 : = 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 300340 : uint32_t available_enctypes = 0;
1146 : /*
1147 : * also legacy enctypes are announced,
1148 : * but effectively restricted by kdc_enctypes
1149 : */
1150 300340 : uint32_t domain_enctypes = ENC_RC4_HMAC_MD5 | ENC_RSA_MD5 | ENC_CRC32;
1151 300340 : uint32_t config_kdc_enctypes = lpcfg_kdc_supported_enctypes(lp_ctx);
1152 310482 : uint32_t kdc_enctypes =
1153 : config_kdc_enctypes != 0 ?
1154 300340 : config_kdc_enctypes :
1155 : ENC_ALL_TYPES;
1156 300340 : const char *samAccountName = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
1157 :
1158 300340 : const struct authn_kerberos_client_policy *authn_client_policy = NULL;
1159 300340 : const struct authn_server_policy *authn_server_policy = NULL;
1160 10142 : int64_t enforced_tgt_lifetime_raw;
1161 300340 : const bool user2user = (flags & SDB_F_USER2USER_PRINCIPAL);
1162 :
1163 300340 : *entry = (struct sdb_entry) {};
1164 :
1165 300340 : tmp_ctx = talloc_new(mem_ctx);
1166 300340 : if (tmp_ctx == NULL) {
1167 0 : return ENOMEM;
1168 : }
1169 :
1170 300340 : if (supported_enctypes == 0) {
1171 0 : supported_enctypes = default_supported_enctypes;
1172 : }
1173 :
1174 300340 : if (dsdb_functional_level(kdc_db_ctx->samdb) >= DS_DOMAIN_FUNCTION_2008) {
1175 281493 : domain_enctypes |= ENC_HMAC_SHA1_96_AES128 | ENC_HMAC_SHA1_96_AES256;
1176 : }
1177 :
1178 300340 : if (ldb_msg_find_element(msg, "msDS-SecondaryKrbTgtNumber")) {
1179 7018 : is_rodc = true;
1180 : }
1181 :
1182 300340 : 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 300340 : objectclasses = ldb_msg_find_element(msg, "objectClass");
1189 :
1190 300340 : if (objectclasses && ldb_msg_find_val(objectclasses, &computer_val)) {
1191 40249 : is_computer = TRUE;
1192 : }
1193 :
1194 300340 : p = talloc_zero(tmp_ctx, struct samba_kdc_entry);
1195 300340 : if (!p) {
1196 0 : ret = ENOMEM;
1197 0 : goto out;
1198 : }
1199 :
1200 300340 : p->is_rodc = is_rodc;
1201 300340 : p->kdc_db_ctx = kdc_db_ctx;
1202 300340 : p->realm_dn = talloc_reference(p, realm_dn);
1203 300340 : if (!p->realm_dn) {
1204 0 : ret = ENOMEM;
1205 0 : goto out;
1206 : }
1207 :
1208 300340 : talloc_set_destructor(p, samba_kdc_entry_destructor);
1209 :
1210 300340 : entry->skdc_entry = p;
1211 :
1212 300340 : userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
1213 :
1214 10142 : msDS_User_Account_Control_Computed
1215 300340 : = 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 300340 : 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 300340 : userAccountControl |= msDS_User_Account_Control_Computed;
1232 : }
1233 :
1234 300340 : if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT) {
1235 172709 : p->is_krbtgt = true;
1236 : }
1237 :
1238 : /* First try and figure out the flags based on the userAccountControl */
1239 300340 : 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 300340 : 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 300340 : if (entry->flags.server && !user2user
1259 300301 : && lpcfg_parm_bool(lp_ctx, NULL, "kdc", "require spn for service", true)) {
1260 300301 : if (!is_computer && !ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL)) {
1261 88332 : 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 300340 : 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 300340 : 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 299665 : 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 162 : entry->created_by.time = ldb_msg_find_krb5time_ldap_time(msg, "whenCreated", 0);
1315 : /* use 'kadmin' for now (needed by mit_samba) */
1316 :
1317 162 : ret = smb_krb5_make_principal(context,
1318 : &entry->created_by.principal,
1319 : lpcfg_realm(lp_ctx), "kadmin", NULL);
1320 162 : if (ret) {
1321 0 : krb5_clear_error_message(context);
1322 0 : goto out;
1323 : }
1324 :
1325 162 : entry->modified_by = calloc(1, sizeof(struct sdb_event));
1326 162 : 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 162 : entry->modified_by->time = ldb_msg_find_krb5time_ldap_time(msg, "whenChanged", 0);
1334 : /* use 'kadmin' for now (needed by mit_samba) */
1335 162 : ret = smb_krb5_make_principal(context,
1336 162 : &entry->modified_by->principal,
1337 : lpcfg_realm(lp_ctx), "kadmin", NULL);
1338 162 : 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 299665 : ret = samdb_result_dom_sid_buf(msg, "objectSid", &sid);
1348 299665 : if (ret) {
1349 0 : goto out;
1350 : }
1351 299665 : status = dom_sid_split_rid(NULL, &sid, NULL, &rid);
1352 299665 : if (!NT_STATUS_IS_OK(status)) {
1353 0 : ret = EINVAL;
1354 0 : goto out;
1355 : }
1356 :
1357 299665 : if (rid == DOMAIN_RID_KRBTGT) {
1358 165952 : char *realm = NULL;
1359 :
1360 165952 : entry->valid_end = NULL;
1361 165952 : entry->pw_end = NULL;
1362 :
1363 165952 : entry->flags.invalid = 0;
1364 165952 : entry->flags.server = 1;
1365 :
1366 165952 : realm = smb_krb5_principal_get_realm(
1367 : tmp_ctx, context, principal);
1368 165952 : 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 165952 : 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 165952 : TALLOC_FREE(realm);
1391 :
1392 165952 : entry->flags.client = 0;
1393 165952 : entry->flags.forwardable = 1;
1394 165952 : entry->flags.ok_as_delegate = 1;
1395 133713 : } 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 7018 : entry->valid_end = NULL;
1401 7018 : entry->pw_end = NULL;
1402 :
1403 : /* Also don't allow the RODC krbtgt to be a client (it should not be needed) */
1404 7018 : entry->flags.client = 0;
1405 7018 : entry->flags.invalid = 0;
1406 7018 : entry->flags.server = 1;
1407 :
1408 7018 : entry->flags.client = 0;
1409 7018 : entry->flags.forwardable = 1;
1410 7018 : entry->flags.ok_as_delegate = 0;
1411 126695 : } 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 27105 : entry->flags.client = 0;
1418 :
1419 27105 : entry->valid_end = NULL;
1420 27105 : entry->pw_end = NULL;
1421 :
1422 : } else {
1423 3413 : NTTIME must_change_time
1424 99590 : = samdb_result_nttime(msg,
1425 : "msDS-UserPasswordExpiryTimeComputed",
1426 : 0);
1427 99590 : if (must_change_time == 0x7FFFFFFFFFFFFFFFULL) {
1428 16533 : entry->pw_end = NULL;
1429 : } else {
1430 83057 : entry->pw_end = malloc(sizeof(*entry->pw_end));
1431 83057 : if (entry->pw_end == NULL) {
1432 0 : ret = ENOMEM;
1433 0 : goto out;
1434 : }
1435 83057 : *entry->pw_end = nt_time_to_unix(must_change_time);
1436 : }
1437 :
1438 99590 : acct_expiry = samdb_result_account_expires(msg);
1439 99590 : if (acct_expiry == 0x7FFFFFFFFFFFFFFFULL) {
1440 99590 : 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 309807 : ret = samba_kdc_get_entry_principal(context,
1452 : kdc_db_ctx,
1453 : samAccountName,
1454 : ent_type,
1455 : flags,
1456 299665 : entry->flags.change_pw,
1457 : principal,
1458 : &entry->principal);
1459 299665 : if (ret != 0) {
1460 0 : krb5_clear_error_message(context);
1461 0 : goto out;
1462 : }
1463 :
1464 299665 : entry->valid_start = NULL;
1465 :
1466 299665 : entry->max_life = malloc(sizeof(*entry->max_life));
1467 299665 : if (entry->max_life == NULL) {
1468 0 : ret = ENOMEM;
1469 0 : goto out;
1470 : }
1471 :
1472 299665 : if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
1473 27362 : *entry->max_life = kdc_db_ctx->policy.svc_tkt_lifetime;
1474 272303 : } else if (ent_type == SAMBA_KDC_ENT_TYPE_KRBTGT || ent_type == SAMBA_KDC_ENT_TYPE_CLIENT) {
1475 272249 : *entry->max_life = kdc_db_ctx->policy.usr_tkt_lifetime;
1476 : } else {
1477 54 : *entry->max_life = MIN(kdc_db_ctx->policy.svc_tkt_lifetime,
1478 : kdc_db_ctx->policy.usr_tkt_lifetime);
1479 : }
1480 :
1481 299665 : 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 299665 : entry->max_renew = malloc(sizeof(*entry->max_renew));
1487 299665 : if (entry->max_renew == NULL) {
1488 0 : ret = ENOMEM;
1489 0 : goto out;
1490 : }
1491 :
1492 299665 : *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 299665 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT &&
1504 99540 : (flags & SDB_F_FOR_AS_REQ) &&
1505 48369 : !(flags & SDB_F_ARMOR_PRINCIPAL))
1506 : {
1507 49679 : ret = authn_policy_kerberos_client(kdc_db_ctx->samdb, tmp_ctx, msg,
1508 : &authn_client_policy);
1509 49679 : 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 299665 : if (ent_type == SAMBA_KDC_ENT_TYPE_SERVER) {
1519 27362 : ret = authn_policy_server(kdc_db_ctx->samdb, tmp_ctx, msg,
1520 : &authn_server_policy);
1521 27362 : if (ret) {
1522 0 : goto out;
1523 : }
1524 : }
1525 :
1526 299665 : enforced_tgt_lifetime_raw = authn_policy_enforced_tgt_lifetime_raw(authn_client_policy);
1527 299665 : 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 299665 : if (ent_type == SAMBA_KDC_ENT_TYPE_CLIENT && (flags & SDB_F_FOR_AS_REQ)) {
1545 1755 : int result;
1546 50124 : 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 50124 : ret = samba_kdc_get_user_info_from_db(tmp_ctx,
1560 : kdc_db_ctx->samdb,
1561 : p,
1562 : msg,
1563 : &user_info_dc);
1564 50124 : if (ret) {
1565 0 : goto out;
1566 : }
1567 :
1568 51879 : result = dsdb_is_protected_user(kdc_db_ctx->samdb,
1569 50124 : user_info_dc->sids,
1570 50124 : user_info_dc->num_sids);
1571 50124 : if (result == -1) {
1572 0 : ret = EINVAL;
1573 0 : goto out;
1574 : }
1575 :
1576 50124 : protected_user = result;
1577 :
1578 50124 : 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 299665 : if (rid == DOMAIN_RID_KRBTGT || is_rodc) {
1594 6106 : bool enable_fast;
1595 :
1596 172970 : 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 172970 : supported_enctypes = domain_enctypes;
1604 :
1605 172970 : enable_fast = lpcfg_kdc_enable_fast(kdc_db_ctx->lp_ctx);
1606 172970 : if (enable_fast) {
1607 161192 : supported_enctypes |= ENC_FAST_SUPPORTED;
1608 : }
1609 :
1610 172970 : supported_enctypes |= ENC_CLAIMS_SUPPORTED;
1611 172970 : supported_enctypes |= ENC_COMPOUND_IDENTITY_SUPPORTED;
1612 :
1613 : /*
1614 : * Resource SID compression is enabled implicitly, unless
1615 : * disabled in msDS-SupportedEncryptionTypes.
1616 : */
1617 :
1618 126695 : } 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 30331 : supported_enctypes |= domain_enctypes;
1625 :
1626 96364 : } 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 89245 : 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 299665 : if (userAccountControl & UF_USE_DES_KEY_ONLY) {
1643 0 : supported_enctypes &= ~ENC_ALL_TYPES;
1644 : }
1645 :
1646 299665 : if (protected_user) {
1647 57 : supported_enctypes &= ~ENC_RC4_HMAC_MD5;
1648 : }
1649 :
1650 299665 : pa_supported_enctypes = supported_enctypes;
1651 299665 : supported_session_etypes = supported_enctypes;
1652 299665 : if (supported_session_etypes & ENC_HMAC_SHA1_96_AES256_SK) {
1653 94255 : supported_session_etypes |= ENC_HMAC_SHA1_96_AES256;
1654 94255 : supported_session_etypes |= ENC_HMAC_SHA1_96_AES128;
1655 : }
1656 299665 : 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 299665 : supported_enctypes &= kdc_enctypes;
1665 299665 : supported_session_etypes &= kdc_enctypes;
1666 :
1667 : /* Get keys from the db */
1668 299665 : 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 299665 : 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 299665 : if (available_enctypes == 0 &&
1689 2657 : (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 299665 : supported_session_etypes |= available_enctypes;
1711 :
1712 299665 : ret = sdb_entry_set_etypes(entry);
1713 299665 : if (ret) {
1714 0 : goto out;
1715 : }
1716 :
1717 299665 : if (entry->flags.server) {
1718 219023 : bool add_aes256 =
1719 219023 : supported_session_etypes & KERB_ENCTYPE_AES256_CTS_HMAC_SHA1_96;
1720 219023 : bool add_aes128 =
1721 219023 : supported_session_etypes & KERB_ENCTYPE_AES128_CTS_HMAC_SHA1_96;
1722 219023 : bool add_rc4 =
1723 219023 : supported_session_etypes & ENC_RC4_HMAC_MD5;
1724 219023 : ret = sdb_entry_set_session_etypes(entry,
1725 : add_aes256,
1726 : add_aes128,
1727 : add_rc4);
1728 219023 : if (ret) {
1729 0 : goto out;
1730 : }
1731 : }
1732 :
1733 299665 : 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 297446 : 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 172816 : entry->keys.len = 1;
1761 172816 : if (entry->etypes != NULL) {
1762 172816 : entry->etypes->len = MIN(entry->etypes->len, 1);
1763 : }
1764 172816 : entry->old_keys.len = MIN(entry->old_keys.len, 1);
1765 172816 : entry->older_keys.len = MIN(entry->older_keys.len, 1);
1766 : }
1767 : #endif
1768 2033 : } 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 1669 : auth_sam_trigger_repl_secret(kdc_db_ctx,
1774 : kdc_db_ctx->msg_ctx,
1775 : kdc_db_ctx->ev_ctx,
1776 : msg->dn);
1777 1669 : ret = SDB_ERR_NOT_FOUND_HERE;
1778 1669 : 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 297996 : p->msg = talloc_steal(p, msg);
1788 297996 : p->supported_enctypes = pa_supported_enctypes;
1789 :
1790 297996 : p->client_policy = talloc_steal(p, authn_client_policy);
1791 297996 : p->server_policy = talloc_steal(p, authn_server_policy);
1792 :
1793 297996 : talloc_steal(kdc_db_ctx, p);
1794 :
1795 300340 : out:
1796 300340 : if (ret != 0) {
1797 : /* This doesn't free ent itself, that is for the eventual caller to do */
1798 2344 : sdb_entry_free(entry);
1799 : }
1800 :
1801 300340 : talloc_free(tmp_ctx);
1802 300340 : 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 100947 : 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 100947 : char *principal_string = NULL;
2314 :
2315 100947 : 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 98189 : char *principal_string_m = NULL;
2325 3413 : krb5_error_code ret;
2326 :
2327 98189 : ret = krb5_unparse_name(context, principal, &principal_string_m);
2328 98189 : if (ret != 0) {
2329 0 : return ret;
2330 : }
2331 :
2332 98189 : principal_string = talloc_strdup(mem_ctx, principal_string_m);
2333 98189 : SAFE_FREE(principal_string_m);
2334 98189 : if (principal_string == NULL) {
2335 0 : return ENOMEM;
2336 : }
2337 : }
2338 :
2339 100947 : nt_status = sam_get_results_principal(kdc_db_ctx->samdb,
2340 : mem_ctx, principal_string, attrs,
2341 : realm_dn, msg);
2342 100947 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
2343 2688 : krb5_principal fallback_principal = NULL;
2344 0 : unsigned int num_comp;
2345 2688 : char *fallback_realm = NULL;
2346 2688 : char *fallback_account = NULL;
2347 0 : krb5_error_code ret;
2348 :
2349 2688 : ret = krb5_parse_name(context, principal_string,
2350 : &fallback_principal);
2351 2688 : TALLOC_FREE(principal_string);
2352 2688 : if (ret != 0) {
2353 0 : return ret;
2354 : }
2355 :
2356 2688 : num_comp = krb5_princ_size(context, fallback_principal);
2357 2688 : fallback_realm = smb_krb5_principal_get_realm(
2358 : mem_ctx, context, fallback_principal);
2359 2688 : if (fallback_realm == NULL) {
2360 0 : krb5_free_principal(context, fallback_principal);
2361 0 : return ENOMEM;
2362 : }
2363 :
2364 2688 : if (num_comp == 1) {
2365 0 : size_t len;
2366 :
2367 2255 : ret = smb_krb5_principal_get_comp_string(mem_ctx,
2368 : context, fallback_principal, 0, &fallback_account);
2369 2255 : if (ret) {
2370 0 : krb5_free_principal(context, fallback_principal);
2371 0 : TALLOC_FREE(fallback_realm);
2372 0 : return ret;
2373 : }
2374 :
2375 2255 : len = strlen(fallback_account);
2376 2255 : if (len >= 2 && fallback_account[len - 1] == '$') {
2377 8 : TALLOC_FREE(fallback_account);
2378 : }
2379 : }
2380 2688 : krb5_free_principal(context, fallback_principal);
2381 2688 : fallback_principal = NULL;
2382 :
2383 2688 : if (fallback_account != NULL) {
2384 0 : char *with_dollar;
2385 :
2386 2247 : with_dollar = talloc_asprintf(mem_ctx, "%s$",
2387 : fallback_account);
2388 2247 : if (with_dollar == NULL) {
2389 0 : TALLOC_FREE(fallback_realm);
2390 0 : return ENOMEM;
2391 : }
2392 2247 : TALLOC_FREE(fallback_account);
2393 :
2394 2247 : ret = smb_krb5_make_principal(context,
2395 : &fallback_principal,
2396 : fallback_realm,
2397 : with_dollar, NULL);
2398 2247 : TALLOC_FREE(with_dollar);
2399 2247 : if (ret != 0) {
2400 0 : TALLOC_FREE(fallback_realm);
2401 0 : return ret;
2402 : }
2403 : }
2404 2688 : TALLOC_FREE(fallback_realm);
2405 :
2406 2688 : if (fallback_principal != NULL) {
2407 2247 : char *fallback_string = NULL;
2408 :
2409 2247 : ret = krb5_unparse_name(context,
2410 : fallback_principal,
2411 : &fallback_string);
2412 2247 : if (ret != 0) {
2413 0 : krb5_free_principal(context, fallback_principal);
2414 0 : return ret;
2415 : }
2416 :
2417 2247 : nt_status = sam_get_results_principal(kdc_db_ctx->samdb,
2418 : mem_ctx,
2419 : fallback_string,
2420 : attrs,
2421 : realm_dn, msg);
2422 2247 : SAFE_FREE(fallback_string);
2423 : }
2424 2688 : krb5_free_principal(context, fallback_principal);
2425 2688 : fallback_principal = NULL;
2426 : }
2427 100947 : TALLOC_FREE(principal_string);
2428 :
2429 100947 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
2430 500 : return SDB_ERR_NOENTRY;
2431 100447 : } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
2432 0 : return ENOMEM;
2433 100447 : } else if (!NT_STATUS_IS_OK(nt_status)) {
2434 0 : return EINVAL;
2435 : }
2436 :
2437 97034 : return 0;
2438 : }
2439 :
2440 100040 : 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 100040 : struct ldb_message *msg = NULL;
2451 :
2452 100040 : ret = samba_kdc_lookup_client(context, kdc_db_ctx,
2453 : mem_ctx, principal, user_attrs,
2454 : &realm_dn, &msg);
2455 100040 : if (ret != 0) {
2456 500 : return ret;
2457 : }
2458 :
2459 99540 : 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 99540 : return ret;
2464 : }
2465 :
2466 203680 : 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 203680 : TALLOC_CTX *tmp_ctx = NULL;
2475 203680 : struct loadparm_context *lp_ctx = kdc_db_ctx->lp_ctx;
2476 203680 : krb5_error_code ret = 0;
2477 6729 : int is_krbtgt;
2478 203680 : struct ldb_message *msg = NULL;
2479 203680 : struct ldb_dn *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
2480 6729 : char *realm_from_princ;
2481 203680 : char *realm_princ_comp = NULL;
2482 :
2483 203680 : tmp_ctx = talloc_new(mem_ctx);
2484 203680 : if (tmp_ctx == NULL) {
2485 0 : ret = ENOMEM;
2486 0 : goto out;
2487 : }
2488 :
2489 203680 : realm_from_princ = smb_krb5_principal_get_realm(
2490 : tmp_ctx, context, principal);
2491 203680 : if (realm_from_princ == NULL) {
2492 : /* can't happen */
2493 0 : ret = SDB_ERR_NOENTRY;
2494 0 : goto out;
2495 : }
2496 :
2497 203680 : is_krbtgt = smb_krb5_principal_is_tgs(context, principal);
2498 203680 : if (is_krbtgt == -1) {
2499 0 : ret = ENOMEM;
2500 0 : goto out;
2501 203680 : } else if (!is_krbtgt) {
2502 : /* Not a krbtgt */
2503 28461 : ret = SDB_ERR_NOENTRY;
2504 28461 : goto out;
2505 : }
2506 :
2507 : /* krbtgt case. Either us or a trusted realm */
2508 :
2509 175219 : ret = smb_krb5_principal_get_comp_string(tmp_ctx, context, principal, 1, &realm_princ_comp);
2510 175219 : if (ret == ENOENT) {
2511 : /* OK. */
2512 175182 : } else if (ret) {
2513 0 : goto out;
2514 : }
2515 :
2516 175219 : if (lpcfg_is_my_domain_or_realm(lp_ctx, realm_from_princ)
2517 341713 : && (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 174060 : if (flags & (SDB_F_KVNO_SPECIFIED|SDB_F_RODC_NUMBER_SPECIFIED)) {
2529 51710 : krbtgt_number = SAMBA_KVNO_GET_KRBTGT(kvno);
2530 51710 : if (kdc_db_ctx->rodc) {
2531 3978 : 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 122350 : krbtgt_number = kdc_db_ctx->my_krbtgt_number;
2538 : }
2539 :
2540 172709 : if (krbtgt_number == kdc_db_ctx->my_krbtgt_number) {
2541 172488 : 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 221 : 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 172709 : 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 172709 : } 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 172709 : 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 172709 : 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 203680 : talloc_free(tmp_ctx);
2640 203680 : return ret;
2641 : }
2642 :
2643 28467 : 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 : const char **attrs,
2649 : struct ldb_dn **realm_dn,
2650 : struct ldb_message **msg)
2651 : {
2652 623 : krb5_error_code ret;
2653 28467 : if ((smb_krb5_principal_get_type(context, principal) != KRB5_NT_ENTERPRISE_PRINCIPAL)
2654 27475 : && krb5_princ_size(context, principal) >= 2) {
2655 : /* 'normal server' case */
2656 623 : int ldb_ret;
2657 623 : NTSTATUS nt_status;
2658 623 : struct ldb_dn *user_dn;
2659 623 : char *principal_string;
2660 :
2661 25851 : ret = krb5_unparse_name_flags(context, principal,
2662 : KRB5_PRINCIPAL_UNPARSE_NO_REALM,
2663 : &principal_string);
2664 25851 : if (ret != 0) {
2665 0 : return ret;
2666 : }
2667 :
2668 : /* At this point we may find the host is known to be
2669 : * in a different realm, so we should generate a
2670 : * referral instead */
2671 25851 : nt_status = crack_service_principal_name(kdc_db_ctx->samdb,
2672 : mem_ctx, principal_string,
2673 : &user_dn, realm_dn);
2674 25851 : free(principal_string);
2675 :
2676 25851 : if (!NT_STATUS_IS_OK(nt_status)) {
2677 238 : return SDB_ERR_NOENTRY;
2678 : }
2679 :
2680 25613 : ldb_ret = dsdb_search_one(kdc_db_ctx->samdb,
2681 : mem_ctx,
2682 : msg, user_dn, LDB_SCOPE_BASE,
2683 : attrs,
2684 : DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
2685 : "(objectClass=*)");
2686 25613 : if (ldb_ret != LDB_SUCCESS) {
2687 0 : return SDB_ERR_NOENTRY;
2688 : }
2689 25613 : return 0;
2690 2616 : } else if (!(flags & SDB_F_FOR_AS_REQ)
2691 2257 : && smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
2692 : /*
2693 : * The behaviour of accepting an
2694 : * KRB5_NT_ENTERPRISE_PRINCIPAL server principal
2695 : * containing a UPN only applies to TGS-REQ packets,
2696 : * not AS-REQ packets.
2697 : */
2698 864 : return samba_kdc_lookup_client(context, kdc_db_ctx,
2699 : mem_ctx, principal, attrs,
2700 : realm_dn, msg);
2701 : } else {
2702 : /*
2703 : * This case is for:
2704 : * - the AS-REQ, where we only accept
2705 : * samAccountName based lookups for the server, no
2706 : * matter if the name is an
2707 : * KRB5_NT_ENTERPRISE_PRINCIPAL or not
2708 : * - for the TGS-REQ when we are not given an
2709 : * KRB5_NT_ENTERPRISE_PRINCIPAL, which also must
2710 : * only lookup samAccountName based names.
2711 : */
2712 0 : int lret;
2713 0 : char *short_princ;
2714 1752 : krb5_principal enterprise_principal = NULL;
2715 1752 : krb5_const_principal used_principal = NULL;
2716 1752 : char *name1 = NULL;
2717 1752 : size_t len1 = 0;
2718 1752 : char *filter = NULL;
2719 :
2720 1752 : if (smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
2721 128 : char *str = NULL;
2722 : /* Need to reparse the enterprise principal to find the real target */
2723 128 : if (krb5_princ_size(context, principal) != 1) {
2724 0 : ret = KRB5_PARSE_MALFORMED;
2725 0 : krb5_set_error_message(context, ret, "samba_kdc_lookup_server: request for an "
2726 : "enterprise principal with wrong (%d) number of components",
2727 0 : krb5_princ_size(context, principal));
2728 0 : return ret;
2729 : }
2730 128 : ret = smb_krb5_principal_get_comp_string(mem_ctx, context, principal, 0, &str);
2731 128 : if (ret) {
2732 0 : return KRB5_PARSE_MALFORMED;
2733 : }
2734 128 : ret = krb5_parse_name(context, str,
2735 : &enterprise_principal);
2736 128 : talloc_free(str);
2737 128 : if (ret) {
2738 0 : return ret;
2739 : }
2740 128 : used_principal = enterprise_principal;
2741 : } else {
2742 1624 : used_principal = principal;
2743 : }
2744 :
2745 : /* server as client principal case, but we must not lookup userPrincipalNames */
2746 1752 : *realm_dn = ldb_get_default_basedn(kdc_db_ctx->samdb);
2747 :
2748 : /* TODO: Check if it is our realm, otherwise give referral */
2749 :
2750 1752 : ret = krb5_unparse_name_flags(context, used_principal,
2751 : KRB5_PRINCIPAL_UNPARSE_NO_REALM |
2752 : KRB5_PRINCIPAL_UNPARSE_DISPLAY,
2753 : &short_princ);
2754 1752 : used_principal = NULL;
2755 1752 : krb5_free_principal(context, enterprise_principal);
2756 1752 : enterprise_principal = NULL;
2757 :
2758 1752 : if (ret != 0) {
2759 0 : krb5_set_error_message(context, ret, "samba_kdc_lookup_server: could not parse principal");
2760 0 : krb5_warnx(context, "samba_kdc_lookup_server: could not parse principal");
2761 0 : return ret;
2762 : }
2763 :
2764 1752 : name1 = ldb_binary_encode_string(mem_ctx, short_princ);
2765 1752 : SAFE_FREE(short_princ);
2766 1752 : if (name1 == NULL) {
2767 0 : return ENOMEM;
2768 : }
2769 1752 : len1 = strlen(name1);
2770 1752 : if (len1 >= 1 && name1[len1 - 1] != '$') {
2771 1187 : filter = talloc_asprintf(mem_ctx,
2772 : "(&(objectClass=user)(|(samAccountName=%s)(samAccountName=%s$)))",
2773 : name1, name1);
2774 1187 : if (filter == NULL) {
2775 0 : return ENOMEM;
2776 : }
2777 : } else {
2778 565 : filter = talloc_asprintf(mem_ctx,
2779 : "(&(objectClass=user)(samAccountName=%s))",
2780 : name1);
2781 565 : if (filter == NULL) {
2782 0 : return ENOMEM;
2783 : }
2784 : }
2785 :
2786 1752 : lret = dsdb_search_one(kdc_db_ctx->samdb, mem_ctx, msg,
2787 : *realm_dn, LDB_SCOPE_SUBTREE,
2788 : attrs,
2789 : DSDB_SEARCH_SHOW_EXTENDED_DN | DSDB_SEARCH_NO_GLOBAL_CATALOG,
2790 : "%s", filter);
2791 1752 : if (lret == LDB_ERR_NO_SUCH_OBJECT) {
2792 192 : DBG_DEBUG("Failed to find an entry for %s filter:%s\n",
2793 : name1, filter);
2794 192 : return SDB_ERR_NOENTRY;
2795 : }
2796 1560 : if (lret == LDB_ERR_CONSTRAINT_VIOLATION) {
2797 0 : DBG_DEBUG("Failed to find unique entry for %s filter:%s\n",
2798 : name1, filter);
2799 0 : return SDB_ERR_NOENTRY;
2800 : }
2801 1560 : if (lret != LDB_SUCCESS) {
2802 0 : DBG_ERR("Failed single search for %s - %s\n",
2803 : name1, ldb_errstring(kdc_db_ctx->samdb));
2804 0 : return SDB_ERR_NOENTRY;
2805 : }
2806 1560 : return 0;
2807 : }
2808 : return SDB_ERR_NOENTRY;
2809 : }
2810 :
2811 :
2812 :
2813 28467 : static krb5_error_code samba_kdc_fetch_server(krb5_context context,
2814 : struct samba_kdc_db_context *kdc_db_ctx,
2815 : TALLOC_CTX *mem_ctx,
2816 : krb5_const_principal principal,
2817 : unsigned flags,
2818 : krb5_kvno kvno,
2819 : struct sdb_entry *entry)
2820 : {
2821 623 : krb5_error_code ret;
2822 623 : struct ldb_dn *realm_dn;
2823 623 : struct ldb_message *msg;
2824 :
2825 28467 : ret = samba_kdc_lookup_server(context, kdc_db_ctx, mem_ctx, principal,
2826 : flags, server_attrs, &realm_dn, &msg);
2827 28467 : if (ret != 0) {
2828 430 : return ret;
2829 : }
2830 :
2831 28037 : ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
2832 : principal, SAMBA_KDC_ENT_TYPE_SERVER,
2833 : flags, kvno,
2834 : realm_dn, msg, entry);
2835 28037 : if (ret != 0) {
2836 717 : char *client_name = NULL;
2837 0 : krb5_error_code code;
2838 :
2839 717 : code = krb5_unparse_name(context, principal, &client_name);
2840 717 : if (code == 0) {
2841 717 : krb5_warnx(context,
2842 : "samba_kdc_fetch_server: message2entry failed for "
2843 : "%s",
2844 : client_name);
2845 : } else {
2846 0 : krb5_warnx(context,
2847 : "samba_kdc_fetch_server: message2entry and "
2848 : "krb5_unparse_name failed");
2849 : }
2850 717 : SAFE_FREE(client_name);
2851 : }
2852 :
2853 27414 : return ret;
2854 : }
2855 :
2856 304579 : static krb5_error_code samba_kdc_lookup_realm(krb5_context context,
2857 : struct samba_kdc_db_context *kdc_db_ctx,
2858 : krb5_const_principal principal,
2859 : unsigned flags,
2860 : struct sdb_entry *entry)
2861 : {
2862 304579 : TALLOC_CTX *frame = talloc_stackframe();
2863 10142 : NTSTATUS status;
2864 10142 : krb5_error_code ret;
2865 304579 : bool check_realm = false;
2866 304579 : const char *realm = NULL;
2867 304579 : struct dsdb_trust_routing_table *trt = NULL;
2868 304579 : const struct lsa_TrustDomainInfoInfoEx *tdo = NULL;
2869 10142 : unsigned int num_comp;
2870 10142 : bool ok;
2871 304579 : char *upper = NULL;
2872 :
2873 304579 : *entry = (struct sdb_entry) {};
2874 :
2875 304579 : num_comp = krb5_princ_size(context, principal);
2876 :
2877 304579 : if (flags & SDB_F_GET_CLIENT) {
2878 100326 : if (flags & SDB_F_FOR_AS_REQ) {
2879 50853 : check_realm = true;
2880 : }
2881 : }
2882 304579 : if (flags & SDB_F_GET_SERVER) {
2883 98704 : if (flags & SDB_F_FOR_TGS_REQ) {
2884 48910 : check_realm = true;
2885 : }
2886 : }
2887 :
2888 302921 : if (!check_realm) {
2889 203158 : TALLOC_FREE(frame);
2890 203158 : return 0;
2891 : }
2892 :
2893 101421 : realm = smb_krb5_principal_get_realm(frame, context, principal);
2894 101421 : if (realm == NULL) {
2895 0 : TALLOC_FREE(frame);
2896 0 : return ENOMEM;
2897 : }
2898 :
2899 : /*
2900 : * The requested realm needs to be our own
2901 : */
2902 101421 : ok = lpcfg_is_my_domain_or_realm(kdc_db_ctx->lp_ctx, realm);
2903 101421 : if (!ok) {
2904 : /*
2905 : * The request is not for us...
2906 : */
2907 1 : TALLOC_FREE(frame);
2908 1 : return SDB_ERR_NOENTRY;
2909 : }
2910 :
2911 101420 : if (smb_krb5_principal_get_type(context, principal) == KRB5_NT_ENTERPRISE_PRINCIPAL) {
2912 2845 : char *principal_string = NULL;
2913 2845 : krb5_principal enterprise_principal = NULL;
2914 2845 : char *enterprise_realm = NULL;
2915 :
2916 2845 : if (num_comp != 1) {
2917 0 : TALLOC_FREE(frame);
2918 0 : return SDB_ERR_NOENTRY;
2919 : }
2920 :
2921 2845 : ret = smb_krb5_principal_get_comp_string(frame, context,
2922 : principal, 0, &principal_string);
2923 2845 : if (ret) {
2924 0 : TALLOC_FREE(frame);
2925 0 : return ret;
2926 : }
2927 :
2928 2845 : ret = krb5_parse_name(context, principal_string,
2929 : &enterprise_principal);
2930 2845 : TALLOC_FREE(principal_string);
2931 2845 : if (ret) {
2932 0 : TALLOC_FREE(frame);
2933 0 : return ret;
2934 : }
2935 :
2936 2845 : enterprise_realm = smb_krb5_principal_get_realm(
2937 : frame, context, enterprise_principal);
2938 2845 : krb5_free_principal(context, enterprise_principal);
2939 2845 : if (enterprise_realm != NULL) {
2940 2845 : realm = enterprise_realm;
2941 : }
2942 : }
2943 :
2944 101420 : if (flags & SDB_F_GET_SERVER) {
2945 50567 : bool is_krbtgt = false;
2946 :
2947 50567 : ret = is_principal_component_equal(context, principal, 0, KRB5_TGS_NAME, &is_krbtgt);
2948 50567 : if (ret) {
2949 0 : TALLOC_FREE(frame);
2950 26961 : return ret;
2951 : }
2952 :
2953 50567 : if (is_krbtgt) {
2954 : /*
2955 : * we need to search krbtgt/ locally
2956 : */
2957 26961 : TALLOC_FREE(frame);
2958 26961 : return 0;
2959 : }
2960 :
2961 : /*
2962 : * We need to check the last component against the routing table.
2963 : *
2964 : * Note this works only with 2 or 3 component principals, e.g:
2965 : *
2966 : * servicePrincipalName: ldap/W2K8R2-219.bla.base
2967 : * servicePrincipalName: ldap/W2K8R2-219.bla.base/bla.base
2968 : * servicePrincipalName: ldap/W2K8R2-219.bla.base/ForestDnsZones.bla.base
2969 : * servicePrincipalName: ldap/W2K8R2-219.bla.base/DomainDnsZones.bla.base
2970 : */
2971 :
2972 23606 : if (num_comp == 2 || num_comp == 3) {
2973 21205 : char *service_realm = NULL;
2974 :
2975 21205 : ret = smb_krb5_principal_get_comp_string(frame,
2976 : context,
2977 : principal,
2978 : num_comp - 1,
2979 : &service_realm);
2980 21205 : if (ret) {
2981 0 : TALLOC_FREE(frame);
2982 0 : return ret;
2983 : } else {
2984 21205 : realm = service_realm;
2985 : }
2986 : }
2987 : }
2988 :
2989 74459 : ok = lpcfg_is_my_domain_or_realm(kdc_db_ctx->lp_ctx, realm);
2990 74459 : if (ok) {
2991 : /*
2992 : * skip the expensive routing lookup
2993 : */
2994 52761 : TALLOC_FREE(frame);
2995 52761 : return 0;
2996 : }
2997 :
2998 21698 : status = dsdb_trust_routing_table_load(kdc_db_ctx->samdb,
2999 : frame, &trt);
3000 21698 : if (!NT_STATUS_IS_OK(status)) {
3001 0 : TALLOC_FREE(frame);
3002 0 : return EINVAL;
3003 : }
3004 :
3005 21698 : tdo = dsdb_trust_routing_by_name(trt, realm);
3006 21698 : if (tdo == NULL) {
3007 : /*
3008 : * This principal has to be local
3009 : */
3010 18776 : TALLOC_FREE(frame);
3011 18776 : return 0;
3012 : }
3013 :
3014 2922 : if (tdo->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
3015 : /*
3016 : * TODO: handle the routing within the forest
3017 : *
3018 : * This should likely be handled in
3019 : * samba_kdc_message2entry() in case we're
3020 : * a global catalog. We'd need to check
3021 : * if realm_dn is our own domain and derive
3022 : * the dns domain name from realm_dn and check that
3023 : * against the routing table or fallback to
3024 : * the tdo we found here.
3025 : *
3026 : * But for now we don't support multiple domains
3027 : * in our forest correctly anyway.
3028 : *
3029 : * Just search in our local database.
3030 : */
3031 2060 : TALLOC_FREE(frame);
3032 2060 : return 0;
3033 : }
3034 :
3035 862 : ret = krb5_copy_principal(context, principal,
3036 : &entry->principal);
3037 862 : if (ret) {
3038 0 : TALLOC_FREE(frame);
3039 0 : return ret;
3040 : }
3041 :
3042 862 : upper = strupper_talloc(frame, tdo->domain_name.string);
3043 862 : if (upper == NULL) {
3044 0 : TALLOC_FREE(frame);
3045 0 : return ENOMEM;
3046 : }
3047 :
3048 862 : ret = smb_krb5_principal_set_realm(context,
3049 : entry->principal,
3050 : upper);
3051 862 : if (ret) {
3052 0 : TALLOC_FREE(frame);
3053 0 : return ret;
3054 : }
3055 :
3056 862 : TALLOC_FREE(frame);
3057 862 : return SDB_ERR_WRONG_REALM;
3058 : }
3059 :
3060 304579 : krb5_error_code samba_kdc_fetch(krb5_context context,
3061 : struct samba_kdc_db_context *kdc_db_ctx,
3062 : krb5_const_principal principal,
3063 : unsigned flags,
3064 : krb5_kvno kvno,
3065 : struct sdb_entry *entry)
3066 : {
3067 304579 : krb5_error_code ret = SDB_ERR_NOENTRY;
3068 10142 : TALLOC_CTX *mem_ctx;
3069 :
3070 304579 : mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_fetch context");
3071 304579 : if (!mem_ctx) {
3072 0 : ret = ENOMEM;
3073 0 : krb5_set_error_message(context, ret, "samba_kdc_fetch: talloc_named() failed!");
3074 0 : return ret;
3075 : }
3076 :
3077 304579 : ret = samba_kdc_lookup_realm(context, kdc_db_ctx,
3078 : principal, flags, entry);
3079 304579 : if (ret != 0) {
3080 863 : goto done;
3081 : }
3082 :
3083 303716 : ret = SDB_ERR_NOENTRY;
3084 :
3085 303716 : if (flags & SDB_F_GET_CLIENT) {
3086 100040 : ret = samba_kdc_fetch_client(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry);
3087 100040 : if (ret != SDB_ERR_NOENTRY) goto done;
3088 : }
3089 204176 : if (flags & SDB_F_GET_SERVER) {
3090 : /* krbtgt fits into this situation for trusted realms, and for resolving different versions of our own realm name */
3091 98115 : ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry);
3092 98115 : if (ret != SDB_ERR_NOENTRY) goto done;
3093 :
3094 : /* We return 'no entry' if it does not start with krbtgt/, so move to the common case quickly */
3095 28467 : ret = samba_kdc_fetch_server(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry);
3096 28467 : if (ret != SDB_ERR_NOENTRY) goto done;
3097 : }
3098 107166 : if (flags & SDB_F_GET_KRBTGT) {
3099 105565 : ret = samba_kdc_fetch_krbtgt(context, kdc_db_ctx, mem_ctx, principal, flags, kvno, entry);
3100 105565 : if (ret != SDB_ERR_NOENTRY) goto done;
3101 : }
3102 :
3103 1605 : done:
3104 304579 : talloc_free(mem_ctx);
3105 304579 : return ret;
3106 : }
3107 :
3108 : struct samba_kdc_seq {
3109 : unsigned int index;
3110 : unsigned int count;
3111 : struct ldb_message **msgs;
3112 : struct ldb_dn *realm_dn;
3113 : };
3114 :
3115 58 : static krb5_error_code samba_kdc_seq(krb5_context context,
3116 : struct samba_kdc_db_context *kdc_db_ctx,
3117 : struct sdb_entry *entry)
3118 : {
3119 0 : krb5_error_code ret;
3120 58 : struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
3121 58 : const char *realm = lpcfg_realm(kdc_db_ctx->lp_ctx);
3122 58 : struct ldb_message *msg = NULL;
3123 58 : const char *sAMAccountName = NULL;
3124 58 : krb5_principal principal = NULL;
3125 0 : TALLOC_CTX *mem_ctx;
3126 :
3127 58 : if (!priv) {
3128 0 : return SDB_ERR_NOENTRY;
3129 : }
3130 :
3131 58 : mem_ctx = talloc_named(priv, 0, "samba_kdc_seq context");
3132 :
3133 58 : if (!mem_ctx) {
3134 0 : ret = ENOMEM;
3135 0 : krb5_set_error_message(context, ret, "samba_kdc_seq: talloc_named() failed!");
3136 0 : goto out;
3137 : }
3138 :
3139 58 : while (priv->index < priv->count) {
3140 54 : msg = priv->msgs[priv->index++];
3141 :
3142 54 : sAMAccountName = ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL);
3143 54 : if (sAMAccountName != NULL) {
3144 54 : break;
3145 : }
3146 : }
3147 :
3148 58 : if (sAMAccountName == NULL) {
3149 4 : ret = SDB_ERR_NOENTRY;
3150 4 : goto out;
3151 : }
3152 :
3153 54 : ret = smb_krb5_make_principal(context, &principal,
3154 : realm, sAMAccountName, NULL);
3155 54 : if (ret != 0) {
3156 0 : goto out;
3157 : }
3158 :
3159 54 : ret = samba_kdc_message2entry(context, kdc_db_ctx, mem_ctx,
3160 : principal, SAMBA_KDC_ENT_TYPE_ANY,
3161 : SDB_F_ADMIN_DATA|SDB_F_GET_ANY,
3162 : 0 /* kvno */,
3163 : priv->realm_dn, msg, entry);
3164 54 : krb5_free_principal(context, principal);
3165 :
3166 58 : out:
3167 58 : if (ret != 0) {
3168 4 : TALLOC_FREE(priv);
3169 4 : kdc_db_ctx->seq_ctx = NULL;
3170 : } else {
3171 54 : talloc_free(mem_ctx);
3172 : }
3173 :
3174 58 : return ret;
3175 : }
3176 :
3177 4 : krb5_error_code samba_kdc_firstkey(krb5_context context,
3178 : struct samba_kdc_db_context *kdc_db_ctx,
3179 : struct sdb_entry *entry)
3180 : {
3181 4 : struct ldb_context *ldb_ctx = kdc_db_ctx->samdb;
3182 4 : struct samba_kdc_seq *priv = kdc_db_ctx->seq_ctx;
3183 0 : char *realm;
3184 4 : struct ldb_result *res = NULL;
3185 0 : krb5_error_code ret;
3186 0 : int lret;
3187 :
3188 4 : if (priv) {
3189 0 : TALLOC_FREE(priv);
3190 0 : kdc_db_ctx->seq_ctx = NULL;
3191 : }
3192 :
3193 4 : priv = (struct samba_kdc_seq *) talloc(kdc_db_ctx, struct samba_kdc_seq);
3194 4 : if (!priv) {
3195 0 : ret = ENOMEM;
3196 0 : krb5_set_error_message(context, ret, "talloc: out of memory");
3197 0 : return ret;
3198 : }
3199 :
3200 4 : priv->index = 0;
3201 4 : priv->msgs = NULL;
3202 4 : priv->realm_dn = ldb_get_default_basedn(ldb_ctx);
3203 4 : priv->count = 0;
3204 :
3205 4 : ret = krb5_get_default_realm(context, &realm);
3206 4 : if (ret != 0) {
3207 0 : TALLOC_FREE(priv);
3208 0 : return ret;
3209 : }
3210 4 : krb5_free_default_realm(context, realm);
3211 :
3212 4 : lret = dsdb_search(ldb_ctx, priv, &res,
3213 : priv->realm_dn, LDB_SCOPE_SUBTREE, user_attrs,
3214 : DSDB_SEARCH_NO_GLOBAL_CATALOG,
3215 : "(objectClass=user)");
3216 :
3217 4 : if (lret != LDB_SUCCESS) {
3218 0 : TALLOC_FREE(priv);
3219 0 : return SDB_ERR_NOENTRY;
3220 : }
3221 :
3222 4 : priv->count = res->count;
3223 4 : priv->msgs = talloc_steal(priv, res->msgs);
3224 4 : talloc_free(res);
3225 :
3226 4 : kdc_db_ctx->seq_ctx = priv;
3227 :
3228 4 : ret = samba_kdc_seq(context, kdc_db_ctx, entry);
3229 :
3230 4 : if (ret != 0) {
3231 0 : TALLOC_FREE(priv);
3232 0 : kdc_db_ctx->seq_ctx = NULL;
3233 : }
3234 4 : return ret;
3235 : }
3236 :
3237 54 : krb5_error_code samba_kdc_nextkey(krb5_context context,
3238 : struct samba_kdc_db_context *kdc_db_ctx,
3239 : struct sdb_entry *entry)
3240 : {
3241 54 : return samba_kdc_seq(context, kdc_db_ctx, entry);
3242 : }
3243 :
3244 : /* Check if a given entry may delegate or do s4u2self to this target principal
3245 : *
3246 : * The safest way to determine 'self' is to check the DB record made at
3247 : * the time the principal was presented to the KDC.
3248 : */
3249 : krb5_error_code
3250 950 : samba_kdc_check_client_matches_target_service(krb5_context context,
3251 : struct samba_kdc_entry *skdc_entry_client,
3252 : struct samba_kdc_entry *skdc_entry_server_target)
3253 : {
3254 0 : struct dom_sid *orig_sid;
3255 0 : struct dom_sid *target_sid;
3256 950 : TALLOC_CTX *frame = talloc_stackframe();
3257 :
3258 950 : orig_sid = samdb_result_dom_sid(frame,
3259 950 : skdc_entry_client->msg,
3260 : "objectSid");
3261 950 : target_sid = samdb_result_dom_sid(frame,
3262 950 : skdc_entry_server_target->msg,
3263 : "objectSid");
3264 :
3265 : /*
3266 : * Allow delegation to the same record (representing a
3267 : * principal), even if by a different name. The easy and safe
3268 : * way to prove this is by SID comparison
3269 : */
3270 950 : if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
3271 6 : talloc_free(frame);
3272 6 : return KRB5KRB_AP_ERR_BADMATCH;
3273 : }
3274 :
3275 944 : talloc_free(frame);
3276 944 : return 0;
3277 : }
3278 :
3279 : /* Certificates printed by the Certificate Authority might have a
3280 : * slightly different form of the user principal name to that in the
3281 : * database. Allow a mismatch where they both refer to the same
3282 : * SID */
3283 :
3284 : krb5_error_code
3285 43 : samba_kdc_check_pkinit_ms_upn_match(krb5_context context,
3286 : struct samba_kdc_db_context *kdc_db_ctx,
3287 : struct samba_kdc_entry *skdc_entry,
3288 : krb5_const_principal certificate_principal)
3289 : {
3290 0 : krb5_error_code ret;
3291 0 : struct ldb_dn *realm_dn;
3292 0 : struct ldb_message *msg;
3293 0 : struct dom_sid *orig_sid;
3294 0 : struct dom_sid *target_sid;
3295 43 : const char *ms_upn_check_attrs[] = {
3296 : "objectSid", NULL
3297 : };
3298 :
3299 43 : TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_pkinit_ms_upn_match");
3300 :
3301 43 : if (!mem_ctx) {
3302 0 : ret = ENOMEM;
3303 0 : krb5_set_error_message(context, ret, "samba_kdc_check_pkinit_ms_upn_match: talloc_named() failed!");
3304 0 : return ret;
3305 : }
3306 :
3307 43 : ret = samba_kdc_lookup_client(context, kdc_db_ctx,
3308 : mem_ctx, certificate_principal,
3309 : ms_upn_check_attrs, &realm_dn, &msg);
3310 :
3311 43 : if (ret != 0) {
3312 0 : talloc_free(mem_ctx);
3313 0 : return ret;
3314 : }
3315 :
3316 43 : orig_sid = samdb_result_dom_sid(mem_ctx, skdc_entry->msg, "objectSid");
3317 43 : target_sid = samdb_result_dom_sid(mem_ctx, msg, "objectSid");
3318 :
3319 : /* Consider these to be the same principal, even if by a different
3320 : * name. The easy and safe way to prove this is by SID
3321 : * comparison */
3322 43 : if (!(orig_sid && target_sid && dom_sid_equal(orig_sid, target_sid))) {
3323 2 : talloc_free(mem_ctx);
3324 : #if defined(KRB5KDC_ERR_CLIENT_NAME_MISMATCH) /* MIT */
3325 0 : return KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
3326 : #else /* Heimdal (where this is an enum) */
3327 2 : return KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;
3328 : #endif
3329 : }
3330 :
3331 41 : talloc_free(mem_ctx);
3332 41 : return ret;
3333 : }
3334 :
3335 : /*
3336 : * Check if a given entry may delegate to this target principal
3337 : * with S4U2Proxy.
3338 : */
3339 : krb5_error_code
3340 146 : samba_kdc_check_s4u2proxy(krb5_context context,
3341 : struct samba_kdc_db_context *kdc_db_ctx,
3342 : struct samba_kdc_entry *skdc_entry,
3343 : krb5_const_principal target_principal)
3344 : {
3345 0 : krb5_error_code ret;
3346 146 : char *tmp = NULL;
3347 146 : const char *client_dn = NULL;
3348 146 : const char *target_principal_name = NULL;
3349 0 : struct ldb_message_element *el;
3350 0 : struct ldb_val val;
3351 0 : unsigned int i;
3352 146 : bool found = false;
3353 :
3354 146 : TALLOC_CTX *mem_ctx = talloc_named(kdc_db_ctx, 0, "samba_kdc_check_s4u2proxy");
3355 :
3356 146 : if (!mem_ctx) {
3357 0 : ret = ENOMEM;
3358 0 : krb5_set_error_message(context, ret,
3359 : "samba_kdc_check_s4u2proxy:"
3360 : " talloc_named() failed!");
3361 0 : return ret;
3362 : }
3363 :
3364 146 : client_dn = ldb_dn_get_linearized(skdc_entry->msg->dn);
3365 146 : if (!client_dn) {
3366 0 : if (errno == 0) {
3367 0 : errno = ENOMEM;
3368 : }
3369 0 : ret = errno;
3370 0 : krb5_set_error_message(context, ret,
3371 : "samba_kdc_check_s4u2proxy:"
3372 : " ldb_dn_get_linearized() failed!");
3373 0 : talloc_free(mem_ctx);
3374 0 : return ret;
3375 : }
3376 :
3377 146 : el = ldb_msg_find_element(skdc_entry->msg, "msDS-AllowedToDelegateTo");
3378 146 : if (el == NULL) {
3379 29 : ret = ENOENT;
3380 29 : goto bad_option;
3381 : }
3382 117 : SMB_ASSERT(el->num_values != 0);
3383 :
3384 : /*
3385 : * This is the Microsoft forwardable flag behavior.
3386 : *
3387 : * If the proxy (target) principal is NULL, and we have any authorized
3388 : * delegation target, allow to forward.
3389 : */
3390 117 : if (target_principal == NULL) {
3391 0 : talloc_free(mem_ctx);
3392 0 : return 0;
3393 : }
3394 :
3395 :
3396 : /*
3397 : * The main heimdal code already checked that the target_principal
3398 : * belongs to the same realm as the client.
3399 : *
3400 : * So we just need the principal without the realm,
3401 : * as that is what is configured in the "msDS-AllowedToDelegateTo"
3402 : * attribute.
3403 : */
3404 117 : ret = krb5_unparse_name_flags(context, target_principal,
3405 : KRB5_PRINCIPAL_UNPARSE_NO_REALM, &tmp);
3406 117 : if (ret) {
3407 0 : talloc_free(mem_ctx);
3408 0 : krb5_set_error_message(context, ret,
3409 : "samba_kdc_check_s4u2proxy:"
3410 : " krb5_unparse_name_flags() failed!");
3411 0 : return ret;
3412 : }
3413 117 : DBG_DEBUG("client[%s] for target[%s]\n",
3414 : client_dn, tmp);
3415 :
3416 117 : target_principal_name = talloc_strdup(mem_ctx, tmp);
3417 117 : SAFE_FREE(tmp);
3418 117 : if (target_principal_name == NULL) {
3419 0 : ret = ENOMEM;
3420 0 : krb5_set_error_message(context, ret,
3421 : "samba_kdc_check_s4u2proxy:"
3422 : " talloc_strdup() failed!");
3423 0 : talloc_free(mem_ctx);
3424 0 : return ret;
3425 : }
3426 :
3427 117 : val = data_blob_string_const(target_principal_name);
3428 :
3429 118 : for (i=0; i<el->num_values; i++) {
3430 117 : struct ldb_val *val1 = &val;
3431 117 : struct ldb_val *val2 = &el->values[i];
3432 0 : int cmp;
3433 :
3434 117 : if (val1->length != val2->length) {
3435 1 : continue;
3436 : }
3437 :
3438 116 : cmp = strncasecmp((const char *)val1->data,
3439 116 : (const char *)val2->data,
3440 : val1->length);
3441 116 : if (cmp != 0) {
3442 0 : continue;
3443 : }
3444 :
3445 116 : found = true;
3446 116 : break;
3447 : }
3448 :
3449 117 : if (!found) {
3450 1 : ret = ENOENT;
3451 1 : goto bad_option;
3452 : }
3453 :
3454 116 : DBG_DEBUG("client[%s] allowed target[%s]\n",
3455 : client_dn, target_principal_name);
3456 116 : talloc_free(mem_ctx);
3457 116 : return 0;
3458 :
3459 30 : bad_option:
3460 30 : krb5_set_error_message(context, ret,
3461 : "samba_kdc_check_s4u2proxy: client[%s] "
3462 : "not allowed for delegation to target[%s]",
3463 : client_dn,
3464 : target_principal_name);
3465 30 : talloc_free(mem_ctx);
3466 30 : return KRB5KDC_ERR_BADOPTION;
3467 : }
3468 :
3469 : /*
3470 : * This method is called for S4U2Proxy requests and implements the
3471 : * resource-based constrained delegation variant, which can support
3472 : * cross-realm delegation.
3473 : */
3474 136 : krb5_error_code samba_kdc_check_s4u2proxy_rbcd(
3475 : krb5_context context,
3476 : struct samba_kdc_db_context *kdc_db_ctx,
3477 : krb5_const_principal client_principal,
3478 : krb5_const_principal server_principal,
3479 : const struct auth_user_info_dc *user_info_dc,
3480 : const struct auth_user_info_dc *device_info_dc,
3481 : const struct auth_claims auth_claims,
3482 : struct samba_kdc_entry *proxy_skdc_entry)
3483 : {
3484 0 : krb5_error_code code;
3485 0 : enum ndr_err_code ndr_err;
3486 136 : char *client_name = NULL;
3487 136 : char *server_name = NULL;
3488 136 : const char *proxy_dn = NULL;
3489 136 : const DATA_BLOB *data = NULL;
3490 136 : struct security_descriptor *rbcd_security_descriptor = NULL;
3491 136 : struct security_token *security_token = NULL;
3492 136 : uint32_t session_info_flags =
3493 : AUTH_SESSION_INFO_DEFAULT_GROUPS |
3494 : AUTH_SESSION_INFO_DEVICE_DEFAULT_GROUPS |
3495 : AUTH_SESSION_INFO_SIMPLE_PRIVILEGES |
3496 : AUTH_SESSION_INFO_FORCE_COMPOUNDED_AUTHENTICATION;
3497 : /*
3498 : * Testing shows that although Windows grants SEC_ADS_GENERIC_ALL access
3499 : * in security descriptors it creates for RBCD, its KDC only requires
3500 : * SEC_ADS_CONTROL_ACCESS for the access check to succeed.
3501 : */
3502 136 : uint32_t access_desired = SEC_ADS_CONTROL_ACCESS;
3503 136 : uint32_t access_granted = 0;
3504 0 : NTSTATUS nt_status;
3505 136 : TALLOC_CTX *mem_ctx = NULL;
3506 :
3507 136 : mem_ctx = talloc_named(kdc_db_ctx,
3508 : 0,
3509 : "samba_kdc_check_s4u2proxy_rbcd");
3510 136 : if (mem_ctx == NULL) {
3511 0 : errno = ENOMEM;
3512 0 : code = errno;
3513 :
3514 0 : return code;
3515 : }
3516 :
3517 136 : proxy_dn = ldb_dn_get_linearized(proxy_skdc_entry->msg->dn);
3518 136 : if (proxy_dn == NULL) {
3519 0 : DBG_ERR("ldb_dn_get_linearized failed for proxy_dn!\n");
3520 0 : if (errno == 0) {
3521 0 : errno = ENOMEM;
3522 : }
3523 0 : code = errno;
3524 :
3525 0 : goto out;
3526 : }
3527 :
3528 136 : rbcd_security_descriptor = talloc_zero(mem_ctx,
3529 : struct security_descriptor);
3530 136 : if (rbcd_security_descriptor == NULL) {
3531 0 : errno = ENOMEM;
3532 0 : code = errno;
3533 :
3534 0 : goto out;
3535 : }
3536 :
3537 136 : code = krb5_unparse_name_flags(context,
3538 : client_principal,
3539 : KRB5_PRINCIPAL_UNPARSE_DISPLAY,
3540 : &client_name);
3541 136 : if (code != 0) {
3542 0 : DBG_ERR("Unable to parse client_principal!\n");
3543 0 : goto out;
3544 : }
3545 :
3546 136 : code = krb5_unparse_name_flags(context,
3547 : server_principal,
3548 : KRB5_PRINCIPAL_UNPARSE_DISPLAY,
3549 : &server_name);
3550 136 : if (code != 0) {
3551 0 : DBG_ERR("Unable to parse server_principal!\n");
3552 0 : goto out;
3553 : }
3554 :
3555 136 : DBG_INFO("Check delegation from client[%s] to server[%s] via "
3556 : "proxy[%s]\n",
3557 : client_name,
3558 : server_name,
3559 : proxy_dn);
3560 :
3561 136 : if (!(user_info_dc->info->user_flags & NETLOGON_GUEST)) {
3562 136 : session_info_flags |= AUTH_SESSION_INFO_AUTHENTICATED;
3563 : }
3564 :
3565 136 : if (device_info_dc != NULL && !(device_info_dc->info->user_flags & NETLOGON_GUEST)) {
3566 90 : session_info_flags |= AUTH_SESSION_INFO_DEVICE_AUTHENTICATED;
3567 : }
3568 :
3569 136 : nt_status = auth_generate_security_token(mem_ctx,
3570 : kdc_db_ctx->lp_ctx,
3571 : kdc_db_ctx->samdb,
3572 : user_info_dc,
3573 : device_info_dc,
3574 : auth_claims,
3575 : session_info_flags,
3576 : &security_token);
3577 136 : if (!NT_STATUS_IS_OK(nt_status)) {
3578 0 : code = map_errno_from_nt_status(nt_status);
3579 0 : goto out;
3580 : }
3581 :
3582 136 : data = ldb_msg_find_ldb_val(proxy_skdc_entry->msg,
3583 : "msDS-AllowedToActOnBehalfOfOtherIdentity");
3584 136 : if (data == NULL) {
3585 5 : DBG_WARNING("Could not find security descriptor "
3586 : "msDS-AllowedToActOnBehalfOfOtherIdentity in "
3587 : "proxy[%s]\n",
3588 : proxy_dn);
3589 5 : code = KRB5KDC_ERR_BADOPTION;
3590 5 : goto out;
3591 : }
3592 :
3593 131 : ndr_err = ndr_pull_struct_blob(
3594 : data,
3595 : mem_ctx,
3596 : rbcd_security_descriptor,
3597 : (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
3598 131 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
3599 0 : errno = ndr_map_error2errno(ndr_err);
3600 0 : DBG_ERR("Failed to unmarshall "
3601 : "msDS-AllowedToActOnBehalfOfOtherIdentity "
3602 : "security descriptor of proxy[%s]\n",
3603 : proxy_dn);
3604 0 : code = KRB5KDC_ERR_BADOPTION;
3605 0 : goto out;
3606 : }
3607 :
3608 131 : if (DEBUGLEVEL >= 10) {
3609 0 : NDR_PRINT_DEBUG(security_token, security_token);
3610 0 : NDR_PRINT_DEBUG(security_descriptor, rbcd_security_descriptor);
3611 : }
3612 :
3613 131 : nt_status = sec_access_check_ds(rbcd_security_descriptor,
3614 : security_token,
3615 : access_desired,
3616 : &access_granted,
3617 : NULL,
3618 : NULL);
3619 :
3620 131 : if (!NT_STATUS_IS_OK(nt_status)) {
3621 22 : DBG_WARNING("RBCD: sec_access_check_ds(access_desired=%#08x, "
3622 : "access_granted:%#08x) failed with: %s\n",
3623 : access_desired,
3624 : access_granted,
3625 : nt_errstr(nt_status));
3626 :
3627 22 : code = KRB5KDC_ERR_BADOPTION;
3628 22 : goto out;
3629 : }
3630 :
3631 109 : DBG_NOTICE("RBCD: Access granted for client[%s]\n", client_name);
3632 :
3633 109 : code = 0;
3634 136 : out:
3635 136 : SAFE_FREE(client_name);
3636 136 : SAFE_FREE(server_name);
3637 :
3638 136 : TALLOC_FREE(mem_ctx);
3639 136 : return code;
3640 : }
3641 :
3642 215 : NTSTATUS samba_kdc_setup_db_ctx(TALLOC_CTX *mem_ctx, struct samba_kdc_base_context *base_ctx,
3643 : struct samba_kdc_db_context **kdc_db_ctx_out)
3644 : {
3645 8 : int ldb_ret;
3646 215 : struct ldb_message *msg = NULL;
3647 215 : struct auth_session_info *session_info = NULL;
3648 215 : struct samba_kdc_db_context *kdc_db_ctx = NULL;
3649 : /* The idea here is very simple. Using Kerberos to
3650 : * authenticate the KDC to the LDAP server is highly likely to
3651 : * be circular.
3652 : *
3653 : * In future we may set this up to use EXTERNAL and SSL
3654 : * certificates, for now it will almost certainly be NTLMSSP_SET_USERNAME
3655 : */
3656 :
3657 215 : kdc_db_ctx = talloc_zero(mem_ctx, struct samba_kdc_db_context);
3658 215 : if (kdc_db_ctx == NULL) {
3659 0 : return NT_STATUS_NO_MEMORY;
3660 : }
3661 215 : kdc_db_ctx->ev_ctx = base_ctx->ev_ctx;
3662 215 : kdc_db_ctx->lp_ctx = base_ctx->lp_ctx;
3663 215 : kdc_db_ctx->msg_ctx = base_ctx->msg_ctx;
3664 :
3665 : /* get default kdc policy */
3666 215 : lpcfg_default_kdc_policy(mem_ctx,
3667 : base_ctx->lp_ctx,
3668 : &kdc_db_ctx->policy.svc_tkt_lifetime,
3669 : &kdc_db_ctx->policy.usr_tkt_lifetime,
3670 : &kdc_db_ctx->policy.renewal_lifetime);
3671 :
3672 215 : session_info = system_session(kdc_db_ctx->lp_ctx);
3673 215 : if (session_info == NULL) {
3674 0 : talloc_free(kdc_db_ctx);
3675 0 : return NT_STATUS_INTERNAL_ERROR;
3676 : }
3677 :
3678 : /* Setup the link to LDB */
3679 215 : kdc_db_ctx->samdb = samdb_connect(kdc_db_ctx,
3680 : base_ctx->ev_ctx,
3681 : base_ctx->lp_ctx,
3682 : session_info,
3683 : NULL,
3684 : 0);
3685 215 : if (kdc_db_ctx->samdb == NULL) {
3686 0 : DBG_WARNING("Cannot open samdb for KDC backend!\n");
3687 0 : talloc_free(kdc_db_ctx);
3688 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3689 : }
3690 :
3691 : /* Find out our own krbtgt kvno */
3692 215 : ldb_ret = samdb_rodc(kdc_db_ctx->samdb, &kdc_db_ctx->rodc);
3693 215 : if (ldb_ret != LDB_SUCCESS) {
3694 0 : DBG_WARNING("Cannot determine if we are an RODC in KDC backend: %s\n",
3695 : ldb_errstring(kdc_db_ctx->samdb));
3696 0 : talloc_free(kdc_db_ctx);
3697 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3698 : }
3699 215 : if (kdc_db_ctx->rodc) {
3700 0 : int my_krbtgt_number;
3701 1 : const char *secondary_keytab[] = { "msDS-SecondaryKrbTgtNumber", NULL };
3702 1 : struct ldb_dn *account_dn = NULL;
3703 1 : struct ldb_dn *server_dn = samdb_server_dn(kdc_db_ctx->samdb, kdc_db_ctx);
3704 1 : if (!server_dn) {
3705 0 : DBG_WARNING("Cannot determine server DN in KDC backend: %s\n",
3706 : ldb_errstring(kdc_db_ctx->samdb));
3707 0 : talloc_free(kdc_db_ctx);
3708 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3709 : }
3710 :
3711 1 : ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, server_dn,
3712 : "serverReference", &account_dn);
3713 1 : if (ldb_ret != LDB_SUCCESS) {
3714 0 : DBG_WARNING("Cannot determine server account in KDC backend: %s\n",
3715 : ldb_errstring(kdc_db_ctx->samdb));
3716 0 : talloc_free(kdc_db_ctx);
3717 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3718 : }
3719 :
3720 1 : ldb_ret = samdb_reference_dn(kdc_db_ctx->samdb, kdc_db_ctx, account_dn,
3721 : "msDS-KrbTgtLink", &kdc_db_ctx->krbtgt_dn);
3722 1 : talloc_free(account_dn);
3723 1 : if (ldb_ret != LDB_SUCCESS) {
3724 0 : DBG_WARNING("Cannot determine RODC krbtgt account in KDC backend: %s\n",
3725 : ldb_errstring(kdc_db_ctx->samdb));
3726 0 : talloc_free(kdc_db_ctx);
3727 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3728 : }
3729 :
3730 1 : ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
3731 : &msg, kdc_db_ctx->krbtgt_dn, LDB_SCOPE_BASE,
3732 : secondary_keytab,
3733 : DSDB_SEARCH_NO_GLOBAL_CATALOG,
3734 : "(&(objectClass=user)(msDS-SecondaryKrbTgtNumber=*))");
3735 1 : if (ldb_ret != LDB_SUCCESS) {
3736 0 : DBG_WARNING("Cannot read krbtgt account %s in KDC backend to get msDS-SecondaryKrbTgtNumber: %s: %s\n",
3737 : ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
3738 : ldb_errstring(kdc_db_ctx->samdb),
3739 : ldb_strerror(ldb_ret));
3740 0 : talloc_free(kdc_db_ctx);
3741 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3742 : }
3743 1 : my_krbtgt_number = ldb_msg_find_attr_as_int(msg, "msDS-SecondaryKrbTgtNumber", -1);
3744 1 : if (my_krbtgt_number == -1) {
3745 0 : DBG_WARNING("Cannot read msDS-SecondaryKrbTgtNumber from krbtgt account %s in KDC backend: got %d\n",
3746 : ldb_dn_get_linearized(kdc_db_ctx->krbtgt_dn),
3747 : my_krbtgt_number);
3748 0 : talloc_free(kdc_db_ctx);
3749 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3750 : }
3751 1 : kdc_db_ctx->my_krbtgt_number = my_krbtgt_number;
3752 :
3753 : } else {
3754 214 : kdc_db_ctx->my_krbtgt_number = 0;
3755 214 : ldb_ret = dsdb_search_one(kdc_db_ctx->samdb, kdc_db_ctx,
3756 : &msg,
3757 : ldb_get_default_basedn(kdc_db_ctx->samdb),
3758 : LDB_SCOPE_SUBTREE,
3759 : krbtgt_attrs,
3760 : DSDB_SEARCH_NO_GLOBAL_CATALOG,
3761 : "(&(objectClass=user)(samAccountName=krbtgt))");
3762 :
3763 214 : if (ldb_ret != LDB_SUCCESS) {
3764 0 : DBG_WARNING("could not find own KRBTGT in DB: %s\n", ldb_errstring(kdc_db_ctx->samdb));
3765 0 : talloc_free(kdc_db_ctx);
3766 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
3767 : }
3768 214 : kdc_db_ctx->krbtgt_dn = talloc_steal(kdc_db_ctx, msg->dn);
3769 214 : kdc_db_ctx->my_krbtgt_number = 0;
3770 214 : talloc_free(msg);
3771 : }
3772 215 : *kdc_db_ctx_out = kdc_db_ctx;
3773 215 : return NT_STATUS_OK;
3774 : }
3775 :
3776 18634 : krb5_error_code dsdb_extract_aes_256_key(krb5_context context,
3777 : TALLOC_CTX *mem_ctx,
3778 : const struct ldb_message *msg,
3779 : uint32_t user_account_control,
3780 : const uint32_t *kvno,
3781 : uint32_t *kvno_out,
3782 : DATA_BLOB *aes_256_key,
3783 : DATA_BLOB *salt)
3784 : {
3785 139 : krb5_error_code krb5_ret;
3786 139 : uint32_t supported_enctypes;
3787 18634 : unsigned flags = SDB_F_GET_CLIENT;
3788 18634 : struct sdb_entry sentry = {};
3789 :
3790 18634 : if (kvno != NULL) {
3791 662 : flags |= SDB_F_KVNO_SPECIFIED;
3792 : }
3793 :
3794 19126 : krb5_ret = samba_kdc_message2entry_keys(context,
3795 : mem_ctx,
3796 : msg,
3797 : false, /* is_krbtgt */
3798 : false, /* is_rodc */
3799 : user_account_control,
3800 : SAMBA_KDC_ENT_TYPE_CLIENT,
3801 : flags,
3802 492 : (kvno != NULL) ? *kvno : 0,
3803 : &sentry,
3804 : ENC_HMAC_SHA1_96_AES256,
3805 : &supported_enctypes);
3806 18634 : if (krb5_ret != 0) {
3807 0 : const char *krb5_err = krb5_get_error_message(context, krb5_ret);
3808 :
3809 0 : DBG_ERR("Failed to parse supplementalCredentials "
3810 : "of %s with %s kvno using "
3811 : "ENCTYPE_HMAC_SHA1_96_AES256 "
3812 : "Kerberos Key: %s\n",
3813 : ldb_dn_get_linearized(msg->dn),
3814 : (kvno != NULL) ? "previous" : "current",
3815 : krb5_err != NULL ? krb5_err : "<unknown>");
3816 :
3817 0 : krb5_free_error_message(context, krb5_err);
3818 :
3819 0 : return krb5_ret;
3820 : }
3821 :
3822 18634 : if ((supported_enctypes & ENC_HMAC_SHA1_96_AES256) == 0 ||
3823 2952 : sentry.keys.len != 1) {
3824 15682 : DBG_INFO("Failed to find a ENCTYPE_HMAC_SHA1_96_AES256 "
3825 : "key in supplementalCredentials "
3826 : "of %s at KVNO %u (got %u keys, expected 1)\n",
3827 : ldb_dn_get_linearized(msg->dn),
3828 : sentry.kvno,
3829 : sentry.keys.len);
3830 15682 : sdb_entry_free(&sentry);
3831 15682 : return ENOENT;
3832 : }
3833 :
3834 2952 : if (sentry.keys.val[0].salt == NULL) {
3835 0 : DBG_INFO("Failed to find a salt in "
3836 : "supplementalCredentials "
3837 : "of %s at KVNO %u\n",
3838 : ldb_dn_get_linearized(msg->dn),
3839 : sentry.kvno);
3840 0 : sdb_entry_free(&sentry);
3841 0 : return ENOENT;
3842 : }
3843 :
3844 2952 : if (aes_256_key != NULL) {
3845 2952 : *aes_256_key = data_blob_talloc(mem_ctx,
3846 : KRB5_KEY_DATA(&sentry.keys.val[0].key),
3847 : KRB5_KEY_LENGTH(&sentry.keys.val[0].key));
3848 2952 : if (aes_256_key->data == NULL) {
3849 0 : sdb_entry_free(&sentry);
3850 0 : return ENOMEM;
3851 : }
3852 2952 : talloc_keep_secret(aes_256_key->data);
3853 : }
3854 :
3855 2952 : if (salt != NULL) {
3856 2588 : *salt = data_blob_talloc(mem_ctx,
3857 : sentry.keys.val[0].salt->salt.data,
3858 : sentry.keys.val[0].salt->salt.length);
3859 2588 : if (salt->data == NULL) {
3860 0 : sdb_entry_free(&sentry);
3861 0 : return ENOMEM;
3862 : }
3863 : }
3864 :
3865 2952 : if (kvno_out != NULL) {
3866 2566 : *kvno_out = sentry.kvno;
3867 : }
3868 :
3869 2952 : sdb_entry_free(&sentry);
3870 :
3871 2952 : return 0;
3872 : }
|