Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : PAC 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 "lib/replace/replace.h"
25 : #include "lib/replace/system/kerberos.h"
26 : #include "lib/replace/system/filesys.h"
27 : #include "lib/util/debug.h"
28 : #include "lib/util/samba_util.h"
29 : #include "lib/util/talloc_stack.h"
30 :
31 : #include "auth/auth_sam_reply.h"
32 : #include "auth/kerberos/kerberos.h"
33 : #include "auth/kerberos/pac_utils.h"
34 : #include "auth/authn_policy.h"
35 : #include "libcli/security/security.h"
36 : #include "libds/common/flags.h"
37 : #include "librpc/gen_ndr/ndr_krb5pac.h"
38 : #include "param/param.h"
39 : #include "source4/auth/auth.h"
40 : #include "source4/dsdb/common/util.h"
41 : #include "source4/dsdb/samdb/samdb.h"
42 : #include "source4/kdc/authn_policy_util.h"
43 : #include "source4/kdc/samba_kdc.h"
44 : #include "source4/kdc/pac-glue.h"
45 : #include "source4/kdc/ad_claims.h"
46 : #include "source4/kdc/pac-blobs.h"
47 :
48 : #include <ldb.h>
49 :
50 : #undef DBGC_CLASS
51 : #define DBGC_CLASS DBGC_KERBEROS
52 :
53 : static
54 79601 : NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
55 : const struct auth_user_info_dc *info,
56 : const struct PAC_DOMAIN_GROUP_MEMBERSHIP *override_resource_groups,
57 : const enum auth_group_inclusion group_inclusion,
58 : DATA_BLOB *pac_data)
59 : {
60 79601 : TALLOC_CTX *tmp_ctx = NULL;
61 79601 : struct netr_SamInfo3 *info3 = NULL;
62 79601 : struct PAC_DOMAIN_GROUP_MEMBERSHIP *_resource_groups = NULL;
63 79601 : struct PAC_DOMAIN_GROUP_MEMBERSHIP **resource_groups = NULL;
64 79601 : union PAC_INFO pac_info = {};
65 2828 : enum ndr_err_code ndr_err;
66 79601 : NTSTATUS nt_status = NT_STATUS_OK;
67 :
68 79601 : *pac_data = data_blob_null;
69 :
70 79601 : tmp_ctx = talloc_new(mem_ctx);
71 79601 : if (tmp_ctx == NULL) {
72 0 : return NT_STATUS_NO_MEMORY;
73 : }
74 :
75 79601 : if (override_resource_groups == NULL) {
76 76768 : resource_groups = &_resource_groups;
77 5 : } else if (group_inclusion != AUTH_EXCLUDE_RESOURCE_GROUPS) {
78 : /*
79 : * It doesn't make sense to override resource groups if we claim
80 : * to want resource groups from user_info_dc.
81 : */
82 0 : DBG_ERR("supplied resource groups with invalid group inclusion parameter: %u\n",
83 : group_inclusion);
84 0 : nt_status = NT_STATUS_INVALID_PARAMETER;
85 0 : goto out;
86 : }
87 :
88 79601 : nt_status = auth_convert_user_info_dc_saminfo3(tmp_ctx, info,
89 : group_inclusion,
90 : &info3,
91 : resource_groups);
92 79601 : if (!NT_STATUS_IS_OK(nt_status)) {
93 0 : DBG_WARNING("Getting Samba info failed: %s\n",
94 : nt_errstr(nt_status));
95 0 : goto out;
96 : }
97 :
98 79601 : pac_info.logon_info.info = talloc_zero(tmp_ctx, struct PAC_LOGON_INFO);
99 79601 : if (!pac_info.logon_info.info) {
100 0 : nt_status = NT_STATUS_NO_MEMORY;
101 0 : goto out;
102 : }
103 :
104 79601 : pac_info.logon_info.info->info3 = *info3;
105 79601 : if (_resource_groups != NULL) {
106 16505 : pac_info.logon_info.info->resource_groups = *_resource_groups;
107 : }
108 :
109 79601 : if (override_resource_groups != NULL) {
110 5 : pac_info.logon_info.info->resource_groups = *override_resource_groups;
111 : }
112 :
113 79601 : if (group_inclusion != AUTH_EXCLUDE_RESOURCE_GROUPS) {
114 : /*
115 : * Set the resource groups flag based on whether any groups are
116 : * present. Otherwise, the flag is propagated from the
117 : * originating PAC.
118 : */
119 23809 : if (pac_info.logon_info.info->resource_groups.groups.count > 0) {
120 16505 : pac_info.logon_info.info->info3.base.user_flags |= NETLOGON_RESOURCE_GROUPS;
121 : } else {
122 7304 : pac_info.logon_info.info->info3.base.user_flags &= ~NETLOGON_RESOURCE_GROUPS;
123 : }
124 : }
125 :
126 79601 : ndr_err = ndr_push_union_blob(pac_data, mem_ctx, &pac_info,
127 : PAC_TYPE_LOGON_INFO,
128 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
129 79601 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
130 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
131 0 : DBG_WARNING("PAC_LOGON_INFO (presig) push failed: %s\n",
132 : nt_errstr(nt_status));
133 0 : goto out;
134 : }
135 :
136 79601 : out:
137 79601 : talloc_free(tmp_ctx);
138 79601 : return nt_status;
139 : }
140 :
141 : static
142 31067 : NTSTATUS samba_get_upn_info_pac_blob(TALLOC_CTX *mem_ctx,
143 : const struct auth_user_info_dc *info,
144 : DATA_BLOB *upn_data)
145 : {
146 31067 : TALLOC_CTX *tmp_ctx = NULL;
147 31067 : union PAC_INFO pac_upn = {};
148 1170 : enum ndr_err_code ndr_err;
149 31067 : NTSTATUS nt_status = NT_STATUS_OK;
150 1170 : bool ok;
151 :
152 31067 : *upn_data = data_blob_null;
153 :
154 31067 : tmp_ctx = talloc_new(mem_ctx);
155 31067 : if (tmp_ctx == NULL) {
156 0 : return NT_STATUS_NO_MEMORY;
157 : }
158 :
159 31067 : pac_upn.upn_dns_info.upn_name = info->info->user_principal_name;
160 60964 : pac_upn.upn_dns_info.dns_domain_name = strupper_talloc(tmp_ctx,
161 29897 : info->info->dns_domain_name);
162 31067 : if (pac_upn.upn_dns_info.dns_domain_name == NULL) {
163 0 : nt_status = NT_STATUS_NO_MEMORY;
164 0 : goto out;
165 : }
166 31067 : if (info->info->user_principal_constructed) {
167 29817 : pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED;
168 : }
169 :
170 31067 : pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID;
171 :
172 1170 : pac_upn.upn_dns_info.ex.sam_name_and_sid.samaccountname
173 31067 : = info->info->account_name;
174 :
175 1170 : pac_upn.upn_dns_info.ex.sam_name_and_sid.objectsid
176 31067 : = &info->sids[PRIMARY_USER_SID_INDEX].sid;
177 :
178 31067 : ndr_err = ndr_push_union_blob(upn_data, mem_ctx, &pac_upn,
179 : PAC_TYPE_UPN_DNS_INFO,
180 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
181 31067 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
182 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
183 0 : DBG_WARNING("PAC UPN_DNS_INFO (presig) push failed: %s\n",
184 : nt_errstr(nt_status));
185 0 : goto out;
186 : }
187 :
188 31067 : ok = data_blob_pad(mem_ctx, upn_data, 8);
189 31067 : if (!ok) {
190 0 : talloc_free(upn_data);
191 0 : nt_status = NT_STATUS_NO_MEMORY;
192 0 : goto out;
193 : }
194 :
195 31067 : out:
196 31067 : talloc_free(tmp_ctx);
197 31067 : return nt_status;
198 : }
199 :
200 : static
201 45 : NTSTATUS samba_get_cred_info_ndr_blob(TALLOC_CTX *mem_ctx,
202 : const struct ldb_message *msg,
203 : DATA_BLOB *cred_blob)
204 : {
205 0 : enum ndr_err_code ndr_err;
206 0 : NTSTATUS nt_status;
207 45 : struct samr_Password *lm_hash = NULL;
208 45 : struct samr_Password *nt_hash = NULL;
209 45 : struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg = {
210 : .version = 0,
211 : };
212 45 : DATA_BLOB ntlm_blob = data_blob_null;
213 45 : struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs[1] = {{
214 : .credential_size = 0,
215 : }};
216 45 : struct PAC_CREDENTIAL_DATA cred_data = {
217 : .credential_count = 0,
218 : };
219 45 : struct PAC_CREDENTIAL_DATA_NDR cred_ndr = {};
220 :
221 45 : *cred_blob = data_blob_null;
222 :
223 45 : lm_hash = samdb_result_hash(mem_ctx, msg, "dBCSPwd");
224 45 : if (lm_hash != NULL) {
225 0 : bool zero = all_zero(lm_hash->hash, 16);
226 0 : if (zero) {
227 0 : lm_hash = NULL;
228 : }
229 : }
230 45 : if (lm_hash != NULL) {
231 0 : DBG_INFO("Passing LM password hash through credentials set\n");
232 0 : ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_LM_HASH;
233 0 : ntlm_secpkg.lm_password = *lm_hash;
234 0 : ZERO_STRUCTP(lm_hash);
235 0 : TALLOC_FREE(lm_hash);
236 : }
237 :
238 45 : nt_hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
239 45 : if (nt_hash != NULL) {
240 45 : bool zero = all_zero(nt_hash->hash, 16);
241 45 : if (zero) {
242 0 : nt_hash = NULL;
243 : }
244 : }
245 45 : if (nt_hash != NULL) {
246 45 : DBG_INFO("Passing NT password hash through credentials set\n");
247 45 : ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_NT_HASH;
248 45 : ntlm_secpkg.nt_password = *nt_hash;
249 45 : ZERO_STRUCTP(nt_hash);
250 45 : TALLOC_FREE(nt_hash);
251 : }
252 :
253 45 : if (ntlm_secpkg.flags == 0) {
254 0 : return NT_STATUS_OK;
255 : }
256 :
257 : #ifdef DEBUG_PASSWORD
258 45 : if (DEBUGLVL(11)) {
259 0 : NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG, &ntlm_secpkg);
260 : }
261 : #endif
262 :
263 45 : ndr_err = ndr_push_struct_blob(&ntlm_blob, mem_ctx, &ntlm_secpkg,
264 : (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG);
265 45 : ZERO_STRUCT(ntlm_secpkg);
266 45 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
267 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
268 0 : DBG_WARNING("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
269 : nt_errstr(nt_status));
270 0 : return nt_status;
271 : }
272 :
273 45 : DBG_DEBUG("NTLM credential BLOB (len %zu) for user\n",
274 : ntlm_blob.length);
275 45 : dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
276 45 : ntlm_blob.data, ntlm_blob.length);
277 :
278 45 : secpkgs[0].package_name.string = discard_const_p(char, "NTLM");
279 45 : secpkgs[0].credential_size = ntlm_blob.length;
280 45 : secpkgs[0].credential = ntlm_blob.data;
281 :
282 45 : cred_data.credential_count = ARRAY_SIZE(secpkgs);
283 45 : cred_data.credentials = secpkgs;
284 :
285 : #ifdef DEBUG_PASSWORD
286 45 : if (DEBUGLVL(11)) {
287 0 : NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA, &cred_data);
288 : }
289 : #endif
290 :
291 45 : cred_ndr.ctr.data = &cred_data;
292 :
293 : #ifdef DEBUG_PASSWORD
294 45 : if (DEBUGLVL(11)) {
295 0 : NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR, &cred_ndr);
296 : }
297 : #endif
298 :
299 45 : ndr_err = ndr_push_struct_blob(cred_blob, mem_ctx, &cred_ndr,
300 : (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_DATA_NDR);
301 45 : data_blob_clear(&ntlm_blob);
302 45 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
303 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
304 0 : DBG_WARNING("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
305 : nt_errstr(nt_status));
306 0 : return nt_status;
307 : }
308 :
309 45 : DBG_DEBUG("Created credential BLOB (len %zu) for user\n",
310 : cred_blob->length);
311 45 : dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
312 45 : cred_blob->data, cred_blob->length);
313 :
314 45 : return NT_STATUS_OK;
315 : }
316 :
317 45 : krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
318 : const krb5_keyblock *pkreplykey,
319 : const DATA_BLOB *cred_ndr_blob,
320 : TALLOC_CTX *mem_ctx,
321 : DATA_BLOB *cred_info_blob)
322 : {
323 : #ifdef SAMBA4_USES_HEIMDAL
324 0 : krb5_crypto cred_crypto;
325 0 : krb5_enctype cred_enctype;
326 0 : krb5_data cred_ndr_crypt;
327 45 : struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
328 0 : krb5_error_code ret;
329 0 : const char *krb5err;
330 0 : enum ndr_err_code ndr_err;
331 0 : NTSTATUS nt_status;
332 :
333 45 : *cred_info_blob = data_blob_null;
334 :
335 45 : ret = krb5_crypto_init(context, pkreplykey, ETYPE_NULL,
336 : &cred_crypto);
337 45 : if (ret != 0) {
338 0 : krb5err = krb5_get_error_message(context, ret);
339 0 : DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err);
340 0 : krb5_free_error_message(context, krb5err);
341 0 : return ret;
342 : }
343 :
344 45 : ret = krb5_crypto_getenctype(context, cred_crypto, &cred_enctype);
345 45 : if (ret != 0) {
346 0 : DBG_WARNING("Failed getting crypto type for key\n");
347 0 : krb5_crypto_destroy(context, cred_crypto);
348 0 : return ret;
349 : }
350 :
351 45 : DBG_DEBUG("Plain cred_ndr_blob (len %zu)\n",
352 : cred_ndr_blob->length);
353 45 : dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
354 45 : cred_ndr_blob->data, cred_ndr_blob->length);
355 :
356 45 : ret = krb5_encrypt(context, cred_crypto,
357 : KRB5_KU_OTHER_ENCRYPTED,
358 45 : cred_ndr_blob->data, cred_ndr_blob->length,
359 : &cred_ndr_crypt);
360 45 : krb5_crypto_destroy(context, cred_crypto);
361 45 : if (ret != 0) {
362 0 : krb5err = krb5_get_error_message(context, ret);
363 0 : DBG_WARNING("Failed crypt of cred data: %s\n", krb5err);
364 0 : krb5_free_error_message(context, krb5err);
365 0 : return ret;
366 : }
367 :
368 45 : pac_cred_info.encryption_type = cred_enctype;
369 45 : pac_cred_info.encrypted_data.length = cred_ndr_crypt.length;
370 45 : pac_cred_info.encrypted_data.data = (uint8_t *)cred_ndr_crypt.data;
371 :
372 45 : if (DEBUGLVL(10)) {
373 0 : NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
374 : }
375 :
376 45 : ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
377 : (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
378 45 : krb5_data_free(&cred_ndr_crypt);
379 45 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
380 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
381 0 : DBG_WARNING("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
382 : nt_errstr(nt_status));
383 0 : return KRB5KDC_ERR_SVC_UNAVAILABLE;
384 : }
385 :
386 45 : DBG_DEBUG("Encrypted credential BLOB (len %zu) with alg %"PRId32"\n",
387 : cred_info_blob->length, pac_cred_info.encryption_type);
388 45 : dump_data_pw("PAC_CREDENTIAL_INFO",
389 45 : cred_info_blob->data, cred_info_blob->length);
390 :
391 45 : return 0;
392 : #else /* SAMBA4_USES_HEIMDAL */
393 0 : TALLOC_CTX *tmp_ctx = NULL;
394 : krb5_key cred_key;
395 : krb5_enctype cred_enctype;
396 0 : struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
397 0 : krb5_error_code code = 0;
398 : const char *krb5err;
399 : enum ndr_err_code ndr_err;
400 : NTSTATUS nt_status;
401 : krb5_data cred_ndr_data;
402 : krb5_enc_data cred_ndr_crypt;
403 0 : size_t enc_len = 0;
404 :
405 0 : *cred_info_blob = data_blob_null;
406 :
407 0 : tmp_ctx = talloc_new(mem_ctx);
408 0 : if (tmp_ctx == NULL) {
409 0 : return ENOMEM;
410 : }
411 :
412 0 : code = krb5_k_create_key(context,
413 : pkreplykey,
414 : &cred_key);
415 0 : if (code != 0) {
416 0 : krb5err = krb5_get_error_message(context, code);
417 0 : DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err);
418 0 : krb5_free_error_message(context, krb5err);
419 0 : goto out;
420 : }
421 :
422 0 : cred_enctype = krb5_k_key_enctype(context, cred_key);
423 :
424 0 : DBG_DEBUG("Plain cred_ndr_blob (len %zu)\n",
425 : cred_ndr_blob->length);
426 0 : dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
427 0 : cred_ndr_blob->data, cred_ndr_blob->length);
428 :
429 0 : pac_cred_info.encryption_type = cred_enctype;
430 :
431 0 : cred_ndr_data = smb_krb5_data_from_blob(*cred_ndr_blob);
432 :
433 0 : code = krb5_c_encrypt_length(context,
434 : cred_enctype,
435 0 : cred_ndr_data.length,
436 : &enc_len);
437 0 : if (code != 0) {
438 0 : krb5err = krb5_get_error_message(context, code);
439 0 : DBG_WARNING("Failed initializing cred data crypto: %s\n", krb5err);
440 0 : krb5_free_error_message(context, krb5err);
441 0 : goto out;
442 : }
443 :
444 0 : pac_cred_info.encrypted_data = data_blob_talloc_zero(tmp_ctx, enc_len);
445 0 : if (pac_cred_info.encrypted_data.data == NULL) {
446 0 : DBG_ERR("Out of memory\n");
447 0 : code = ENOMEM;
448 0 : goto out;
449 : }
450 :
451 0 : cred_ndr_crypt.ciphertext = smb_krb5_data_from_blob(pac_cred_info.encrypted_data);
452 :
453 0 : code = krb5_k_encrypt(context,
454 : cred_key,
455 : KRB5_KU_OTHER_ENCRYPTED,
456 : NULL,
457 : &cred_ndr_data,
458 : &cred_ndr_crypt);
459 0 : krb5_k_free_key(context, cred_key);
460 0 : if (code != 0) {
461 0 : krb5err = krb5_get_error_message(context, code);
462 0 : DBG_WARNING("Failed crypt of cred data: %s\n", krb5err);
463 0 : krb5_free_error_message(context, krb5err);
464 0 : goto out;
465 : }
466 :
467 0 : if (DEBUGLVL(10)) {
468 0 : NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
469 : }
470 :
471 0 : ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
472 : (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
473 0 : TALLOC_FREE(pac_cred_info.encrypted_data.data);
474 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
475 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
476 0 : DBG_WARNING("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
477 : nt_errstr(nt_status));
478 0 : code = KRB5KDC_ERR_SVC_UNAVAILABLE;
479 0 : goto out;
480 : }
481 :
482 0 : DBG_DEBUG("Encrypted credential BLOB (len %zu) with alg %"PRId32"\n",
483 : cred_info_blob->length, pac_cred_info.encryption_type);
484 0 : dump_data_pw("PAC_CREDENTIAL_INFO",
485 0 : cred_info_blob->data, cred_info_blob->length);
486 :
487 0 : out:
488 0 : talloc_free(tmp_ctx);
489 0 : return code;
490 : #endif /* SAMBA4_USES_HEIMDAL */
491 : }
492 :
493 :
494 : /**
495 : * @brief Create a PAC with the given blobs (logon, credentials, upn and
496 : * delegation).
497 : *
498 : * @param[in] context The KRB5 context to use.
499 : *
500 : * @param[in] logon_blob Fill the logon info PAC buffer with the given blob,
501 : * use NULL to ignore it.
502 : *
503 : * @param[in] cred_blob Fill the credentials info PAC buffer with the given
504 : * blob, use NULL to ignore it.
505 : *
506 : * @param[in] upn_blob Fill the UPN info PAC buffer with the given blob, use
507 : * NULL to ignore it.
508 : *
509 : * @param[in] deleg_blob Fill the delegation info PAC buffer with the given
510 : * blob, use NULL to ignore it.
511 : *
512 : * @param[in] client_claims_blob Fill the client claims info PAC buffer with the
513 : * given blob, use NULL to ignore it.
514 : *
515 : * @param[in] device_info_blob Fill the device info PAC buffer with the given
516 : * blob, use NULL to ignore it.
517 : *
518 : * @param[in] device_claims_blob Fill the device claims info PAC buffer with the given
519 : * blob, use NULL to ignore it.
520 : *
521 : * @param[in] pac The pac buffer to fill. This should be allocated with
522 : * krb5_pac_init() already.
523 : *
524 : * @returns 0 on success or a corresponding KRB5 error.
525 : */
526 30952 : krb5_error_code samba_make_krb5_pac(krb5_context context,
527 : const DATA_BLOB *logon_blob,
528 : const DATA_BLOB *cred_blob,
529 : const DATA_BLOB *upn_blob,
530 : const DATA_BLOB *pac_attrs_blob,
531 : const DATA_BLOB *requester_sid_blob,
532 : const DATA_BLOB *deleg_blob,
533 : const DATA_BLOB *client_claims_blob,
534 : const DATA_BLOB *device_info_blob,
535 : const DATA_BLOB *device_claims_blob,
536 : krb5_pac pac)
537 : {
538 1170 : krb5_data logon_data;
539 1170 : krb5_error_code ret;
540 30952 : char null_byte = '\0';
541 30952 : krb5_data null_data = smb_krb5_make_data(&null_byte, 0);
542 :
543 : /* The user account may be set not to want the PAC */
544 30952 : if (logon_blob == NULL) {
545 0 : return 0;
546 : }
547 :
548 30952 : logon_data = smb_krb5_data_from_blob(*logon_blob);
549 30952 : ret = krb5_pac_add_buffer(context, pac, PAC_TYPE_LOGON_INFO, &logon_data);
550 30952 : if (ret != 0) {
551 0 : return ret;
552 : }
553 :
554 30952 : if (device_info_blob != NULL) {
555 0 : krb5_data device_info_data = smb_krb5_data_from_blob(*device_info_blob);
556 0 : ret = krb5_pac_add_buffer(context, pac,
557 : PAC_TYPE_DEVICE_INFO,
558 : &device_info_data);
559 0 : if (ret != 0) {
560 0 : return ret;
561 : }
562 : }
563 :
564 30952 : if (client_claims_blob != NULL) {
565 1170 : krb5_data client_claims_data;
566 30952 : krb5_data *data = NULL;
567 :
568 30952 : if (client_claims_blob->length != 0) {
569 316 : client_claims_data = smb_krb5_data_from_blob(*client_claims_blob);
570 316 : data = &client_claims_data;
571 : } else {
572 29466 : data = &null_data;
573 : }
574 :
575 30952 : ret = krb5_pac_add_buffer(context, pac,
576 : PAC_TYPE_CLIENT_CLAIMS_INFO,
577 : data);
578 30952 : if (ret != 0) {
579 0 : return ret;
580 : }
581 : }
582 :
583 30952 : if (device_claims_blob != NULL) {
584 0 : krb5_data device_claims_data = smb_krb5_data_from_blob(*device_claims_blob);
585 0 : ret = krb5_pac_add_buffer(context, pac,
586 : PAC_TYPE_DEVICE_CLAIMS_INFO,
587 : &device_claims_data);
588 0 : if (ret != 0) {
589 0 : return ret;
590 : }
591 : }
592 :
593 30952 : if (cred_blob != NULL) {
594 45 : krb5_data cred_data = smb_krb5_data_from_blob(*cred_blob);
595 45 : ret = krb5_pac_add_buffer(context, pac,
596 : PAC_TYPE_CREDENTIAL_INFO,
597 : &cred_data);
598 45 : if (ret != 0) {
599 0 : return ret;
600 : }
601 : }
602 :
603 : #ifdef SAMBA4_USES_HEIMDAL
604 : /*
605 : * null_data will be filled by the generic KDC code in the caller
606 : * here we just add it in order to have it before
607 : * PAC_TYPE_UPN_DNS_INFO
608 : *
609 : * Not needed with MIT Kerberos - asn
610 : */
611 30952 : ret = krb5_pac_add_buffer(context, pac,
612 : PAC_TYPE_LOGON_NAME,
613 : &null_data);
614 30952 : if (ret != 0) {
615 0 : return ret;
616 : }
617 : #endif
618 :
619 30952 : if (upn_blob != NULL) {
620 30952 : krb5_data upn_data = smb_krb5_data_from_blob(*upn_blob);
621 30952 : ret = krb5_pac_add_buffer(context, pac,
622 : PAC_TYPE_UPN_DNS_INFO,
623 : &upn_data);
624 30952 : if (ret != 0) {
625 0 : return ret;
626 : }
627 : }
628 :
629 30952 : if (pac_attrs_blob != NULL) {
630 27723 : krb5_data pac_attrs_data = smb_krb5_data_from_blob(*pac_attrs_blob);
631 27723 : ret = krb5_pac_add_buffer(context, pac,
632 : PAC_TYPE_ATTRIBUTES_INFO,
633 : &pac_attrs_data);
634 27723 : if (ret != 0) {
635 0 : return ret;
636 : }
637 : }
638 :
639 30952 : if (requester_sid_blob != NULL) {
640 27723 : krb5_data requester_sid_data = smb_krb5_data_from_blob(*requester_sid_blob);
641 27723 : ret = krb5_pac_add_buffer(context, pac,
642 : PAC_TYPE_REQUESTER_SID,
643 : &requester_sid_data);
644 27723 : if (ret != 0) {
645 0 : return ret;
646 : }
647 : }
648 :
649 30952 : if (deleg_blob != NULL) {
650 0 : krb5_data deleg_data = smb_krb5_data_from_blob(*deleg_blob);
651 0 : ret = krb5_pac_add_buffer(context, pac,
652 : PAC_TYPE_CONSTRAINED_DELEGATION,
653 : &deleg_data);
654 0 : if (ret != 0) {
655 0 : return ret;
656 : }
657 : }
658 :
659 29782 : return ret;
660 : }
661 :
662 48649 : bool samba_princ_needs_pac(const struct samba_kdc_entry *skdc_entry)
663 : {
664 :
665 1658 : uint32_t userAccountControl;
666 :
667 : /* The service account may be set not to want the PAC */
668 48649 : userAccountControl = ldb_msg_find_attr_as_uint(skdc_entry->msg, "userAccountControl", 0);
669 48649 : if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
670 5 : return false;
671 : }
672 :
673 46986 : return true;
674 : }
675 :
676 20478 : static krb5_error_code samba_client_requested_pac(krb5_context context,
677 : const krb5_const_pac pac,
678 : TALLOC_CTX *mem_ctx,
679 : bool *requested_pac)
680 : {
681 623 : enum ndr_err_code ndr_err;
682 623 : krb5_data k5pac_attrs_in;
683 623 : DATA_BLOB pac_attrs_in;
684 623 : union PAC_INFO pac_attrs;
685 623 : krb5_error_code ret;
686 :
687 20478 : *requested_pac = true;
688 :
689 20478 : ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_ATTRIBUTES_INFO,
690 : &k5pac_attrs_in);
691 20478 : if (ret != 0) {
692 138 : return ret == ENOENT ? 0 : ret;
693 : }
694 :
695 20340 : pac_attrs_in = data_blob_const(k5pac_attrs_in.data,
696 0 : k5pac_attrs_in.length);
697 :
698 20340 : ndr_err = ndr_pull_union_blob(&pac_attrs_in, mem_ctx, &pac_attrs,
699 : PAC_TYPE_ATTRIBUTES_INFO,
700 : (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
701 20340 : smb_krb5_free_data_contents(context, &k5pac_attrs_in);
702 20340 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
703 0 : NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
704 0 : DBG_ERR("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status));
705 0 : return map_errno_from_nt_status(nt_status);
706 : }
707 :
708 20340 : if (pac_attrs.attributes_info.flags & (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
709 : | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED)) {
710 20334 : *requested_pac = true;
711 : } else {
712 6 : *requested_pac = false;
713 : }
714 :
715 19717 : return 0;
716 : }
717 :
718 : /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
719 50550 : krb5_error_code samba_krbtgt_is_in_db(const struct samba_kdc_entry *p,
720 : bool *is_in_db,
721 : bool *is_trusted)
722 : {
723 1658 : NTSTATUS status;
724 1658 : krb5_error_code ret;
725 1658 : int rodc_krbtgt_number, trust_direction;
726 1658 : struct dom_sid sid;
727 1658 : uint32_t rid;
728 :
729 50550 : trust_direction = ldb_msg_find_attr_as_int(p->msg, "trustDirection", 0);
730 :
731 50550 : if (trust_direction != 0) {
732 : /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
733 :
734 : This is exactly where we should flag for SID
735 : validation when we do inter-forest trusts
736 : */
737 51 : *is_trusted = true;
738 51 : *is_in_db = false;
739 51 : return 0;
740 : }
741 :
742 : /* The lack of password controls etc applies to krbtgt by
743 : * virtue of being that particular RID */
744 50499 : ret = samdb_result_dom_sid_buf(p->msg, "objectSid", &sid);
745 50499 : if (ret) {
746 0 : return ret;
747 : }
748 :
749 50499 : status = dom_sid_split_rid(NULL, &sid, NULL, &rid);
750 50499 : if (!NT_STATUS_IS_OK(status)) {
751 0 : return map_errno_from_nt_status(status);
752 : }
753 :
754 50499 : rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1);
755 :
756 50499 : if (p->kdc_db_ctx->my_krbtgt_number == 0) {
757 48106 : if (rid == DOMAIN_RID_KRBTGT) {
758 47880 : *is_trusted = true;
759 47880 : *is_in_db = true;
760 47880 : return 0;
761 226 : } else if (rodc_krbtgt_number != -1) {
762 226 : *is_in_db = true;
763 226 : *is_trusted = false;
764 226 : return 0;
765 : }
766 2393 : } else if ((rid != DOMAIN_RID_KRBTGT) && (rodc_krbtgt_number == p->kdc_db_ctx->my_krbtgt_number)) {
767 2393 : *is_trusted = true;
768 2393 : *is_in_db = true;
769 2393 : return 0;
770 0 : } else if (rid == DOMAIN_RID_KRBTGT) {
771 : /* krbtgt viewed from an RODC */
772 0 : *is_trusted = true;
773 0 : *is_in_db = false;
774 0 : return 0;
775 : }
776 :
777 : /* Another RODC */
778 0 : *is_trusted = false;
779 0 : *is_in_db = false;
780 0 : return 0;
781 : }
782 :
783 : /*
784 : * Because the KDC does not limit protocol transition, two new well-known SIDs
785 : * were introduced to give this control to the resource administrator. These
786 : * SIDs identify whether protocol transition has occurred, and can be used with
787 : * standard access control lists to grant or limit access as needed.
788 : *
789 : * https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview
790 : */
791 31096 : NTSTATUS samba_kdc_add_asserted_identity(enum samba_asserted_identity ai,
792 : struct auth_user_info_dc *user_info_dc)
793 : {
794 31096 : const struct dom_sid *ai_sid = NULL;
795 :
796 31096 : switch (ai) {
797 652 : case SAMBA_ASSERTED_IDENTITY_SERVICE:
798 652 : ai_sid = &global_sid_Asserted_Identity_Service;
799 652 : break;
800 30444 : case SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY:
801 30444 : ai_sid = &global_sid_Asserted_Identity_Authentication_Authority;
802 30444 : break;
803 0 : case SAMBA_ASSERTED_IDENTITY_IGNORE:
804 0 : return NT_STATUS_OK;
805 0 : default:
806 0 : return NT_STATUS_INVALID_PARAMETER;
807 : }
808 :
809 31096 : return add_sid_to_array_attrs_unique(
810 : user_info_dc,
811 : ai_sid,
812 : SE_GROUP_DEFAULT_FLAGS,
813 : &user_info_dc->sids,
814 : &user_info_dc->num_sids);
815 : }
816 :
817 31125 : NTSTATUS samba_kdc_add_claims_valid(struct auth_user_info_dc *user_info_dc)
818 : {
819 31125 : return add_sid_to_array_attrs_unique(
820 : user_info_dc,
821 : &global_sid_Claims_Valid,
822 : SE_GROUP_DEFAULT_FLAGS,
823 : &user_info_dc->sids,
824 : &user_info_dc->num_sids);
825 : }
826 :
827 8 : NTSTATUS samba_kdc_add_fresh_public_key_identity(struct auth_user_info_dc *user_info_dc)
828 : {
829 8 : return add_sid_to_array_attrs_unique(
830 : user_info_dc,
831 : &global_sid_Fresh_Public_Key_Identity,
832 : SE_GROUP_DEFAULT_FLAGS,
833 : &user_info_dc->sids,
834 : &user_info_dc->num_sids);
835 : }
836 :
837 73 : static NTSTATUS samba_kdc_add_compounded_auth(struct auth_user_info_dc *user_info_dc)
838 : {
839 73 : return add_sid_to_array_attrs_unique(
840 : user_info_dc,
841 : &global_sid_Compounded_Authentication,
842 : SE_GROUP_DEFAULT_FLAGS,
843 : &user_info_dc->sids,
844 : &user_info_dc->num_sids);
845 : }
846 :
847 197736 : bool samba_kdc_entry_is_trust(const struct samba_kdc_entry *entry)
848 : {
849 197736 : return entry != NULL && entry->is_trust;
850 : }
851 :
852 : /*
853 : * Return true if this entry has an associated PAC issued or signed by a KDC
854 : * that our KDC trusts. We trust the main krbtgt account, but we don’t trust any
855 : * RODC krbtgt besides ourselves.
856 : */
857 450738 : bool samba_krb5_pac_is_trusted(const struct samba_kdc_entry_pac pac)
858 : {
859 450738 : if (pac.pac == NULL) {
860 0 : return false;
861 : }
862 :
863 : #ifdef HAVE_KRB5_PAC_IS_TRUSTED /* Heimdal */
864 450738 : return krb5_pac_is_trusted(pac.pac);
865 : #else /* MIT */
866 0 : return pac.pac_is_trusted;
867 : #endif /* HAVE_KRB5_PAC_IS_TRUSTED */
868 : }
869 :
870 : #ifdef HAVE_KRB5_PAC_IS_TRUSTED /* Heimdal */
871 246448 : struct samba_kdc_entry_pac samba_kdc_entry_pac(krb5_const_pac pac,
872 : struct samba_kdc_entry *entry,
873 : bool is_from_trust)
874 : {
875 246448 : return (struct samba_kdc_entry_pac) {
876 : .entry = entry,
877 : .pac = pac,
878 : .is_from_trust = is_from_trust,
879 : };
880 : }
881 : #else /* MIT */
882 0 : struct samba_kdc_entry_pac samba_kdc_entry_pac_from_trusted(krb5_const_pac pac,
883 : struct samba_kdc_entry *entry,
884 : bool is_from_trust,
885 : bool is_trusted)
886 : {
887 0 : return (struct samba_kdc_entry_pac) {
888 : .entry = entry,
889 : .pac = pac,
890 : .is_from_trust = is_from_trust,
891 : .pac_is_trusted = is_trusted,
892 : };
893 : }
894 : #endif /* HAVE_KRB5_PAC_IS_TRUSTED */
895 :
896 50464 : static bool samba_kdc_entry_pac_issued_by_trust(const struct samba_kdc_entry_pac entry)
897 : {
898 50464 : return entry.pac != NULL && entry.is_from_trust;
899 : }
900 :
901 31067 : NTSTATUS samba_kdc_get_logon_info_blob(TALLOC_CTX *mem_ctx,
902 : const struct auth_user_info_dc *user_info_dc,
903 : const enum auth_group_inclusion group_inclusion,
904 : DATA_BLOB **_logon_info_blob)
905 : {
906 31067 : DATA_BLOB *logon_blob = NULL;
907 1170 : NTSTATUS nt_status;
908 :
909 31067 : *_logon_info_blob = NULL;
910 :
911 31067 : logon_blob = talloc_zero(mem_ctx, DATA_BLOB);
912 31067 : if (logon_blob == NULL) {
913 0 : return NT_STATUS_NO_MEMORY;
914 : }
915 :
916 31067 : nt_status = samba_get_logon_info_pac_blob(logon_blob,
917 : user_info_dc,
918 : NULL,
919 : group_inclusion,
920 : logon_blob);
921 31067 : if (!NT_STATUS_IS_OK(nt_status)) {
922 0 : DBG_ERR("Building PAC LOGON INFO failed: %s\n",
923 : nt_errstr(nt_status));
924 0 : talloc_free(logon_blob);
925 0 : return nt_status;
926 : }
927 :
928 31067 : *_logon_info_blob = logon_blob;
929 :
930 31067 : return NT_STATUS_OK;
931 : }
932 :
933 45 : NTSTATUS samba_kdc_get_cred_ndr_blob(TALLOC_CTX *mem_ctx,
934 : const struct samba_kdc_entry *p,
935 : DATA_BLOB **_cred_ndr_blob)
936 : {
937 45 : DATA_BLOB *cred_blob = NULL;
938 0 : NTSTATUS nt_status;
939 :
940 45 : SMB_ASSERT(_cred_ndr_blob != NULL);
941 :
942 45 : *_cred_ndr_blob = NULL;
943 :
944 45 : cred_blob = talloc_zero(mem_ctx, DATA_BLOB);
945 45 : if (cred_blob == NULL) {
946 0 : return NT_STATUS_NO_MEMORY;
947 : }
948 :
949 45 : nt_status = samba_get_cred_info_ndr_blob(cred_blob,
950 45 : p->msg,
951 : cred_blob);
952 45 : if (!NT_STATUS_IS_OK(nt_status)) {
953 0 : DBG_ERR("Building PAC CRED INFO failed: %s\n",
954 : nt_errstr(nt_status));
955 0 : talloc_free(cred_blob);
956 0 : return nt_status;
957 : }
958 :
959 45 : *_cred_ndr_blob = cred_blob;
960 :
961 45 : return NT_STATUS_OK;
962 : }
963 :
964 31067 : NTSTATUS samba_kdc_get_upn_info_blob(TALLOC_CTX *mem_ctx,
965 : const struct auth_user_info_dc *user_info_dc,
966 : DATA_BLOB **_upn_info_blob)
967 : {
968 31067 : DATA_BLOB *upn_blob = NULL;
969 1170 : NTSTATUS nt_status;
970 :
971 31067 : *_upn_info_blob = NULL;
972 :
973 31067 : upn_blob = talloc_zero(mem_ctx, DATA_BLOB);
974 31067 : if (upn_blob == NULL) {
975 0 : return NT_STATUS_NO_MEMORY;
976 : }
977 :
978 31067 : nt_status = samba_get_upn_info_pac_blob(upn_blob,
979 : user_info_dc,
980 : upn_blob);
981 31067 : if (!NT_STATUS_IS_OK(nt_status)) {
982 0 : DBG_ERR("Building PAC UPN INFO failed: %s\n",
983 : nt_errstr(nt_status));
984 0 : talloc_free(upn_blob);
985 0 : return nt_status;
986 : }
987 :
988 31067 : *_upn_info_blob = upn_blob;
989 :
990 31067 : return NT_STATUS_OK;
991 : }
992 :
993 27723 : NTSTATUS samba_kdc_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
994 : uint64_t pac_attributes,
995 : DATA_BLOB **_pac_attrs_blob)
996 : {
997 27723 : DATA_BLOB *pac_attrs_blob = NULL;
998 27723 : union PAC_INFO pac_attrs = {};
999 1170 : enum ndr_err_code ndr_err;
1000 1170 : NTSTATUS nt_status;
1001 :
1002 27723 : SMB_ASSERT(_pac_attrs_blob != NULL);
1003 :
1004 27723 : *_pac_attrs_blob = NULL;
1005 :
1006 27723 : pac_attrs_blob = talloc_zero(mem_ctx, DATA_BLOB);
1007 27723 : if (pac_attrs_blob == NULL) {
1008 0 : return NT_STATUS_NO_MEMORY;
1009 : }
1010 :
1011 : /* Set the length of the flags in bits. */
1012 27723 : pac_attrs.attributes_info.flags_length = 2;
1013 27723 : pac_attrs.attributes_info.flags = pac_attributes;
1014 :
1015 27723 : ndr_err = ndr_push_union_blob(pac_attrs_blob, pac_attrs_blob, &pac_attrs,
1016 : PAC_TYPE_ATTRIBUTES_INFO,
1017 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
1018 27723 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1019 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
1020 0 : DBG_WARNING("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
1021 : nt_errstr(nt_status));
1022 0 : DBG_ERR("Building PAC ATTRIBUTES failed: %s\n",
1023 : nt_errstr(nt_status));
1024 :
1025 0 : talloc_free(pac_attrs_blob);
1026 0 : return nt_status;
1027 : }
1028 :
1029 27723 : *_pac_attrs_blob = pac_attrs_blob;
1030 :
1031 27723 : return NT_STATUS_OK;
1032 : }
1033 :
1034 27741 : NTSTATUS samba_kdc_get_requester_sid_blob(TALLOC_CTX *mem_ctx,
1035 : const struct auth_user_info_dc *user_info_dc,
1036 : DATA_BLOB **_requester_sid_blob)
1037 : {
1038 27741 : DATA_BLOB *requester_sid_blob = NULL;
1039 1170 : NTSTATUS nt_status;
1040 :
1041 27741 : SMB_ASSERT(_requester_sid_blob != NULL);
1042 :
1043 27741 : *_requester_sid_blob = NULL;
1044 :
1045 27741 : requester_sid_blob = talloc_zero(mem_ctx, DATA_BLOB);
1046 27741 : if (requester_sid_blob == NULL) {
1047 0 : return NT_STATUS_NO_MEMORY;
1048 : }
1049 :
1050 27741 : if (user_info_dc->num_sids > 0) {
1051 27741 : union PAC_INFO pac_requester_sid = {};
1052 1170 : enum ndr_err_code ndr_err;
1053 :
1054 27741 : pac_requester_sid.requester_sid.sid = user_info_dc->sids[PRIMARY_USER_SID_INDEX].sid;
1055 :
1056 27741 : ndr_err = ndr_push_union_blob(requester_sid_blob, requester_sid_blob,
1057 : &pac_requester_sid,
1058 : PAC_TYPE_REQUESTER_SID,
1059 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
1060 27741 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1061 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
1062 0 : DBG_WARNING("PAC_REQUESTER_SID (presig) push failed: %s\n",
1063 : nt_errstr(nt_status));
1064 0 : DBG_ERR("Building PAC REQUESTER SID failed: %s\n",
1065 : nt_errstr(nt_status));
1066 :
1067 0 : talloc_free(requester_sid_blob);
1068 0 : return nt_status;
1069 : }
1070 : }
1071 :
1072 27741 : *_requester_sid_blob = requester_sid_blob;
1073 :
1074 27741 : return NT_STATUS_OK;
1075 : }
1076 :
1077 115 : NTSTATUS samba_kdc_get_claims_blob(TALLOC_CTX *mem_ctx,
1078 : struct samba_kdc_entry *p,
1079 : const DATA_BLOB **_claims_blob)
1080 : {
1081 115 : DATA_BLOB *claims_blob = NULL;
1082 115 : struct claims_data *claims_data = NULL;
1083 0 : NTSTATUS nt_status;
1084 0 : int ret;
1085 :
1086 115 : SMB_ASSERT(_claims_blob != NULL);
1087 :
1088 115 : *_claims_blob = NULL;
1089 :
1090 115 : claims_blob = talloc_zero(mem_ctx, DATA_BLOB);
1091 115 : if (claims_blob == NULL) {
1092 0 : return NT_STATUS_NO_MEMORY;
1093 : }
1094 :
1095 115 : ret = samba_kdc_get_claims_data_from_db(p->kdc_db_ctx->samdb,
1096 : p,
1097 : &claims_data);
1098 115 : if (ret != LDB_SUCCESS) {
1099 0 : nt_status = dsdb_ldb_err_to_ntstatus(ret);
1100 0 : DBG_ERR("Building claims failed: %s\n",
1101 : nt_errstr(nt_status));
1102 0 : talloc_free(claims_blob);
1103 0 : return nt_status;
1104 : }
1105 :
1106 115 : nt_status = claims_data_encoded_claims_set(claims_blob,
1107 : claims_data,
1108 : claims_blob);
1109 115 : if (!NT_STATUS_IS_OK(nt_status)) {
1110 0 : talloc_free(claims_blob);
1111 0 : return nt_status;
1112 : }
1113 :
1114 115 : *_claims_blob = claims_blob;
1115 :
1116 115 : return NT_STATUS_OK;
1117 : }
1118 :
1119 82961 : krb5_error_code samba_kdc_get_user_info_from_db(TALLOC_CTX *mem_ctx,
1120 : struct ldb_context *samdb,
1121 : struct samba_kdc_entry *entry,
1122 : const struct ldb_message *msg,
1123 : const struct auth_user_info_dc **info_out)
1124 : {
1125 2925 : NTSTATUS nt_status;
1126 :
1127 82961 : if (samdb == NULL) {
1128 0 : return EINVAL;
1129 : }
1130 :
1131 82961 : if (msg == NULL) {
1132 0 : return EINVAL;
1133 : }
1134 :
1135 82961 : if (info_out == NULL) {
1136 0 : return EINVAL;
1137 : }
1138 :
1139 82961 : if (entry == NULL) {
1140 0 : return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1141 : }
1142 :
1143 82961 : *info_out = NULL;
1144 :
1145 82961 : if (entry->info_from_db == NULL) {
1146 52474 : struct auth_user_info_dc *info_from_db = NULL;
1147 52474 : struct loadparm_context *lp_ctx = entry->kdc_db_ctx->lp_ctx;
1148 :
1149 52474 : nt_status = authsam_make_user_info_dc(entry,
1150 : samdb,
1151 : lpcfg_netbios_name(lp_ctx),
1152 : lpcfg_sam_name(lp_ctx),
1153 : lpcfg_sam_dnsname(lp_ctx),
1154 : entry->realm_dn,
1155 : msg,
1156 : data_blob_null,
1157 : data_blob_null,
1158 : &info_from_db);
1159 52474 : if (!NT_STATUS_IS_OK(nt_status)) {
1160 0 : DBG_ERR("Getting user info for PAC failed: %s\n",
1161 : nt_errstr(nt_status));
1162 : /* NT_STATUS_OBJECT_NAME_NOT_FOUND is mapped to ENOENT. */
1163 0 : return map_errno_from_nt_status(nt_status);
1164 : }
1165 :
1166 52474 : entry->info_from_db = info_from_db;
1167 : }
1168 :
1169 82961 : *info_out = entry->info_from_db;
1170 :
1171 82961 : return 0;
1172 : }
1173 :
1174 : /*
1175 : * Check whether a PAC contains the Authentication Authority Asserted Identity
1176 : * SID.
1177 : */
1178 169 : static krb5_error_code samba_kdc_pac_contains_asserted_identity(
1179 : krb5_context context,
1180 : const struct samba_kdc_entry_pac entry,
1181 : bool *contains_out)
1182 : {
1183 169 : TALLOC_CTX *frame = NULL;
1184 169 : struct auth_user_info_dc *info = NULL;
1185 169 : krb5_error_code ret = 0;
1186 :
1187 169 : if (contains_out == NULL) {
1188 0 : ret = EINVAL;
1189 0 : goto out;
1190 : }
1191 169 : *contains_out = false;
1192 :
1193 169 : frame = talloc_stackframe();
1194 :
1195 : /*
1196 : * Extract our info from the PAC. This does a bit of unnecessary work,
1197 : * setting up fields we don’t care about — we only want the SIDs.
1198 : */
1199 169 : ret = kerberos_pac_to_user_info_dc(frame,
1200 169 : entry.pac,
1201 : context,
1202 : &info,
1203 : AUTH_EXCLUDE_RESOURCE_GROUPS,
1204 : NULL /* pac_srv_sig */,
1205 : NULL /* pac_kdc_sig */,
1206 : /* Ignore the resource groups. */
1207 : NULL /* resource_groups */);
1208 169 : if (ret) {
1209 0 : const char *krb5err = krb5_get_error_message(context, ret);
1210 0 : DBG_ERR("kerberos_pac_to_user_info_dc failed: %s\n",
1211 : krb5err != NULL ? krb5err : "?");
1212 0 : krb5_free_error_message(context, krb5err);
1213 :
1214 0 : goto out;
1215 : }
1216 :
1217 : /* Determine whether the PAC contains the Asserted Identity SID. */
1218 169 : *contains_out = sid_attrs_contains_sid(
1219 169 : info->sids,
1220 169 : info->num_sids,
1221 : &global_sid_Asserted_Identity_Authentication_Authority);
1222 :
1223 169 : out:
1224 169 : talloc_free(frame);
1225 169 : return ret;
1226 : }
1227 :
1228 49359 : static krb5_error_code samba_kdc_get_user_info_from_pac(TALLOC_CTX *mem_ctx,
1229 : krb5_context context,
1230 : struct ldb_context *samdb,
1231 : const struct samba_kdc_entry_pac entry,
1232 : const struct auth_user_info_dc **info_out,
1233 : const struct PAC_DOMAIN_GROUP_MEMBERSHIP **resource_groups_out)
1234 : {
1235 49359 : TALLOC_CTX *frame = NULL;
1236 49359 : struct auth_user_info_dc *info = NULL;
1237 49359 : struct PAC_DOMAIN_GROUP_MEMBERSHIP *resource_groups = NULL;
1238 49359 : krb5_error_code ret = 0;
1239 1658 : NTSTATUS nt_status;
1240 :
1241 49359 : if (samdb == NULL) {
1242 0 : ret = EINVAL;
1243 0 : goto out;
1244 : }
1245 :
1246 49359 : if (!samba_krb5_pac_is_trusted(entry)) {
1247 0 : ret = EINVAL;
1248 0 : goto out;
1249 : }
1250 :
1251 49359 : if (info_out == NULL) {
1252 0 : ret = EINVAL;
1253 0 : goto out;
1254 : }
1255 :
1256 49359 : *info_out = NULL;
1257 49359 : if (resource_groups_out != NULL) {
1258 28051 : *resource_groups_out = NULL;
1259 : }
1260 :
1261 49359 : if (entry.entry == NULL || entry.entry->info_from_pac == NULL) {
1262 49329 : frame = talloc_stackframe();
1263 :
1264 50987 : ret = kerberos_pac_to_user_info_dc(frame,
1265 49329 : entry.pac,
1266 : context,
1267 : &info,
1268 : AUTH_EXCLUDE_RESOURCE_GROUPS,
1269 : NULL,
1270 : NULL,
1271 : &resource_groups);
1272 49329 : if (ret) {
1273 0 : const char *krb5err = krb5_get_error_message(context, ret);
1274 0 : DBG_ERR("kerberos_pac_to_user_info_dc failed: %s\n",
1275 : krb5err != NULL ? krb5err : "?");
1276 0 : krb5_free_error_message(context, krb5err);
1277 :
1278 0 : goto out;
1279 : }
1280 :
1281 : /*
1282 : * We need to expand group memberships within our local domain,
1283 : * as the token might be generated by a trusted domain.
1284 : */
1285 49329 : nt_status = authsam_update_user_info_dc(frame,
1286 : samdb,
1287 : info);
1288 49329 : if (!NT_STATUS_IS_OK(nt_status)) {
1289 0 : DBG_ERR("authsam_update_user_info_dc failed: %s\n",
1290 : nt_errstr(nt_status));
1291 :
1292 0 : ret = map_errno_from_nt_status(nt_status);
1293 0 : goto out;
1294 : }
1295 :
1296 49329 : if (entry.entry != NULL) {
1297 49277 : entry.entry->info_from_pac = talloc_steal(entry.entry, info);
1298 49277 : entry.entry->resource_groups_from_pac = talloc_steal(entry.entry, resource_groups);
1299 : }
1300 : }
1301 :
1302 :
1303 49359 : if (entry.entry != NULL) {
1304 : /* Note: the caller does not own this! */
1305 49307 : *info_out = entry.entry->info_from_pac;
1306 :
1307 49307 : if (resource_groups_out != NULL) {
1308 : /* Note: the caller does not own this! */
1309 28051 : *resource_groups_out = entry.entry->resource_groups_from_pac;
1310 : }
1311 : } else {
1312 52 : *info_out = talloc_steal(mem_ctx, info);
1313 :
1314 52 : if (resource_groups_out != NULL) {
1315 0 : *resource_groups_out = talloc_steal(mem_ctx, resource_groups);
1316 : }
1317 : }
1318 :
1319 52 : out:
1320 49359 : talloc_free(frame);
1321 49359 : return ret;
1322 : }
1323 :
1324 49528 : krb5_error_code samba_kdc_get_user_info_dc(TALLOC_CTX *mem_ctx,
1325 : krb5_context context,
1326 : struct ldb_context *samdb,
1327 : const struct samba_kdc_entry_pac entry,
1328 : const struct auth_user_info_dc **info_out,
1329 : const struct PAC_DOMAIN_GROUP_MEMBERSHIP **resource_groups_out)
1330 : {
1331 49528 : const struct auth_user_info_dc *info = NULL;
1332 49528 : struct auth_user_info_dc *info_shallow_copy = NULL;
1333 49528 : bool pac_contains_asserted_identity = false;
1334 49528 : krb5_error_code ret = 0;
1335 1658 : NTSTATUS nt_status;
1336 :
1337 49528 : *info_out = NULL;
1338 49528 : if (resource_groups_out != NULL) {
1339 28069 : *resource_groups_out = NULL;
1340 : }
1341 :
1342 49528 : if (samba_krb5_pac_is_trusted(entry)) {
1343 49359 : return samba_kdc_get_user_info_from_pac(mem_ctx,
1344 : context,
1345 : samdb,
1346 : entry,
1347 : info_out,
1348 : resource_groups_out);
1349 : }
1350 :
1351 169 : if (entry.entry == NULL) {
1352 0 : return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1353 : }
1354 :
1355 : /*
1356 : * In this case the RWDC discards the PAC an RODC generated.
1357 : * Windows adds the asserted_identity in this case too.
1358 : *
1359 : * Note that SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
1360 : * generates KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN.
1361 : * So we can always use
1362 : * SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
1363 : * here.
1364 : */
1365 169 : ret = samba_kdc_get_user_info_from_db(mem_ctx,
1366 : samdb,
1367 169 : entry.entry,
1368 169 : entry.entry->msg,
1369 : &info);
1370 169 : if (ret) {
1371 0 : const char *krb5err = krb5_get_error_message(context, ret);
1372 0 : DBG_ERR("samba_kdc_get_user_info_from_db: %s\n",
1373 : krb5err != NULL ? krb5err : "?");
1374 0 : krb5_free_error_message(context, krb5err);
1375 :
1376 0 : return KRB5KDC_ERR_TGT_REVOKED;
1377 : }
1378 :
1379 : /* Make a shallow copy of the user_info_dc structure. */
1380 169 : nt_status = authsam_shallow_copy_user_info_dc(mem_ctx,
1381 : info,
1382 : &info_shallow_copy);
1383 169 : info = NULL;
1384 :
1385 169 : if (!NT_STATUS_IS_OK(nt_status)) {
1386 0 : DBG_ERR("Failed to allocate user_info_dc SIDs: %s\n",
1387 : nt_errstr(nt_status));
1388 0 : return map_errno_from_nt_status(nt_status);
1389 : }
1390 :
1391 : /* Determine whether the PAC contains the Asserted Identity SID. */
1392 169 : ret = samba_kdc_pac_contains_asserted_identity(
1393 : context, entry, &pac_contains_asserted_identity);
1394 169 : if (ret) {
1395 0 : return ret;
1396 : }
1397 :
1398 169 : if (pac_contains_asserted_identity) {
1399 140 : nt_status = samba_kdc_add_asserted_identity(
1400 : SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY,
1401 : info_shallow_copy);
1402 140 : if (!NT_STATUS_IS_OK(nt_status)) {
1403 0 : DBG_ERR("Failed to add asserted identity: %s\n",
1404 : nt_errstr(nt_status));
1405 0 : TALLOC_FREE(info_shallow_copy);
1406 0 : return KRB5KDC_ERR_TGT_REVOKED;
1407 : }
1408 : }
1409 :
1410 169 : nt_status = samba_kdc_add_claims_valid(info_shallow_copy);
1411 169 : if (!NT_STATUS_IS_OK(nt_status)) {
1412 0 : DBG_ERR("Failed to add Claims Valid: %s\n",
1413 : nt_errstr(nt_status));
1414 0 : TALLOC_FREE(info_shallow_copy);
1415 0 : return KRB5KDC_ERR_TGT_REVOKED;
1416 : }
1417 :
1418 169 : *info_out = info_shallow_copy;
1419 :
1420 169 : return 0;
1421 : }
1422 :
1423 152 : static NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx,
1424 : krb5_context context,
1425 : const krb5_const_pac pac,
1426 : const krb5_const_principal server_principal,
1427 : const krb5_const_principal proxy_principal,
1428 : DATA_BLOB *new_blob)
1429 : {
1430 152 : krb5_data old_data = {};
1431 0 : DATA_BLOB old_blob;
1432 0 : krb5_error_code ret;
1433 152 : NTSTATUS nt_status = NT_STATUS_OK;
1434 0 : enum ndr_err_code ndr_err;
1435 152 : union PAC_INFO info = {};
1436 152 : struct PAC_CONSTRAINED_DELEGATION _d = {};
1437 152 : struct PAC_CONSTRAINED_DELEGATION *d = NULL;
1438 152 : char *server = NULL;
1439 152 : char *proxy = NULL;
1440 0 : uint32_t i;
1441 152 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1442 :
1443 152 : if (tmp_ctx == NULL) {
1444 0 : nt_status = NT_STATUS_NO_MEMORY;
1445 0 : goto out;
1446 : }
1447 :
1448 152 : ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_CONSTRAINED_DELEGATION, &old_data);
1449 152 : if (ret == ENOENT) {
1450 : /* OK. */
1451 3 : } else if (ret) {
1452 0 : nt_status = NT_STATUS_UNSUCCESSFUL;
1453 0 : goto out;
1454 : }
1455 :
1456 152 : old_blob.length = old_data.length;
1457 152 : old_blob.data = (uint8_t *)old_data.data;
1458 :
1459 152 : if (old_blob.length > 0) {
1460 3 : ndr_err = ndr_pull_union_blob(&old_blob, tmp_ctx,
1461 : &info, PAC_TYPE_CONSTRAINED_DELEGATION,
1462 : (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1463 3 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1464 0 : smb_krb5_free_data_contents(context, &old_data);
1465 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
1466 0 : DBG_ERR("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status));
1467 0 : goto out;
1468 : }
1469 : } else {
1470 149 : info.constrained_delegation.info = &_d;
1471 : }
1472 152 : smb_krb5_free_data_contents(context, &old_data);
1473 :
1474 152 : ret = krb5_unparse_name_flags(context, server_principal,
1475 : KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server);
1476 152 : if (ret) {
1477 0 : nt_status = NT_STATUS_INTERNAL_ERROR;
1478 0 : goto out;
1479 : }
1480 :
1481 152 : ret = krb5_unparse_name(context, proxy_principal, &proxy);
1482 152 : if (ret) {
1483 0 : SAFE_FREE(server);
1484 0 : nt_status = NT_STATUS_INTERNAL_ERROR;
1485 0 : goto out;
1486 : }
1487 :
1488 152 : d = info.constrained_delegation.info;
1489 152 : i = d->num_transited_services;
1490 152 : d->proxy_target.string = server;
1491 152 : d->transited_services = talloc_realloc(mem_ctx, d->transited_services,
1492 : struct lsa_String, i + 1);
1493 152 : if (d->transited_services == NULL) {
1494 0 : SAFE_FREE(server);
1495 0 : SAFE_FREE(proxy);
1496 0 : nt_status = NT_STATUS_INTERNAL_ERROR;
1497 0 : goto out;
1498 : }
1499 152 : d->transited_services[i].string = proxy;
1500 152 : d->num_transited_services = i + 1;
1501 :
1502 152 : ndr_err = ndr_push_union_blob(new_blob, mem_ctx,
1503 : &info, PAC_TYPE_CONSTRAINED_DELEGATION,
1504 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
1505 152 : SAFE_FREE(server);
1506 152 : SAFE_FREE(proxy);
1507 152 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1508 0 : smb_krb5_free_data_contents(context, &old_data);
1509 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
1510 0 : DBG_ERR("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status));
1511 0 : goto out;
1512 : }
1513 :
1514 152 : out:
1515 152 : talloc_free(tmp_ctx);
1516 152 : return nt_status;
1517 : }
1518 :
1519 : /* function to map policy errors */
1520 43 : krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status)
1521 : {
1522 0 : krb5_error_code ret;
1523 :
1524 43 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE))
1525 5 : ret = KRB5KDC_ERR_KEY_EXP;
1526 38 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED))
1527 0 : ret = KRB5KDC_ERR_KEY_EXP;
1528 38 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED))
1529 0 : ret = KRB5KDC_ERR_CLIENT_REVOKED;
1530 38 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED))
1531 8 : ret = KRB5KDC_ERR_CLIENT_REVOKED;
1532 30 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS))
1533 4 : ret = KRB5KDC_ERR_CLIENT_REVOKED;
1534 26 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT))
1535 26 : ret = KRB5KDC_ERR_CLIENT_REVOKED;
1536 0 : else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION))
1537 0 : ret = KRB5KDC_ERR_POLICY;
1538 : else
1539 0 : ret = KRB5KDC_ERR_POLICY;
1540 :
1541 43 : return ret;
1542 : }
1543 :
1544 : /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
1545 : * for consistency */
1546 49267 : NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry,
1547 : const char *client_name,
1548 : const char *workstation,
1549 : bool password_change)
1550 : {
1551 1755 : TALLOC_CTX *tmp_ctx;
1552 1755 : NTSTATUS nt_status;
1553 :
1554 49267 : tmp_ctx = talloc_named(NULL, 0, "samba_kdc_check_client_access");
1555 49267 : if (!tmp_ctx) {
1556 0 : return NT_STATUS_NO_MEMORY;
1557 : }
1558 :
1559 : /* we allow all kinds of trusts here */
1560 49267 : nt_status = authsam_account_ok(tmp_ctx,
1561 49267 : kdc_entry->kdc_db_ctx->samdb,
1562 : MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
1563 : MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
1564 : kdc_entry->realm_dn, kdc_entry->msg,
1565 : workstation, client_name,
1566 : true, password_change);
1567 :
1568 49267 : kdc_entry->reject_status = nt_status;
1569 49267 : talloc_free(tmp_ctx);
1570 49267 : return nt_status;
1571 : }
1572 :
1573 50457 : static krb5_error_code samba_get_requester_sid(TALLOC_CTX *mem_ctx,
1574 : krb5_const_pac pac,
1575 : krb5_context context,
1576 : struct dom_sid *sid)
1577 : {
1578 1658 : NTSTATUS nt_status;
1579 1658 : enum ndr_err_code ndr_err;
1580 50457 : krb5_error_code ret = 0;
1581 :
1582 1658 : DATA_BLOB pac_requester_sid_in;
1583 1658 : krb5_data k5pac_requester_sid_in;
1584 :
1585 1658 : union PAC_INFO info;
1586 :
1587 50457 : TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1588 50457 : if (tmp_ctx == NULL) {
1589 0 : ret = ENOMEM;
1590 0 : goto out;
1591 : }
1592 :
1593 50457 : ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_REQUESTER_SID,
1594 : &k5pac_requester_sid_in);
1595 50457 : if (ret != 0) {
1596 164 : goto out;
1597 : }
1598 :
1599 50293 : pac_requester_sid_in = data_blob_const(k5pac_requester_sid_in.data,
1600 0 : k5pac_requester_sid_in.length);
1601 :
1602 50293 : ndr_err = ndr_pull_union_blob(&pac_requester_sid_in, tmp_ctx, &info,
1603 : PAC_TYPE_REQUESTER_SID,
1604 : (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1605 50293 : smb_krb5_free_data_contents(context, &k5pac_requester_sid_in);
1606 50293 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1607 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
1608 0 : DBG_ERR("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status));
1609 0 : ret = map_errno_from_nt_status(nt_status);
1610 0 : goto out;
1611 : }
1612 :
1613 50293 : *sid = info.requester_sid.sid;
1614 :
1615 50457 : out:
1616 50457 : talloc_free(tmp_ctx);
1617 50457 : return ret;
1618 : }
1619 :
1620 : /* Does a parse and SID check, but no crypto. */
1621 50457 : static krb5_error_code samba_kdc_validate_pac_blob(
1622 : krb5_context context,
1623 : const struct samba_kdc_entry_pac client)
1624 : {
1625 50457 : TALLOC_CTX *frame = talloc_stackframe();
1626 50457 : struct auth_user_info_dc *pac_user_info = NULL;
1627 1658 : struct dom_sid client_sid;
1628 1658 : struct dom_sid pac_sid;
1629 1658 : krb5_error_code code;
1630 1658 : bool ok;
1631 :
1632 : /*
1633 : * First, try to get the SID from the requester SID buffer in the PAC.
1634 : */
1635 50457 : code = samba_get_requester_sid(frame, client.pac, context, &pac_sid);
1636 :
1637 50457 : if (code == ENOENT) {
1638 : /*
1639 : * If the requester SID buffer isn't present, fall back to the
1640 : * SID in the LOGON_INFO PAC buffer.
1641 : */
1642 164 : code = kerberos_pac_to_user_info_dc(frame,
1643 164 : client.pac,
1644 : context,
1645 : &pac_user_info,
1646 : AUTH_EXCLUDE_RESOURCE_GROUPS,
1647 : NULL,
1648 : NULL,
1649 : NULL);
1650 164 : if (code != 0) {
1651 0 : goto out;
1652 : }
1653 :
1654 164 : if (pac_user_info->num_sids == 0) {
1655 0 : code = EINVAL;
1656 0 : goto out;
1657 : }
1658 :
1659 164 : pac_sid = pac_user_info->sids[PRIMARY_USER_SID_INDEX].sid;
1660 50293 : } else if (code != 0) {
1661 0 : goto out;
1662 : }
1663 :
1664 50457 : code = samdb_result_dom_sid_buf(client.entry->msg,
1665 : "objectSid",
1666 : &client_sid);
1667 50457 : if (code) {
1668 0 : goto out;
1669 : }
1670 :
1671 50457 : ok = dom_sid_equal(&pac_sid, &client_sid);
1672 50457 : if (!ok) {
1673 0 : struct dom_sid_buf buf1;
1674 0 : struct dom_sid_buf buf2;
1675 :
1676 38 : DBG_ERR("SID mismatch between PAC and looked up client: "
1677 : "PAC[%s] != CLI[%s]\n",
1678 : dom_sid_str_buf(&pac_sid, &buf1),
1679 : dom_sid_str_buf(&client_sid, &buf2));
1680 38 : code = KRB5KDC_ERR_TGT_REVOKED;
1681 38 : goto out;
1682 : }
1683 :
1684 48761 : code = 0;
1685 50457 : out:
1686 50457 : TALLOC_FREE(frame);
1687 50457 : return code;
1688 : }
1689 :
1690 :
1691 : /*
1692 : * In the RODC case, to confirm that the returned user is permitted to
1693 : * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
1694 : */
1695 210 : static WERROR samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids,
1696 : const struct dom_sid *object_sids,
1697 : const struct samba_kdc_entry *rodc,
1698 : const struct samba_kdc_entry *object)
1699 : {
1700 0 : int ret;
1701 0 : WERROR werr;
1702 210 : TALLOC_CTX *frame = talloc_stackframe();
1703 210 : const char *rodc_attrs[] = { "msDS-KrbTgtLink",
1704 : "msDS-NeverRevealGroup",
1705 : "msDS-RevealOnDemandGroup",
1706 : "userAccountControl",
1707 : "objectSid",
1708 : NULL };
1709 210 : struct ldb_result *rodc_machine_account = NULL;
1710 210 : struct ldb_dn *rodc_machine_account_dn = samdb_result_dn(rodc->kdc_db_ctx->samdb,
1711 : frame,
1712 210 : rodc->msg,
1713 : "msDS-KrbTgtLinkBL",
1714 : NULL);
1715 210 : const struct dom_sid *rodc_machine_account_sid = NULL;
1716 :
1717 210 : if (rodc_machine_account_dn == NULL) {
1718 6 : DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
1719 : ldb_dn_get_linearized(rodc->msg->dn));
1720 6 : TALLOC_FREE(frame);
1721 6 : return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1722 : }
1723 :
1724 : /*
1725 : * Follow the link and get the RODC account (the krbtgt
1726 : * account is the krbtgt_XXX account, but the
1727 : * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
1728 : * the RODC$ account)
1729 : *
1730 : * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
1731 : * out of the extended DNs
1732 : */
1733 :
1734 204 : ret = dsdb_search_dn(rodc->kdc_db_ctx->samdb,
1735 : frame,
1736 : &rodc_machine_account,
1737 : rodc_machine_account_dn,
1738 : rodc_attrs,
1739 : DSDB_SEARCH_SHOW_EXTENDED_DN);
1740 204 : if (ret != LDB_SUCCESS) {
1741 0 : DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
1742 : ldb_dn_get_linearized(rodc_machine_account_dn),
1743 : ldb_dn_get_linearized(rodc->msg->dn),
1744 : ldb_errstring(rodc->kdc_db_ctx->samdb));
1745 0 : TALLOC_FREE(frame);
1746 0 : return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1747 : }
1748 :
1749 204 : if (rodc_machine_account->count != 1) {
1750 0 : DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
1751 : ldb_dn_get_linearized(rodc_machine_account_dn),
1752 : ldb_dn_get_linearized(rodc->msg->dn),
1753 : rodc_machine_account->count);
1754 0 : TALLOC_FREE(frame);
1755 0 : return WERR_DS_DRA_BAD_DN;
1756 : }
1757 :
1758 : /* if the object SID is equal to the user_sid, allow */
1759 204 : rodc_machine_account_sid = samdb_result_dom_sid(frame,
1760 204 : rodc_machine_account->msgs[0],
1761 : "objectSid");
1762 204 : if (rodc_machine_account_sid == NULL) {
1763 0 : TALLOC_FREE(frame);
1764 0 : return WERR_DS_DRA_BAD_DN;
1765 : }
1766 :
1767 204 : werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc->kdc_db_ctx->samdb,
1768 : rodc_machine_account_sid,
1769 204 : rodc_machine_account->msgs[0],
1770 204 : object->msg,
1771 : num_object_sids,
1772 : object_sids);
1773 :
1774 204 : TALLOC_FREE(frame);
1775 204 : return werr;
1776 : }
1777 :
1778 : /*
1779 : * Perform an access check for the client attempting to authenticate to the
1780 : * server. ‘client_info’ must be talloc-allocated so that we can make a
1781 : * reference to it.
1782 : */
1783 170 : krb5_error_code samba_kdc_allowed_to_authenticate_to(TALLOC_CTX *mem_ctx,
1784 : struct ldb_context *samdb,
1785 : struct loadparm_context *lp_ctx,
1786 : const struct samba_kdc_entry *client,
1787 : const struct auth_user_info_dc *client_info,
1788 : const struct auth_user_info_dc *device_info,
1789 : const struct auth_claims auth_claims,
1790 : const struct samba_kdc_entry *server,
1791 : struct authn_audit_info **server_audit_info_out,
1792 : NTSTATUS *status_out)
1793 : {
1794 170 : krb5_error_code ret = 0;
1795 0 : NTSTATUS status;
1796 0 : _UNUSED_ NTSTATUS _status;
1797 170 : struct dom_sid server_sid = {};
1798 170 : const struct authn_server_policy *server_policy = server->server_policy;
1799 :
1800 170 : if (status_out != NULL) {
1801 170 : *status_out = NT_STATUS_OK;
1802 : }
1803 :
1804 170 : ret = samdb_result_dom_sid_buf(server->msg, "objectSid", &server_sid);
1805 170 : if (ret) {
1806 : /*
1807 : * Ignore the return status — we are already in an error path,
1808 : * and overwriting the real error code with the audit info
1809 : * status is unhelpful.
1810 : */
1811 0 : _status = authn_server_policy_audit_info(mem_ctx,
1812 : server_policy,
1813 : client_info,
1814 : AUTHN_AUDIT_EVENT_OTHER_ERROR,
1815 : AUTHN_AUDIT_REASON_NONE,
1816 : dsdb_ldb_err_to_ntstatus(ret),
1817 : server_audit_info_out);
1818 0 : goto out;
1819 : }
1820 :
1821 170 : if (dom_sid_equal(&client_info->sids[PRIMARY_USER_SID_INDEX].sid, &server_sid)) {
1822 : /* Authenticating to ourselves is always allowed. */
1823 8 : status = authn_server_policy_audit_info(mem_ctx,
1824 : server_policy,
1825 : client_info,
1826 : AUTHN_AUDIT_EVENT_OK,
1827 : AUTHN_AUDIT_REASON_NONE,
1828 : NT_STATUS_OK,
1829 : server_audit_info_out);
1830 8 : if (!NT_STATUS_IS_OK(status)) {
1831 0 : ret = KRB5KRB_ERR_GENERIC;
1832 : }
1833 8 : goto out;
1834 : }
1835 :
1836 162 : status = authn_policy_authenticate_to_service(mem_ctx,
1837 : samdb,
1838 : lp_ctx,
1839 : AUTHN_POLICY_AUTH_TYPE_KERBEROS,
1840 : client_info,
1841 : device_info,
1842 : auth_claims,
1843 : server_policy,
1844 162 : (struct authn_policy_flags) { .force_compounded_authentication = true },
1845 : server_audit_info_out);
1846 162 : if (!NT_STATUS_IS_OK(status)) {
1847 67 : if (status_out != NULL) {
1848 67 : *status_out = status;
1849 : }
1850 67 : if (NT_STATUS_EQUAL(status, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED)) {
1851 66 : ret = KRB5KDC_ERR_POLICY;
1852 1 : } else if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
1853 1 : ret = KRB5KDC_ERR_POLICY;
1854 : } else {
1855 0 : ret = KRB5KRB_ERR_GENERIC;
1856 : }
1857 : }
1858 :
1859 95 : out:
1860 170 : return ret;
1861 : }
1862 :
1863 94 : static krb5_error_code samba_kdc_add_domain_group_sid(struct PAC_DEVICE_INFO *info,
1864 : const struct netr_SidAttr *sid)
1865 : {
1866 0 : uint32_t i;
1867 0 : uint32_t rid;
1868 0 : NTSTATUS status;
1869 :
1870 94 : uint32_t domain_group_count = info->domain_group_count;
1871 94 : struct PAC_DOMAIN_GROUP_MEMBERSHIP *domain_group = NULL;
1872 94 : struct samr_RidWithAttribute *rids = NULL;
1873 :
1874 132 : for (i = 0; i < domain_group_count; ++i) {
1875 53 : struct PAC_DOMAIN_GROUP_MEMBERSHIP *this_domain_group
1876 53 : = &info->domain_groups[i];
1877 :
1878 53 : if (dom_sid_in_domain(this_domain_group->domain_sid, sid->sid)) {
1879 15 : domain_group = this_domain_group;
1880 15 : break;
1881 : }
1882 : }
1883 :
1884 94 : if (domain_group == NULL) {
1885 79 : struct PAC_DOMAIN_GROUP_MEMBERSHIP *domain_groups = NULL;
1886 :
1887 79 : if (domain_group_count == UINT32_MAX) {
1888 0 : return EINVAL;
1889 : }
1890 :
1891 79 : domain_groups = talloc_realloc(
1892 : info,
1893 : info->domain_groups,
1894 : struct PAC_DOMAIN_GROUP_MEMBERSHIP,
1895 : domain_group_count + 1);
1896 79 : if (domain_groups == NULL) {
1897 0 : return ENOMEM;
1898 : }
1899 :
1900 79 : info->domain_groups = domain_groups;
1901 :
1902 79 : domain_group = &info->domain_groups[domain_group_count++];
1903 79 : *domain_group = (struct PAC_DOMAIN_GROUP_MEMBERSHIP) {};
1904 :
1905 79 : status = dom_sid_split_rid(info->domain_groups,
1906 79 : sid->sid,
1907 : &domain_group->domain_sid,
1908 : &rid);
1909 79 : if (!NT_STATUS_IS_OK(status)) {
1910 0 : return map_errno_from_nt_status(status);
1911 : }
1912 : } else {
1913 15 : status = dom_sid_split_rid(NULL,
1914 15 : sid->sid,
1915 : NULL,
1916 : &rid);
1917 15 : if (!NT_STATUS_IS_OK(status)) {
1918 0 : return map_errno_from_nt_status(status);
1919 : }
1920 : }
1921 :
1922 94 : if (domain_group->groups.count == UINT32_MAX) {
1923 0 : return EINVAL;
1924 : }
1925 :
1926 94 : rids = talloc_realloc(info->domain_groups,
1927 : domain_group->groups.rids,
1928 : struct samr_RidWithAttribute,
1929 : domain_group->groups.count + 1);
1930 94 : if (rids == NULL) {
1931 0 : return ENOMEM;
1932 : }
1933 :
1934 94 : domain_group->groups.rids = rids;
1935 :
1936 94 : domain_group->groups.rids[domain_group->groups.count] = (struct samr_RidWithAttribute) {
1937 : .rid = rid,
1938 94 : .attributes = sid->attributes,
1939 : };
1940 :
1941 94 : ++domain_group->groups.count;
1942 :
1943 94 : info->domain_group_count = domain_group_count;
1944 :
1945 94 : return 0;
1946 : }
1947 :
1948 73 : static krb5_error_code samba_kdc_make_device_info(TALLOC_CTX *mem_ctx,
1949 : const struct netr_SamInfo3 *info3,
1950 : struct PAC_DOMAIN_GROUP_MEMBERSHIP *resource_groups,
1951 : union PAC_INFO *info)
1952 : {
1953 73 : TALLOC_CTX *tmp_ctx = NULL;
1954 73 : struct PAC_DEVICE_INFO *device_info = NULL;
1955 0 : uint32_t i;
1956 73 : krb5_error_code ret = 0;
1957 :
1958 73 : *info = (union PAC_INFO) {};
1959 :
1960 73 : info->device_info.info = NULL;
1961 :
1962 73 : tmp_ctx = talloc_new(mem_ctx);
1963 73 : if (tmp_ctx == NULL) {
1964 0 : return ENOMEM;
1965 : }
1966 :
1967 73 : device_info = talloc(tmp_ctx, struct PAC_DEVICE_INFO);
1968 73 : if (device_info == NULL) {
1969 0 : ret = ENOMEM;
1970 0 : goto out;
1971 : }
1972 :
1973 73 : device_info->rid = info3->base.rid;
1974 73 : device_info->primary_gid = info3->base.primary_gid;
1975 73 : device_info->domain_sid = info3->base.domain_sid;
1976 73 : device_info->groups = info3->base.groups;
1977 :
1978 73 : device_info->sid_count = 0;
1979 73 : device_info->sids = NULL;
1980 :
1981 73 : if (resource_groups != NULL) {
1982 : /*
1983 : * The account's resource groups all belong to the same domain,
1984 : * so we can add them all in one go.
1985 : */
1986 1 : device_info->domain_group_count = 1;
1987 1 : device_info->domain_groups = talloc_move(device_info, &resource_groups);
1988 : } else {
1989 72 : device_info->domain_group_count = 0;
1990 72 : device_info->domain_groups = NULL;
1991 : }
1992 :
1993 245 : for (i = 0; i < info3->sidcount; ++i) {
1994 172 : const struct netr_SidAttr *device_sid = &info3->sids[i];
1995 :
1996 172 : if (dom_sid_has_account_domain(device_sid->sid)) {
1997 68 : ret = samba_kdc_add_domain_group_sid(device_info, device_sid);
1998 68 : if (ret != 0) {
1999 0 : goto out;
2000 : }
2001 : } else {
2002 104 : device_info->sids = talloc_realloc(device_info, device_info->sids,
2003 : struct netr_SidAttr,
2004 : device_info->sid_count + 1);
2005 104 : if (device_info->sids == NULL) {
2006 0 : ret = ENOMEM;
2007 0 : goto out;
2008 : }
2009 :
2010 104 : device_info->sids[device_info->sid_count].sid = dom_sid_dup(device_info->sids, device_sid->sid);
2011 104 : if (device_info->sids[device_info->sid_count].sid == NULL) {
2012 0 : ret = ENOMEM;
2013 0 : goto out;
2014 : }
2015 :
2016 104 : device_info->sids[device_info->sid_count].attributes = device_sid->attributes;
2017 :
2018 104 : ++device_info->sid_count;
2019 : }
2020 : }
2021 :
2022 73 : info->device_info.info = talloc_steal(mem_ctx, device_info);
2023 :
2024 73 : out:
2025 73 : talloc_free(tmp_ctx);
2026 73 : return ret;
2027 : }
2028 :
2029 64 : static krb5_error_code samba_kdc_update_device_info(TALLOC_CTX *mem_ctx,
2030 : struct ldb_context *samdb,
2031 : const union PAC_INFO *logon_info,
2032 : struct PAC_DEVICE_INFO *device_info)
2033 : {
2034 0 : NTSTATUS nt_status;
2035 64 : struct auth_user_info_dc *device_info_dc = NULL;
2036 0 : union netr_Validation validation;
2037 0 : uint32_t i;
2038 0 : uint32_t num_existing_sids;
2039 :
2040 : /*
2041 : * This does a bit of unnecessary work, setting up fields we don't care
2042 : * about -- we only want the SIDs.
2043 : */
2044 64 : validation.sam3 = &logon_info->logon_info.info->info3;
2045 64 : nt_status = make_user_info_dc_netlogon_validation(mem_ctx, "", 3, &validation,
2046 : true, /* This user was authenticated */
2047 : &device_info_dc);
2048 64 : if (!NT_STATUS_IS_OK(nt_status)) {
2049 0 : return map_errno_from_nt_status(nt_status);
2050 : }
2051 :
2052 64 : num_existing_sids = device_info_dc->num_sids;
2053 :
2054 : /*
2055 : * We need to expand group memberships within our local domain,
2056 : * as the token might be generated by a trusted domain.
2057 : */
2058 64 : nt_status = authsam_update_user_info_dc(mem_ctx,
2059 : samdb,
2060 : device_info_dc);
2061 64 : if (!NT_STATUS_IS_OK(nt_status)) {
2062 0 : return map_errno_from_nt_status(nt_status);
2063 : }
2064 :
2065 90 : for (i = num_existing_sids; i < device_info_dc->num_sids; ++i) {
2066 26 : struct auth_SidAttr *device_sid = &device_info_dc->sids[i];
2067 26 : const struct netr_SidAttr sid = (struct netr_SidAttr) {
2068 26 : .sid = &device_sid->sid,
2069 26 : .attributes = device_sid->attrs,
2070 : };
2071 :
2072 26 : krb5_error_code ret = samba_kdc_add_domain_group_sid(device_info, &sid);
2073 26 : if (ret != 0) {
2074 0 : return ret;
2075 : }
2076 : }
2077 :
2078 64 : return 0;
2079 : }
2080 :
2081 73 : static krb5_error_code samba_kdc_get_device_info_pac_blob(TALLOC_CTX *mem_ctx,
2082 : union PAC_INFO *info,
2083 : DATA_BLOB **_device_info_blob)
2084 : {
2085 73 : DATA_BLOB *device_info_blob = NULL;
2086 0 : enum ndr_err_code ndr_err;
2087 :
2088 73 : *_device_info_blob = NULL;
2089 :
2090 73 : device_info_blob = talloc_zero(mem_ctx, DATA_BLOB);
2091 73 : if (device_info_blob == NULL) {
2092 0 : DBG_ERR("Out of memory\n");
2093 0 : return ENOMEM;
2094 : }
2095 :
2096 73 : ndr_err = ndr_push_union_blob(device_info_blob, device_info_blob,
2097 : info, PAC_TYPE_DEVICE_INFO,
2098 : (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
2099 73 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2100 0 : NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
2101 0 : DBG_WARNING("PAC_DEVICE_INFO (presig) push failed: %s\n",
2102 : nt_errstr(nt_status));
2103 0 : talloc_free(device_info_blob);
2104 0 : return map_errno_from_nt_status(nt_status);
2105 : }
2106 :
2107 73 : *_device_info_blob = device_info_blob;
2108 :
2109 73 : return 0;
2110 : }
2111 :
2112 64 : static krb5_error_code samba_kdc_create_device_info_blob(TALLOC_CTX *mem_ctx,
2113 : krb5_context context,
2114 : struct ldb_context *samdb,
2115 : const krb5_const_pac device_pac,
2116 : DATA_BLOB **device_info_blob)
2117 : {
2118 64 : TALLOC_CTX *frame = NULL;
2119 0 : krb5_data device_logon_info;
2120 64 : krb5_error_code code = EINVAL;
2121 0 : NTSTATUS nt_status;
2122 :
2123 0 : union PAC_INFO info;
2124 0 : enum ndr_err_code ndr_err;
2125 0 : DATA_BLOB device_logon_info_blob;
2126 :
2127 0 : union PAC_INFO logon_info;
2128 :
2129 64 : code = krb5_pac_get_buffer(context, device_pac,
2130 : PAC_TYPE_LOGON_INFO,
2131 : &device_logon_info);
2132 64 : if (code != 0) {
2133 0 : if (code == ENOENT) {
2134 0 : DBG_ERR("Device PAC is missing LOGON_INFO\n");
2135 : } else {
2136 0 : DBG_ERR("Error getting LOGON_INFO from device PAC\n");
2137 : }
2138 0 : return code;
2139 : }
2140 :
2141 64 : frame = talloc_stackframe();
2142 :
2143 64 : device_logon_info_blob = data_blob_const(device_logon_info.data,
2144 0 : device_logon_info.length);
2145 :
2146 64 : ndr_err = ndr_pull_union_blob(&device_logon_info_blob, frame, &logon_info,
2147 : PAC_TYPE_LOGON_INFO,
2148 : (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
2149 64 : smb_krb5_free_data_contents(context, &device_logon_info);
2150 64 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2151 0 : nt_status = ndr_map_error2ntstatus(ndr_err);
2152 0 : DBG_ERR("can't parse device PAC LOGON_INFO: %s\n",
2153 : nt_errstr(nt_status));
2154 0 : talloc_free(frame);
2155 0 : return map_errno_from_nt_status(nt_status);
2156 : }
2157 :
2158 : /*
2159 : * When creating the device info structure, existing resource groups are
2160 : * discarded.
2161 : */
2162 64 : code = samba_kdc_make_device_info(frame,
2163 64 : &logon_info.logon_info.info->info3,
2164 : NULL, /* resource_groups */
2165 : &info);
2166 64 : if (code != 0) {
2167 0 : talloc_free(frame);
2168 0 : return code;
2169 : }
2170 :
2171 64 : code = samba_kdc_update_device_info(frame,
2172 : samdb,
2173 : &logon_info,
2174 : info.device_info.info);
2175 64 : if (code != 0) {
2176 0 : talloc_free(frame);
2177 0 : return code;
2178 : }
2179 :
2180 64 : code = samba_kdc_get_device_info_pac_blob(mem_ctx,
2181 : &info,
2182 : device_info_blob);
2183 :
2184 64 : talloc_free(frame);
2185 64 : return code;
2186 : }
2187 :
2188 9 : static krb5_error_code samba_kdc_get_device_info_blob(TALLOC_CTX *mem_ctx,
2189 : krb5_context context,
2190 : struct ldb_context *samdb,
2191 : const struct samba_kdc_entry_pac device,
2192 : DATA_BLOB **device_info_blob)
2193 : {
2194 9 : TALLOC_CTX *frame = NULL;
2195 9 : krb5_error_code code = EINVAL;
2196 0 : NTSTATUS nt_status;
2197 :
2198 9 : const struct auth_user_info_dc *device_info = NULL;
2199 9 : struct netr_SamInfo3 *info3 = NULL;
2200 9 : struct PAC_DOMAIN_GROUP_MEMBERSHIP *resource_groups = NULL;
2201 :
2202 0 : union PAC_INFO info;
2203 :
2204 9 : frame = talloc_stackframe();
2205 :
2206 9 : code = samba_kdc_get_user_info_dc(frame,
2207 : context,
2208 : samdb,
2209 : device,
2210 : &device_info,
2211 : NULL /* resource_groups_out */);
2212 9 : if (code) {
2213 0 : const char *krb5_err = krb5_get_error_message(context, code);
2214 0 : DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
2215 : krb5_err != NULL ? krb5_err : "<unknown>");
2216 0 : krb5_free_error_message(context, krb5_err);
2217 :
2218 0 : talloc_free(frame);
2219 0 : return KRB5KDC_ERR_TGT_REVOKED;
2220 : }
2221 :
2222 9 : nt_status = auth_convert_user_info_dc_saminfo3(frame, device_info,
2223 : AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED,
2224 : &info3,
2225 : &resource_groups);
2226 9 : if (!NT_STATUS_IS_OK(nt_status)) {
2227 0 : DBG_WARNING("Getting Samba info failed: %s\n",
2228 : nt_errstr(nt_status));
2229 0 : talloc_free(frame);
2230 0 : return nt_status_to_krb5(nt_status);
2231 : }
2232 :
2233 9 : code = samba_kdc_make_device_info(frame,
2234 : info3,
2235 : resource_groups,
2236 : &info);
2237 9 : if (code != 0) {
2238 0 : talloc_free(frame);
2239 0 : return code;
2240 : }
2241 :
2242 9 : code = samba_kdc_get_device_info_pac_blob(mem_ctx,
2243 : &info,
2244 : device_info_blob);
2245 :
2246 9 : talloc_free(frame);
2247 9 : return code;
2248 : }
2249 :
2250 : /**
2251 : * @brief Verify a PAC
2252 : *
2253 : * @param mem_ctx A talloc memory context
2254 : *
2255 : * @param context A krb5 context
2256 : *
2257 : * @param samdb An open samdb connection.
2258 : *
2259 : * @param flags Bitwise OR'ed flags
2260 : *
2261 : * @param client The client samba kdc PAC entry.
2262 :
2263 : * @param krbtgt The krbtgt samba kdc entry.
2264 : *
2265 : * @return A Kerberos error code.
2266 : */
2267 50509 : krb5_error_code samba_kdc_verify_pac(TALLOC_CTX *mem_ctx,
2268 : krb5_context context,
2269 : struct ldb_context *samdb,
2270 : uint32_t flags,
2271 : const struct samba_kdc_entry_pac client,
2272 : const struct samba_kdc_entry *krbtgt)
2273 : {
2274 50509 : TALLOC_CTX *tmp_ctx = NULL;
2275 50509 : struct pac_blobs *pac_blobs = NULL;
2276 50509 : krb5_error_code code = EINVAL;
2277 :
2278 50509 : tmp_ctx = talloc_new(mem_ctx);
2279 50509 : if (tmp_ctx == NULL) {
2280 0 : code = ENOMEM;
2281 0 : goto done;
2282 : }
2283 :
2284 50509 : if (client.entry != NULL) {
2285 : /*
2286 : * Check the objectSID of the client and pac data are the same.
2287 : * Does a parse and SID check, but no crypto.
2288 : */
2289 50457 : code = samba_kdc_validate_pac_blob(context, client);
2290 50457 : if (code != 0) {
2291 38 : goto done;
2292 : }
2293 : }
2294 :
2295 50471 : if (!samba_krb5_pac_is_trusted(client)) {
2296 210 : const struct auth_user_info_dc *user_info_dc = NULL;
2297 0 : WERROR werr;
2298 :
2299 210 : struct dom_sid *object_sids = NULL;
2300 0 : uint32_t j;
2301 :
2302 210 : if (client.entry == NULL) {
2303 0 : code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2304 32 : goto done;
2305 : }
2306 :
2307 210 : code = samba_kdc_get_user_info_from_db(tmp_ctx,
2308 : samdb,
2309 210 : client.entry,
2310 210 : client.entry->msg,
2311 : &user_info_dc);
2312 210 : if (code) {
2313 0 : const char *krb5_err = krb5_get_error_message(context, code);
2314 0 : DBG_ERR("Getting user info for PAC failed: %s\n",
2315 : krb5_err != NULL ? krb5_err : "<unknown>");
2316 0 : krb5_free_error_message(context, krb5_err);
2317 :
2318 0 : code = KRB5KDC_ERR_TGT_REVOKED;
2319 0 : goto done;
2320 : }
2321 :
2322 : /*
2323 : * Check if the SID list in the user_info_dc intersects
2324 : * correctly with the RODC allow/deny lists.
2325 : */
2326 210 : object_sids = talloc_array(tmp_ctx, struct dom_sid, user_info_dc->num_sids);
2327 210 : if (object_sids == NULL) {
2328 0 : code = ENOMEM;
2329 0 : goto done;
2330 : }
2331 :
2332 930 : for (j = 0; j < user_info_dc->num_sids; ++j) {
2333 720 : object_sids[j] = user_info_dc->sids[j].sid;
2334 : }
2335 :
2336 210 : werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids,
2337 : object_sids,
2338 : krbtgt,
2339 210 : client.entry);
2340 210 : if (!W_ERROR_IS_OK(werr)) {
2341 30 : code = KRB5KDC_ERR_TGT_REVOKED;
2342 30 : if (W_ERROR_EQUAL(werr,
2343 : WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
2344 12 : code = KRB5KDC_ERR_POLICY;
2345 : }
2346 30 : goto done;
2347 : }
2348 :
2349 : /*
2350 : * The RODC PAC data isn't trusted for authorization as it may
2351 : * be stale. The only thing meaningful we can do with an RODC
2352 : * account on a full DC is exchange the RODC TGT for a 'real'
2353 : * TGT.
2354 : *
2355 : * So we match Windows (at least server 2022) and
2356 : * don't allow S4U2Self.
2357 : *
2358 : * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
2359 : */
2360 180 : if (flags & SAMBA_KDC_FLAG_PROTOCOL_TRANSITION) {
2361 2 : code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
2362 2 : goto done;
2363 : }
2364 : }
2365 :
2366 : /* Check the types of the given PAC */
2367 :
2368 52097 : code = pac_blobs_from_krb5_pac(tmp_ctx,
2369 : context,
2370 50439 : client.pac,
2371 : &pac_blobs);
2372 50439 : if (code != 0) {
2373 0 : goto done;
2374 : }
2375 :
2376 50439 : code = pac_blobs_ensure_exists(pac_blobs,
2377 : PAC_TYPE_LOGON_INFO);
2378 50439 : if (code != 0) {
2379 0 : goto done;
2380 : }
2381 :
2382 50439 : code = pac_blobs_ensure_exists(pac_blobs,
2383 : PAC_TYPE_LOGON_NAME);
2384 50439 : if (code != 0) {
2385 0 : goto done;
2386 : }
2387 :
2388 50439 : code = pac_blobs_ensure_exists(pac_blobs,
2389 : PAC_TYPE_SRV_CHECKSUM);
2390 50439 : if (code != 0) {
2391 0 : goto done;
2392 : }
2393 :
2394 50439 : code = pac_blobs_ensure_exists(pac_blobs,
2395 : PAC_TYPE_KDC_CHECKSUM);
2396 50439 : if (code != 0) {
2397 0 : goto done;
2398 : }
2399 :
2400 50439 : if (!(flags & SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION)) {
2401 50284 : code = pac_blobs_ensure_exists(pac_blobs,
2402 : PAC_TYPE_REQUESTER_SID);
2403 50284 : if (code != 0) {
2404 6 : code = KRB5KDC_ERR_TGT_REVOKED;
2405 6 : goto done;
2406 : }
2407 : }
2408 :
2409 48775 : code = 0;
2410 :
2411 50509 : done:
2412 50509 : talloc_free(tmp_ctx);
2413 :
2414 50509 : return code;
2415 : }
2416 :
2417 : /**
2418 : * @brief Update a PAC
2419 : *
2420 : * @param mem_ctx A talloc memory context
2421 : *
2422 : * @param context A krb5 context
2423 : *
2424 : * @param samdb An open samdb connection.
2425 : *
2426 : * @param lp_ctx A loadparm context.
2427 : *
2428 : * @param flags Bitwise OR'ed flags
2429 : *
2430 : * @param device_pac_is_trusted Whether the device's PAC was issued by a trusted server,
2431 : * as opposed to an RODC.
2432 : *
2433 : * @param client The client samba kdc PAC entry.
2434 : *
2435 : * @param server_principal The server principal
2436 : *
2437 : * @param server The server samba kdc entry.
2438 : *
2439 : * @param delegated_proxy_principal The delegated proxy principal used for
2440 : * updating the constrained delegation PAC
2441 : * buffer.
2442 : *
2443 : * @param delegated_proxy The delegated proxy kdc PAC entry.
2444 : *
2445 : * @param device The computer's samba kdc PAC entry; used for compound
2446 : * authentication.
2447 : *
2448 : * @param new_pac The new already allocated PAC
2449 : *
2450 : * @return A Kerberos error code. If no PAC should be returned, the code will be
2451 : * ENOATTR!
2452 : */
2453 48712 : krb5_error_code samba_kdc_update_pac(TALLOC_CTX *mem_ctx,
2454 : krb5_context context,
2455 : struct ldb_context *samdb,
2456 : struct loadparm_context *lp_ctx,
2457 : uint32_t flags,
2458 : const struct samba_kdc_entry_pac client,
2459 : const krb5_const_principal server_principal,
2460 : const struct samba_kdc_entry *server,
2461 : const krb5_const_principal delegated_proxy_principal,
2462 : const struct samba_kdc_entry_pac delegated_proxy,
2463 : const struct samba_kdc_entry_pac device,
2464 : krb5_pac new_pac,
2465 : struct authn_audit_info **server_audit_info_out,
2466 : NTSTATUS *status_out)
2467 : {
2468 48712 : TALLOC_CTX *tmp_ctx = NULL;
2469 48712 : krb5_error_code code = EINVAL;
2470 1658 : NTSTATUS nt_status;
2471 48712 : DATA_BLOB *pac_blob = NULL;
2472 48712 : DATA_BLOB *upn_blob = NULL;
2473 48712 : DATA_BLOB *deleg_blob = NULL;
2474 48712 : DATA_BLOB *requester_sid_blob = NULL;
2475 48712 : const DATA_BLOB *client_claims_blob = NULL;
2476 48712 : DATA_BLOB device_claims_blob = {};
2477 48712 : const DATA_BLOB *device_claims_blob_ptr = NULL;
2478 48712 : struct auth_claims auth_claims = {};
2479 48712 : DATA_BLOB *device_info_blob = NULL;
2480 48712 : bool is_tgs = false;
2481 48712 : bool server_restrictions_present = false;
2482 48712 : struct pac_blobs *pac_blobs = NULL;
2483 48712 : const struct auth_user_info_dc *user_info_dc_const = NULL;
2484 48712 : struct auth_user_info_dc *user_info_dc_shallow_copy = NULL;
2485 48712 : const struct PAC_DOMAIN_GROUP_MEMBERSHIP *_resource_groups = NULL;
2486 1658 : enum auth_group_inclusion group_inclusion;
2487 1658 : bool compounded_auth;
2488 48712 : size_t i = 0;
2489 :
2490 48712 : if (server_audit_info_out != NULL) {
2491 48712 : *server_audit_info_out = NULL;
2492 : }
2493 :
2494 48712 : if (status_out != NULL) {
2495 48712 : *status_out = NT_STATUS_OK;
2496 : }
2497 :
2498 48712 : tmp_ctx = talloc_new(mem_ctx);
2499 48712 : if (tmp_ctx == NULL) {
2500 0 : code = ENOMEM;
2501 0 : goto done;
2502 : }
2503 :
2504 : {
2505 48712 : int result = smb_krb5_principal_is_tgs(context, server_principal);
2506 48712 : if (result == -1) {
2507 0 : code = ENOMEM;
2508 0 : goto done;
2509 : }
2510 :
2511 48712 : is_tgs = result;
2512 : }
2513 :
2514 48712 : server_restrictions_present = !is_tgs && authn_policy_restrictions_present(server->server_policy);
2515 :
2516 : /* Only include resource groups in a service ticket. */
2517 48712 : if (is_tgs) {
2518 27034 : group_inclusion = AUTH_EXCLUDE_RESOURCE_GROUPS;
2519 20643 : } else if (server->supported_enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED) {
2520 21 : group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS;
2521 : } else {
2522 20622 : group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED;
2523 : }
2524 :
2525 281 : compounded_auth = device.entry != NULL && !is_tgs
2526 48993 : && server->supported_enctypes & KERB_ENCTYPE_COMPOUND_IDENTITY_SUPPORTED;
2527 :
2528 48712 : if (compounded_auth || (server_restrictions_present && device.entry != NULL)) {
2529 : /*
2530 : * [MS-KILE] 3.3.5.7.4 Compound Identity: the client claims from
2531 : * the device PAC become the device claims in the new PAC.
2532 : */
2533 211 : code = samba_kdc_get_claims_data(tmp_ctx,
2534 : context,
2535 : samdb,
2536 : device,
2537 : &auth_claims.device_claims);
2538 211 : if (code) {
2539 0 : goto done;
2540 : }
2541 :
2542 211 : if (compounded_auth) {
2543 73 : nt_status = claims_data_encoded_claims_set(tmp_ctx,
2544 : auth_claims.device_claims,
2545 : &device_claims_blob);
2546 73 : if (!NT_STATUS_IS_OK(nt_status)) {
2547 0 : DBG_ERR("claims_data_encoded_claims_set failed: %s\n",
2548 : nt_errstr(nt_status));
2549 0 : code = map_errno_from_nt_status(nt_status);
2550 0 : goto done;
2551 : }
2552 :
2553 73 : device_claims_blob_ptr = &device_claims_blob;
2554 :
2555 73 : if (samba_krb5_pac_is_trusted(device)) {
2556 64 : code = samba_kdc_create_device_info_blob(tmp_ctx,
2557 : context,
2558 : samdb,
2559 64 : device.pac,
2560 : &device_info_blob);
2561 64 : if (code != 0) {
2562 0 : goto done;
2563 : }
2564 : } else {
2565 : /* Don't trust an RODC‐issued PAC; regenerate the device info. */
2566 9 : code = samba_kdc_get_device_info_blob(tmp_ctx,
2567 : context,
2568 : samdb,
2569 : device,
2570 : &device_info_blob);
2571 9 : if (code != 0) {
2572 0 : goto done;
2573 : }
2574 : }
2575 : }
2576 : }
2577 :
2578 48712 : if (delegated_proxy_principal != NULL) {
2579 152 : deleg_blob = talloc_zero(tmp_ctx, DATA_BLOB);
2580 152 : if (deleg_blob == NULL) {
2581 0 : code = ENOMEM;
2582 0 : goto done;
2583 : }
2584 :
2585 152 : nt_status = samba_kdc_update_delegation_info_blob(
2586 : deleg_blob,
2587 : context,
2588 152 : client.pac,
2589 : server_principal,
2590 : delegated_proxy_principal,
2591 : deleg_blob);
2592 152 : if (!NT_STATUS_IS_OK(nt_status)) {
2593 0 : DBG_ERR("update delegation info blob failed: %s\n",
2594 : nt_errstr(nt_status));
2595 0 : code = map_errno_from_nt_status(nt_status);
2596 0 : goto done;
2597 : }
2598 : }
2599 :
2600 : /*
2601 : * If we are creating a TGT, resource groups from our domain are not to
2602 : * be put into the PAC. Instead, we take the resource groups directly
2603 : * from the original PAC and copy them unmodified into the new one.
2604 : */
2605 49335 : code = samba_kdc_get_user_info_dc(tmp_ctx,
2606 : context,
2607 : samdb,
2608 : client,
2609 : &user_info_dc_const,
2610 : is_tgs ? &_resource_groups : NULL);
2611 48712 : if (code != 0) {
2612 0 : const char *err_str = krb5_get_error_message(context, code);
2613 0 : DBG_ERR("samba_kdc_get_user_info_dc failed: %s\n",
2614 : err_str != NULL ? err_str : "<unknown>");
2615 0 : krb5_free_error_message(context, err_str);
2616 :
2617 0 : goto done;
2618 : }
2619 :
2620 : /*
2621 : * Enforce the AllowedToAuthenticateTo part of an authentication policy,
2622 : * if one is present.
2623 : */
2624 48712 : if (server_restrictions_present) {
2625 0 : struct samba_kdc_entry_pac auth_entry;
2626 161 : const struct auth_user_info_dc *auth_user_info_dc = NULL;
2627 161 : const struct auth_user_info_dc *device_info = NULL;
2628 :
2629 161 : if (delegated_proxy.entry != NULL) {
2630 34 : auth_entry = delegated_proxy;
2631 :
2632 34 : code = samba_kdc_get_user_info_dc(tmp_ctx,
2633 : context,
2634 : samdb,
2635 : delegated_proxy,
2636 : &auth_user_info_dc,
2637 : NULL /* resource_groups_out */);
2638 34 : if (code) {
2639 63 : goto done;
2640 : }
2641 : } else {
2642 127 : auth_entry = client;
2643 127 : auth_user_info_dc = user_info_dc_const;
2644 : }
2645 :
2646 : /* Fetch the user’s claims. */
2647 161 : code = samba_kdc_get_claims_data(tmp_ctx,
2648 : context,
2649 : samdb,
2650 : auth_entry,
2651 : &auth_claims.user_claims);
2652 161 : if (code) {
2653 0 : goto done;
2654 : }
2655 :
2656 161 : if (device.entry != NULL) {
2657 146 : code = samba_kdc_get_user_info_dc(tmp_ctx,
2658 : context,
2659 : samdb,
2660 : device,
2661 : &device_info,
2662 : NULL /* resource_groups_out */);
2663 146 : if (code) {
2664 0 : goto done;
2665 : }
2666 : }
2667 :
2668 : /*
2669 : * Allocate the audit info and output status on to the parent
2670 : * mem_ctx, not the temporary context.
2671 : */
2672 161 : code = samba_kdc_allowed_to_authenticate_to(mem_ctx,
2673 : samdb,
2674 : lp_ctx,
2675 161 : auth_entry.entry,
2676 : auth_user_info_dc,
2677 : device_info,
2678 : auth_claims,
2679 : server,
2680 : server_audit_info_out,
2681 : status_out);
2682 161 : if (code) {
2683 63 : goto done;
2684 : }
2685 : }
2686 :
2687 48649 : if (compounded_auth) {
2688 : /* Make a shallow copy of the user_info_dc structure. */
2689 73 : nt_status = authsam_shallow_copy_user_info_dc(tmp_ctx,
2690 : user_info_dc_const,
2691 : &user_info_dc_shallow_copy);
2692 73 : user_info_dc_const = NULL;
2693 :
2694 73 : if (!NT_STATUS_IS_OK(nt_status)) {
2695 0 : DBG_ERR("Failed to copy user_info_dc: %s\n",
2696 : nt_errstr(nt_status));
2697 :
2698 0 : code = KRB5KDC_ERR_TGT_REVOKED;
2699 0 : goto done;
2700 : }
2701 :
2702 73 : nt_status = samba_kdc_add_compounded_auth(user_info_dc_shallow_copy);
2703 73 : if (!NT_STATUS_IS_OK(nt_status)) {
2704 0 : DBG_ERR("Failed to add Compounded Authentication: %s\n",
2705 : nt_errstr(nt_status));
2706 :
2707 0 : code = KRB5KDC_ERR_TGT_REVOKED;
2708 0 : goto done;
2709 : }
2710 :
2711 : /* We can now set back to the const, it will not be modified */
2712 73 : user_info_dc_const = user_info_dc_shallow_copy;
2713 : }
2714 :
2715 48649 : if (samba_krb5_pac_is_trusted(client)) {
2716 48534 : pac_blob = talloc_zero(tmp_ctx, DATA_BLOB);
2717 48534 : if (pac_blob == NULL) {
2718 0 : code = ENOMEM;
2719 0 : goto done;
2720 : }
2721 :
2722 48534 : nt_status = samba_get_logon_info_pac_blob(tmp_ctx,
2723 : user_info_dc_const,
2724 : _resource_groups,
2725 : group_inclusion,
2726 : pac_blob);
2727 48534 : if (!NT_STATUS_IS_OK(nt_status)) {
2728 0 : DBG_ERR("samba_get_logon_info_pac_blob failed: %s\n",
2729 : nt_errstr(nt_status));
2730 :
2731 0 : code = map_errno_from_nt_status(nt_status);
2732 0 : goto done;
2733 : }
2734 :
2735 : /*
2736 : * TODO: we need claim translation over trusts,
2737 : * for now we just clear them...
2738 : */
2739 50192 : if (samba_kdc_entry_pac_issued_by_trust(client)) {
2740 51 : client_claims_blob = &data_blob_null;
2741 : }
2742 : } else {
2743 115 : nt_status = samba_kdc_get_logon_info_blob(tmp_ctx,
2744 : user_info_dc_const,
2745 : group_inclusion,
2746 : &pac_blob);
2747 115 : if (!NT_STATUS_IS_OK(nt_status)) {
2748 0 : DBG_ERR("samba_kdc_get_logon_info_blob failed: %s\n",
2749 : nt_errstr(nt_status));
2750 0 : code = KRB5KDC_ERR_TGT_REVOKED;
2751 0 : goto done;
2752 : }
2753 :
2754 115 : nt_status = samba_kdc_get_upn_info_blob(tmp_ctx,
2755 : user_info_dc_const,
2756 : &upn_blob);
2757 115 : if (!NT_STATUS_IS_OK(nt_status)) {
2758 0 : DBG_ERR("samba_kdc_get_upn_info_blob failed: %s\n",
2759 : nt_errstr(nt_status));
2760 0 : code = KRB5KDC_ERR_TGT_REVOKED;
2761 0 : goto done;
2762 : }
2763 :
2764 115 : if (is_tgs) {
2765 18 : nt_status = samba_kdc_get_requester_sid_blob(tmp_ctx,
2766 : user_info_dc_const,
2767 : &requester_sid_blob);
2768 18 : if (!NT_STATUS_IS_OK(nt_status)) {
2769 0 : DBG_ERR("samba_kdc_get_requester_sid_blob failed: %s\n",
2770 : nt_errstr(nt_status));
2771 0 : code = KRB5KDC_ERR_TGT_REVOKED;
2772 0 : goto done;
2773 : }
2774 : }
2775 :
2776 : /* Don't trust RODC-issued claims. Regenerate them. */
2777 115 : nt_status = samba_kdc_get_claims_blob(tmp_ctx,
2778 115 : client.entry,
2779 : &client_claims_blob);
2780 115 : if (!NT_STATUS_IS_OK(nt_status)) {
2781 0 : DBG_ERR("samba_kdc_get_claims_blob failed: %s\n",
2782 : nt_errstr(nt_status));
2783 0 : code = map_errno_from_nt_status(nt_status);
2784 0 : goto done;
2785 : }
2786 : }
2787 :
2788 : /* Check the types of the given PAC */
2789 48649 : code = pac_blobs_from_krb5_pac(tmp_ctx,
2790 : context,
2791 46991 : client.pac,
2792 : &pac_blobs);
2793 48649 : if (code != 0) {
2794 0 : goto done;
2795 : }
2796 :
2797 48649 : code = pac_blobs_replace_existing(pac_blobs,
2798 : PAC_TYPE_LOGON_INFO,
2799 : pac_blob);
2800 48649 : if (code != 0) {
2801 0 : goto done;
2802 : }
2803 :
2804 : #ifdef SAMBA4_USES_HEIMDAL
2805 : /* Not needed with MIT Kerberos */
2806 48649 : code = pac_blobs_replace_existing(pac_blobs,
2807 : PAC_TYPE_LOGON_NAME,
2808 : &data_blob_null);
2809 48649 : if (code != 0) {
2810 0 : goto done;
2811 : }
2812 :
2813 48649 : code = pac_blobs_replace_existing(pac_blobs,
2814 : PAC_TYPE_SRV_CHECKSUM,
2815 : &data_blob_null);
2816 48649 : if (code != 0) {
2817 0 : goto done;
2818 : }
2819 :
2820 48649 : code = pac_blobs_replace_existing(pac_blobs,
2821 : PAC_TYPE_KDC_CHECKSUM,
2822 : &data_blob_null);
2823 48649 : if (code != 0) {
2824 0 : goto done;
2825 : }
2826 : #endif
2827 :
2828 48649 : code = pac_blobs_add_blob(pac_blobs,
2829 : PAC_TYPE_CONSTRAINED_DELEGATION,
2830 : deleg_blob);
2831 48649 : if (code != 0) {
2832 0 : goto done;
2833 : }
2834 :
2835 48649 : code = pac_blobs_add_blob(pac_blobs,
2836 : PAC_TYPE_UPN_DNS_INFO,
2837 : upn_blob);
2838 48649 : if (code != 0) {
2839 0 : goto done;
2840 : }
2841 :
2842 48649 : code = pac_blobs_add_blob(pac_blobs,
2843 : PAC_TYPE_CLIENT_CLAIMS_INFO,
2844 : client_claims_blob);
2845 48649 : if (code != 0) {
2846 0 : goto done;
2847 : }
2848 :
2849 48649 : code = pac_blobs_add_blob(pac_blobs,
2850 : PAC_TYPE_DEVICE_INFO,
2851 : device_info_blob);
2852 48649 : if (code != 0) {
2853 0 : goto done;
2854 : }
2855 :
2856 48649 : code = pac_blobs_add_blob(pac_blobs,
2857 : PAC_TYPE_DEVICE_CLAIMS_INFO,
2858 : device_claims_blob_ptr);
2859 48649 : if (code != 0) {
2860 0 : goto done;
2861 : }
2862 :
2863 48649 : if (!samba_krb5_pac_is_trusted(client) || !is_tgs) {
2864 20598 : pac_blobs_remove_blob(pac_blobs,
2865 : PAC_TYPE_ATTRIBUTES_INFO);
2866 : }
2867 :
2868 48649 : if (!is_tgs) {
2869 20580 : pac_blobs_remove_blob(pac_blobs,
2870 : PAC_TYPE_REQUESTER_SID);
2871 : }
2872 :
2873 48649 : code = pac_blobs_add_blob(pac_blobs,
2874 : PAC_TYPE_REQUESTER_SID,
2875 : requester_sid_blob);
2876 48649 : if (code != 0) {
2877 0 : goto done;
2878 : }
2879 :
2880 : /*
2881 : * The server account may be set not to want the PAC.
2882 : *
2883 : * While this is wasteful if the above calculations were done
2884 : * and now thrown away, this is cleaner as we do any ticket
2885 : * signature checking etc always.
2886 : *
2887 : * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
2888 : * time (eg not accepting a ticket from the RODC) we do not
2889 : * need to re-generate anything anyway.
2890 : */
2891 48649 : if (!samba_princ_needs_pac(server)) {
2892 5 : code = ENOATTR;
2893 5 : goto done;
2894 : }
2895 :
2896 48644 : if (samba_krb5_pac_is_trusted(client) && !is_tgs) {
2897 : /*
2898 : * The client may have requested no PAC when obtaining the
2899 : * TGT.
2900 : */
2901 20478 : bool requested_pac = false;
2902 :
2903 20478 : code = samba_client_requested_pac(context,
2904 19855 : client.pac,
2905 : tmp_ctx,
2906 : &requested_pac);
2907 20478 : if (code != 0 || !requested_pac) {
2908 6 : if (!requested_pac) {
2909 6 : code = ENOATTR;
2910 : }
2911 6 : goto done;
2912 : }
2913 : }
2914 :
2915 397207 : for (i = 0; i < pac_blobs->num_types; ++i) {
2916 12018 : krb5_data type_data;
2917 348569 : const DATA_BLOB *type_blob = pac_blobs->type_blobs[i].data;
2918 348569 : uint32_t type = pac_blobs->type_blobs[i].type;
2919 :
2920 12018 : static char null_byte = '\0';
2921 348569 : const krb5_data null_data = smb_krb5_make_data(&null_byte, 0);
2922 :
2923 : #ifndef SAMBA4_USES_HEIMDAL
2924 : /* Not needed with MIT Kerberos */
2925 0 : switch(type) {
2926 0 : case PAC_TYPE_LOGON_NAME:
2927 : case PAC_TYPE_SRV_CHECKSUM:
2928 : case PAC_TYPE_KDC_CHECKSUM:
2929 : case PAC_TYPE_FULL_CHECKSUM:
2930 0 : continue;
2931 0 : default:
2932 0 : break;
2933 : }
2934 : #endif
2935 :
2936 348569 : if (type_blob != NULL) {
2937 195134 : type_data = smb_krb5_data_from_blob(*type_blob);
2938 : /*
2939 : * Passing a NULL pointer into krb5_pac_add_buffer() is
2940 : * not allowed, so pass null_data instead if needed.
2941 : */
2942 195134 : code = krb5_pac_add_buffer(context,
2943 : new_pac,
2944 : type,
2945 195134 : (type_data.data != NULL) ? &type_data : &null_data);
2946 195134 : if (code != 0) {
2947 0 : goto done;
2948 : }
2949 153435 : } else if (samba_krb5_pac_is_trusted(client)) {
2950 : /*
2951 : * Convey the buffer from the original PAC if we can
2952 : * trust it.
2953 : */
2954 :
2955 153410 : code = krb5_pac_get_buffer(context,
2956 148024 : client.pac,
2957 : type,
2958 : &type_data);
2959 153410 : if (code != 0) {
2960 0 : goto done;
2961 : }
2962 : /*
2963 : * Passing a NULL pointer into krb5_pac_add_buffer() is
2964 : * not allowed, so pass null_data instead if needed.
2965 : */
2966 153410 : code = krb5_pac_add_buffer(context,
2967 : new_pac,
2968 : type,
2969 153410 : (type_data.data != NULL) ? &type_data : &null_data);
2970 153410 : smb_krb5_free_data_contents(context, &type_data);
2971 153410 : if (code != 0) {
2972 0 : goto done;
2973 : }
2974 : }
2975 : }
2976 :
2977 46980 : code = 0;
2978 48712 : done:
2979 48712 : TALLOC_FREE(tmp_ctx);
2980 48712 : return code;
2981 : }
2982 :
2983 999 : krb5_error_code samba_kdc_get_claims_data(TALLOC_CTX *mem_ctx,
2984 : krb5_context context,
2985 : struct ldb_context *samdb,
2986 : struct samba_kdc_entry_pac entry,
2987 : struct claims_data **claims_data_out)
2988 : {
2989 999 : if (samba_kdc_entry_pac_issued_by_trust(entry)) {
2990 0 : NTSTATUS status;
2991 :
2992 : /*
2993 : * TODO: we need claim translation over trusts; for now we just
2994 : * clear them…
2995 : */
2996 0 : status = claims_data_from_encoded_claims_set(mem_ctx,
2997 : NULL,
2998 : claims_data_out);
2999 0 : if (!NT_STATUS_IS_OK(status)) {
3000 0 : return map_errno_from_nt_status(status);
3001 : }
3002 :
3003 0 : return 0;
3004 : }
3005 :
3006 999 : if (samba_krb5_pac_is_trusted(entry)) {
3007 931 : return samba_kdc_get_claims_data_from_pac(mem_ctx,
3008 : context,
3009 : entry,
3010 : claims_data_out);
3011 : }
3012 :
3013 68 : return samba_kdc_get_claims_data_from_db(samdb,
3014 : entry.entry,
3015 : claims_data_out);
3016 : }
3017 :
3018 931 : krb5_error_code samba_kdc_get_claims_data_from_pac(TALLOC_CTX *mem_ctx,
3019 : krb5_context context,
3020 : struct samba_kdc_entry_pac entry,
3021 : struct claims_data **claims_data_out)
3022 : {
3023 931 : TALLOC_CTX *frame = NULL;
3024 931 : krb5_data claims_info = {};
3025 931 : struct claims_data *claims_data = NULL;
3026 931 : NTSTATUS status = NT_STATUS_OK;
3027 0 : krb5_error_code code;
3028 :
3029 931 : if (!samba_krb5_pac_is_trusted(entry)) {
3030 0 : code = EINVAL;
3031 0 : goto out;
3032 : }
3033 :
3034 931 : if (samba_kdc_entry_pac_issued_by_trust(entry)) {
3035 0 : code = EINVAL;
3036 0 : goto out;
3037 : }
3038 :
3039 931 : if (claims_data_out == NULL) {
3040 0 : code = EINVAL;
3041 0 : goto out;
3042 : }
3043 :
3044 931 : *claims_data_out = NULL;
3045 :
3046 931 : if (entry.entry != NULL && entry.entry->claims_from_pac_are_initialized) {
3047 : /* Note: the caller does not own this! */
3048 30 : *claims_data_out = entry.entry->claims_from_pac;
3049 30 : return 0;
3050 : }
3051 :
3052 901 : frame = talloc_stackframe();
3053 :
3054 : /* Fetch the claims from the PAC. */
3055 901 : code = krb5_pac_get_buffer(context, entry.pac,
3056 : PAC_TYPE_CLIENT_CLAIMS_INFO,
3057 : &claims_info);
3058 901 : if (code == ENOENT) {
3059 : /* OK. */
3060 901 : } else if (code != 0) {
3061 0 : DBG_ERR("Error getting CLIENT_CLAIMS_INFO from PAC\n");
3062 0 : goto out;
3063 901 : } else if (claims_info.length) {
3064 341 : DATA_BLOB claims_blob = data_blob_const(claims_info.data,
3065 0 : claims_info.length);
3066 :
3067 341 : status = claims_data_from_encoded_claims_set(frame,
3068 : &claims_blob,
3069 : &claims_data);
3070 341 : if (!NT_STATUS_IS_OK(status)) {
3071 0 : code = map_errno_from_nt_status(status);
3072 0 : goto out;
3073 : }
3074 : }
3075 :
3076 901 : if (entry.entry != NULL) {
3077 : /* Note: the caller does not own this! */
3078 901 : entry.entry->claims_from_pac = talloc_steal(entry.entry,
3079 : claims_data);
3080 901 : entry.entry->claims_from_pac_are_initialized = true;
3081 : } else {
3082 0 : talloc_steal(mem_ctx, claims_data);
3083 : }
3084 :
3085 901 : *claims_data_out = claims_data;
3086 :
3087 901 : out:
3088 901 : smb_krb5_free_data_contents(context, &claims_info);
3089 901 : talloc_free(frame);
3090 901 : return code;
3091 : }
3092 :
3093 31139 : krb5_error_code samba_kdc_get_claims_data_from_db(struct ldb_context *samdb,
3094 : struct samba_kdc_entry *entry,
3095 : struct claims_data **claims_data_out)
3096 : {
3097 31139 : TALLOC_CTX *frame = NULL;
3098 :
3099 31139 : struct claims_data *claims_data = NULL;
3100 31139 : struct CLAIMS_SET *claims_set = NULL;
3101 31139 : NTSTATUS status = NT_STATUS_OK;
3102 1170 : krb5_error_code code;
3103 :
3104 31139 : if (samdb == NULL) {
3105 0 : code = EINVAL;
3106 0 : goto out;
3107 : }
3108 :
3109 31139 : if (claims_data_out == NULL) {
3110 0 : code = EINVAL;
3111 0 : goto out;
3112 : }
3113 :
3114 31139 : if (entry == NULL) {
3115 0 : code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
3116 0 : goto out;
3117 : }
3118 :
3119 31139 : *claims_data_out = NULL;
3120 :
3121 31139 : if (entry->claims_from_db_are_initialized) {
3122 : /* Note: the caller does not own this! */
3123 14 : *claims_data_out = entry->claims_from_db;
3124 14 : return 0;
3125 : }
3126 :
3127 31125 : frame = talloc_stackframe();
3128 :
3129 32295 : code = get_claims_set_for_principal(samdb,
3130 : frame,
3131 31125 : entry->msg,
3132 : &claims_set);
3133 31125 : if (code) {
3134 0 : DBG_ERR("Failed to fetch claims\n");
3135 0 : goto out;
3136 : }
3137 :
3138 31125 : if (claims_set != NULL) {
3139 324 : status = claims_data_from_claims_set(claims_data,
3140 : claims_set,
3141 : &claims_data);
3142 324 : if (!NT_STATUS_IS_OK(status)) {
3143 0 : code = map_errno_from_nt_status(status);
3144 0 : goto out;
3145 : }
3146 : }
3147 :
3148 31125 : entry->claims_from_db = talloc_steal(entry,
3149 : claims_data);
3150 31125 : entry->claims_from_db_are_initialized = true;
3151 :
3152 : /* Note: the caller does not own this! */
3153 31125 : *claims_data_out = entry->claims_from_db;
3154 :
3155 31125 : out:
3156 31125 : talloc_free(frame);
3157 31125 : return code;
3158 : }
3159 :
3160 49529 : krb5_error_code samba_kdc_check_device(TALLOC_CTX *mem_ctx,
3161 : krb5_context context,
3162 : struct ldb_context *samdb,
3163 : struct loadparm_context *lp_ctx,
3164 : const struct samba_kdc_entry_pac device,
3165 : const struct authn_kerberos_client_policy *client_policy,
3166 : struct authn_audit_info **client_audit_info_out,
3167 : NTSTATUS *status_out)
3168 : {
3169 49529 : TALLOC_CTX *frame = NULL;
3170 49529 : krb5_error_code code = 0;
3171 1755 : NTSTATUS nt_status;
3172 49529 : const struct auth_user_info_dc *device_info = NULL;
3173 49529 : struct authn_audit_info *client_audit_info = NULL;
3174 49529 : struct auth_claims auth_claims = {};
3175 :
3176 49529 : if (status_out != NULL) {
3177 49529 : *status_out = NT_STATUS_OK;
3178 : }
3179 :
3180 49529 : if (!authn_policy_device_restrictions_present(client_policy)) {
3181 47377 : return 0;
3182 : }
3183 :
3184 397 : if (device.entry == NULL || device.pac == NULL) {
3185 3 : NTSTATUS out_status = NT_STATUS_INVALID_WORKSTATION;
3186 :
3187 3 : nt_status = authn_kerberos_client_policy_audit_info(mem_ctx,
3188 : client_policy,
3189 : NULL /* client_info */,
3190 : AUTHN_AUDIT_EVENT_KERBEROS_DEVICE_RESTRICTION,
3191 : AUTHN_AUDIT_REASON_FAST_REQUIRED,
3192 : out_status,
3193 : client_audit_info_out);
3194 3 : if (!NT_STATUS_IS_OK(nt_status)) {
3195 0 : code = KRB5KRB_ERR_GENERIC;
3196 3 : } else if (authn_kerberos_client_policy_is_enforced(client_policy)) {
3197 2 : code = KRB5KDC_ERR_POLICY;
3198 :
3199 2 : if (status_out != NULL) {
3200 2 : *status_out = out_status;
3201 : }
3202 : } else {
3203 : /* OK. */
3204 1 : code = 0;
3205 : }
3206 :
3207 3 : goto out;
3208 : }
3209 :
3210 394 : frame = talloc_stackframe();
3211 :
3212 394 : code = samba_kdc_get_user_info_dc(frame,
3213 : context,
3214 : samdb,
3215 : device,
3216 : &device_info,
3217 : NULL);
3218 394 : if (code) {
3219 0 : goto out;
3220 : }
3221 :
3222 : /*
3223 : * The device claims become the *user* claims for the purpose of
3224 : * evaluating a conditional ACE expression.
3225 : */
3226 394 : code = samba_kdc_get_claims_data(frame,
3227 : context,
3228 : samdb,
3229 : device,
3230 : &auth_claims.user_claims);
3231 394 : if (code) {
3232 0 : goto out;
3233 : }
3234 :
3235 394 : nt_status = authn_policy_authenticate_from_device(frame,
3236 : samdb,
3237 : lp_ctx,
3238 : device_info,
3239 : auth_claims,
3240 : client_policy,
3241 : &client_audit_info);
3242 394 : if (client_audit_info != NULL) {
3243 394 : *client_audit_info_out = talloc_move(mem_ctx, &client_audit_info);
3244 : }
3245 394 : if (!NT_STATUS_IS_OK(nt_status)) {
3246 260 : if (NT_STATUS_EQUAL(nt_status, NT_STATUS_AUTHENTICATION_FIREWALL_FAILED)) {
3247 242 : code = KRB5KDC_ERR_POLICY;
3248 : } else {
3249 18 : code = KRB5KRB_ERR_GENERIC;
3250 : }
3251 :
3252 260 : goto out;
3253 : }
3254 :
3255 134 : out:
3256 397 : talloc_free(frame);
3257 397 : return code;
3258 : }
|