s4:kdc: Add asserted identity SID to identify whether S4U2Self has occurred
[Samba.git] / source4 / kdc / pac-glue.c
blobff364511f2a4ce90518483012bcfb381eb7847a5
1 /*
2 Unix SMB/CIFS implementation.
4 PAC Glue between Samba and the KDC
6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2009
7 Copyright (C) Simo Sorce <idra@samba.org> 2010
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.
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.
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/>.
24 #include "lib/replace/replace.h"
25 #include "lib/replace/system/kerberos.h"
26 #include "lib/util/debug.h"
27 #include "lib/util/samba_util.h"
28 #include "lib/util/talloc_stack.h"
30 #include "auth/auth_sam_reply.h"
31 #include "auth/kerberos/kerberos.h"
32 #include "auth/kerberos/pac_utils.h"
33 #include "libcli/security/security.h"
34 #include "libds/common/flags.h"
35 #include "librpc/gen_ndr/ndr_krb5pac.h"
36 #include "param/param.h"
37 #include "source4/auth/auth.h"
38 #include "source4/dsdb/common/util.h"
39 #include "source4/dsdb/samdb/samdb.h"
40 #include "source4/kdc/samba_kdc.h"
41 #include "source4/kdc/pac-glue.h"
43 #include <ldb.h>
45 #undef DBGC_CLASS
46 #define DBGC_CLASS DBGC_KERBEROS
48 static
49 NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
50 const struct auth_user_info_dc *info,
51 DATA_BLOB *pac_data,
52 DATA_BLOB *requester_sid_blob)
54 struct netr_SamInfo3 *info3;
55 union PAC_INFO pac_info;
56 enum ndr_err_code ndr_err;
57 NTSTATUS nt_status;
59 ZERO_STRUCT(pac_info);
61 *pac_data = data_blob_null;
62 if (requester_sid_blob != NULL) {
63 *requester_sid_blob = data_blob_null;
66 nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, info, &info3);
67 if (!NT_STATUS_IS_OK(nt_status)) {
68 DEBUG(1, ("Getting Samba info failed: %s\n",
69 nt_errstr(nt_status)));
70 return nt_status;
73 pac_info.logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO);
74 if (!pac_info.logon_info.info) {
75 return NT_STATUS_NO_MEMORY;
78 pac_info.logon_info.info->info3 = *info3;
80 ndr_err = ndr_push_union_blob(pac_data, mem_ctx, &pac_info,
81 PAC_TYPE_LOGON_INFO,
82 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
83 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
84 nt_status = ndr_map_error2ntstatus(ndr_err);
85 DEBUG(1, ("PAC_LOGON_INFO (presig) push failed: %s\n",
86 nt_errstr(nt_status)));
87 return nt_status;
90 if (requester_sid_blob != NULL && info->num_sids > 0) {
91 union PAC_INFO pac_requester_sid;
93 ZERO_STRUCT(pac_requester_sid);
95 pac_requester_sid.requester_sid.sid = info->sids[0];
97 ndr_err = ndr_push_union_blob(requester_sid_blob, mem_ctx,
98 &pac_requester_sid,
99 PAC_TYPE_REQUESTER_SID,
100 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
101 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
102 nt_status = ndr_map_error2ntstatus(ndr_err);
103 DEBUG(1, ("PAC_REQUESTER_SID (presig) push failed: %s\n",
104 nt_errstr(nt_status)));
105 return nt_status;
109 return NT_STATUS_OK;
112 static
113 NTSTATUS samba_get_upn_info_pac_blob(TALLOC_CTX *mem_ctx,
114 const struct auth_user_info_dc *info,
115 DATA_BLOB *upn_data)
117 union PAC_INFO pac_upn;
118 enum ndr_err_code ndr_err;
119 NTSTATUS nt_status;
120 bool ok;
122 ZERO_STRUCT(pac_upn);
124 *upn_data = data_blob_null;
126 pac_upn.upn_dns_info.upn_name = info->info->user_principal_name;
127 pac_upn.upn_dns_info.dns_domain_name = strupper_talloc(mem_ctx,
128 info->info->dns_domain_name);
129 if (pac_upn.upn_dns_info.dns_domain_name == NULL) {
130 return NT_STATUS_NO_MEMORY;
132 if (info->info->user_principal_constructed) {
133 pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED;
136 pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID;
138 pac_upn.upn_dns_info.ex.sam_name_and_sid.samaccountname
139 = info->info->account_name;
141 pac_upn.upn_dns_info.ex.sam_name_and_sid.objectsid
142 = &info->sids[0];
144 ndr_err = ndr_push_union_blob(upn_data, mem_ctx, &pac_upn,
145 PAC_TYPE_UPN_DNS_INFO,
146 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
147 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
148 nt_status = ndr_map_error2ntstatus(ndr_err);
149 DEBUG(1, ("PAC UPN_DNS_INFO (presig) push failed: %s\n",
150 nt_errstr(nt_status)));
151 return nt_status;
154 ok = data_blob_pad(mem_ctx, upn_data, 8);
155 if (!ok) {
156 return NT_STATUS_NO_MEMORY;
159 return NT_STATUS_OK;
162 static
163 NTSTATUS samba_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
164 uint64_t pac_attributes,
165 DATA_BLOB *pac_attrs_data)
167 union PAC_INFO pac_attrs;
168 enum ndr_err_code ndr_err;
169 NTSTATUS nt_status;
171 ZERO_STRUCT(pac_attrs);
173 *pac_attrs_data = data_blob_null;
175 /* Set the length of the flags in bits. */
176 pac_attrs.attributes_info.flags_length = 2;
177 pac_attrs.attributes_info.flags = pac_attributes;
179 ndr_err = ndr_push_union_blob(pac_attrs_data, mem_ctx, &pac_attrs,
180 PAC_TYPE_ATTRIBUTES_INFO,
181 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
182 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
183 nt_status = ndr_map_error2ntstatus(ndr_err);
184 DEBUG(1, ("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
185 nt_errstr(nt_status)));
186 return nt_status;
189 return NT_STATUS_OK;
192 static
193 NTSTATUS samba_get_cred_info_ndr_blob(TALLOC_CTX *mem_ctx,
194 const struct ldb_message *msg,
195 DATA_BLOB *cred_blob)
197 enum ndr_err_code ndr_err;
198 NTSTATUS nt_status;
199 struct samr_Password *lm_hash = NULL;
200 struct samr_Password *nt_hash = NULL;
201 struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg = {
202 .version = 0,
204 DATA_BLOB ntlm_blob = data_blob_null;
205 struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs[1] = {{
206 .credential_size = 0,
208 struct PAC_CREDENTIAL_DATA cred_data = {
209 .credential_count = 0,
211 struct PAC_CREDENTIAL_DATA_NDR cred_ndr;
213 ZERO_STRUCT(cred_ndr);
215 *cred_blob = data_blob_null;
217 lm_hash = samdb_result_hash(mem_ctx, msg, "dBCSPwd");
218 if (lm_hash != NULL) {
219 bool zero = all_zero(lm_hash->hash, 16);
220 if (zero) {
221 lm_hash = NULL;
224 if (lm_hash != NULL) {
225 DEBUG(5, ("Passing LM password hash through credentials set\n"));
226 ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_LM_HASH;
227 ntlm_secpkg.lm_password = *lm_hash;
228 ZERO_STRUCTP(lm_hash);
229 TALLOC_FREE(lm_hash);
232 nt_hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
233 if (nt_hash != NULL) {
234 bool zero = all_zero(nt_hash->hash, 16);
235 if (zero) {
236 nt_hash = NULL;
239 if (nt_hash != NULL) {
240 DEBUG(5, ("Passing LM password hash through credentials set\n"));
241 ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_NT_HASH;
242 ntlm_secpkg.nt_password = *nt_hash;
243 ZERO_STRUCTP(nt_hash);
244 TALLOC_FREE(nt_hash);
247 if (ntlm_secpkg.flags == 0) {
248 return NT_STATUS_OK;
251 #ifdef DEBUG_PASSWORD
252 if (DEBUGLVL(11)) {
253 NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG, &ntlm_secpkg);
255 #endif
257 ndr_err = ndr_push_struct_blob(&ntlm_blob, mem_ctx, &ntlm_secpkg,
258 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG);
259 ZERO_STRUCT(ntlm_secpkg);
260 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
261 nt_status = ndr_map_error2ntstatus(ndr_err);
262 DEBUG(1, ("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
263 nt_errstr(nt_status)));
264 return nt_status;
267 DEBUG(10, ("NTLM credential BLOB (len %zu) for user\n",
268 ntlm_blob.length));
269 dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
270 ntlm_blob.data, ntlm_blob.length);
272 secpkgs[0].package_name.string = discard_const_p(char, "NTLM");
273 secpkgs[0].credential_size = ntlm_blob.length;
274 secpkgs[0].credential = ntlm_blob.data;
276 cred_data.credential_count = ARRAY_SIZE(secpkgs);
277 cred_data.credentials = secpkgs;
279 #ifdef DEBUG_PASSWORD
280 if (DEBUGLVL(11)) {
281 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA, &cred_data);
283 #endif
285 cred_ndr.ctr.data = &cred_data;
287 #ifdef DEBUG_PASSWORD
288 if (DEBUGLVL(11)) {
289 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR, &cred_ndr);
291 #endif
293 ndr_err = ndr_push_struct_blob(cred_blob, mem_ctx, &cred_ndr,
294 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_DATA_NDR);
295 data_blob_clear(&ntlm_blob);
296 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
297 nt_status = ndr_map_error2ntstatus(ndr_err);
298 DEBUG(1, ("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
299 nt_errstr(nt_status)));
300 return nt_status;
303 DEBUG(10, ("Created credential BLOB (len %zu) for user\n",
304 cred_blob->length));
305 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
306 cred_blob->data, cred_blob->length);
308 return NT_STATUS_OK;
311 #ifdef SAMBA4_USES_HEIMDAL
312 krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
313 const krb5_keyblock *pkreplykey,
314 const DATA_BLOB *cred_ndr_blob,
315 TALLOC_CTX *mem_ctx,
316 DATA_BLOB *cred_info_blob)
318 krb5_crypto cred_crypto;
319 krb5_enctype cred_enctype;
320 krb5_data cred_ndr_crypt;
321 struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
322 krb5_error_code ret;
323 const char *krb5err;
324 enum ndr_err_code ndr_err;
325 NTSTATUS nt_status;
327 *cred_info_blob = data_blob_null;
329 ret = krb5_crypto_init(context, pkreplykey, ETYPE_NULL,
330 &cred_crypto);
331 if (ret != 0) {
332 krb5err = krb5_get_error_message(context, ret);
333 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
334 krb5_free_error_message(context, krb5err);
335 return ret;
338 ret = krb5_crypto_getenctype(context, cred_crypto, &cred_enctype);
339 if (ret != 0) {
340 DEBUG(1, ("Failed getting crypto type for key\n"));
341 krb5_crypto_destroy(context, cred_crypto);
342 return ret;
345 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
346 cred_ndr_blob->length));
347 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
348 cred_ndr_blob->data, cred_ndr_blob->length);
350 ret = krb5_encrypt(context, cred_crypto,
351 KRB5_KU_OTHER_ENCRYPTED,
352 cred_ndr_blob->data, cred_ndr_blob->length,
353 &cred_ndr_crypt);
354 krb5_crypto_destroy(context, cred_crypto);
355 if (ret != 0) {
356 krb5err = krb5_get_error_message(context, ret);
357 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err));
358 krb5_free_error_message(context, krb5err);
359 return ret;
362 pac_cred_info.encryption_type = cred_enctype;
363 pac_cred_info.encrypted_data.length = cred_ndr_crypt.length;
364 pac_cred_info.encrypted_data.data = (uint8_t *)cred_ndr_crypt.data;
366 if (DEBUGLVL(10)) {
367 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
370 ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
371 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
372 krb5_data_free(&cred_ndr_crypt);
373 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
374 nt_status = ndr_map_error2ntstatus(ndr_err);
375 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
376 nt_errstr(nt_status)));
377 return KRB5KDC_ERR_SVC_UNAVAILABLE;
380 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
381 cred_info_blob->length, (int)pac_cred_info.encryption_type));
382 dump_data_pw("PAC_CREDENTIAL_INFO",
383 cred_info_blob->data, cred_info_blob->length);
385 return 0;
387 #else /* SAMBA4_USES_HEIMDAL */
388 krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
389 const krb5_keyblock *pkreplykey,
390 const DATA_BLOB *cred_ndr_blob,
391 TALLOC_CTX *mem_ctx,
392 DATA_BLOB *cred_info_blob)
394 krb5_key cred_key;
395 krb5_enctype cred_enctype;
396 struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
397 krb5_error_code code;
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 size_t enc_len = 0;
405 *cred_info_blob = data_blob_null;
407 code = krb5_k_create_key(context,
408 pkreplykey,
409 &cred_key);
410 if (code != 0) {
411 krb5err = krb5_get_error_message(context, code);
412 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
413 krb5_free_error_message(context, krb5err);
414 return code;
417 cred_enctype = krb5_k_key_enctype(context, cred_key);
419 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
420 cred_ndr_blob->length));
421 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
422 cred_ndr_blob->data, cred_ndr_blob->length);
424 pac_cred_info.encryption_type = cred_enctype;
426 cred_ndr_data.magic = 0;
427 cred_ndr_data.data = (char *)cred_ndr_blob->data;
428 cred_ndr_data.length = cred_ndr_blob->length;
430 code = krb5_c_encrypt_length(context,
431 cred_enctype,
432 cred_ndr_data.length,
433 &enc_len);
434 if (code != 0) {
435 krb5err = krb5_get_error_message(context, code);
436 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
437 krb5_free_error_message(context, krb5err);
438 return code;
441 pac_cred_info.encrypted_data = data_blob_talloc_zero(mem_ctx, enc_len);
442 if (pac_cred_info.encrypted_data.data == NULL) {
443 DBG_ERR("Out of memory\n");
444 return ENOMEM;
447 cred_ndr_crypt.ciphertext.length = enc_len;
448 cred_ndr_crypt.ciphertext.data = (char *)pac_cred_info.encrypted_data.data;
450 code = krb5_k_encrypt(context,
451 cred_key,
452 KRB5_KU_OTHER_ENCRYPTED,
453 NULL,
454 &cred_ndr_data,
455 &cred_ndr_crypt);
456 krb5_k_free_key(context, cred_key);
457 if (code != 0) {
458 krb5err = krb5_get_error_message(context, code);
459 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err));
460 krb5_free_error_message(context, krb5err);
461 return code;
464 if (DEBUGLVL(10)) {
465 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
468 ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
469 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
470 TALLOC_FREE(pac_cred_info.encrypted_data.data);
471 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
472 nt_status = ndr_map_error2ntstatus(ndr_err);
473 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
474 nt_errstr(nt_status)));
475 return KRB5KDC_ERR_SVC_UNAVAILABLE;
478 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
479 cred_info_blob->length, (int)pac_cred_info.encryption_type));
480 dump_data_pw("PAC_CREDENTIAL_INFO",
481 cred_info_blob->data, cred_info_blob->length);
483 return 0;
485 #endif /* SAMBA4_USES_HEIMDAL */
489 * @brief Create a PAC with the given blobs (logon, credentials, upn and
490 * delegation).
492 * @param[in] context The KRB5 context to use.
494 * @param[in] logon_blob Fill the logon info PAC buffer with the given blob,
495 * use NULL to ignore it.
497 * @param[in] cred_blob Fill the credentials info PAC buffer with the given
498 * blob, use NULL to ignore it.
500 * @param[in] upn_blob Fill the UPN info PAC buffer with the given blob, use
501 * NULL to ignore it.
503 * @param[in] deleg_blob Fill the delegation info PAC buffer with the given
504 * blob, use NULL to ignore it.
506 * @param[in] pac The pac buffer to fill. This should be allocated with
507 * krb5_pac_init() already.
509 * @returns 0 on success or a corresponding KRB5 error.
511 krb5_error_code samba_make_krb5_pac(krb5_context context,
512 const DATA_BLOB *logon_blob,
513 const DATA_BLOB *cred_blob,
514 const DATA_BLOB *upn_blob,
515 const DATA_BLOB *pac_attrs_blob,
516 const DATA_BLOB *requester_sid_blob,
517 const DATA_BLOB *deleg_blob,
518 krb5_pac pac)
520 krb5_data logon_data;
521 krb5_data cred_data;
522 krb5_data upn_data;
523 krb5_data pac_attrs_data;
524 krb5_data requester_sid_data;
525 krb5_data deleg_data;
526 krb5_error_code ret;
527 #ifdef SAMBA4_USES_HEIMDAL
528 char null_byte = '\0';
529 krb5_data null_data = {
530 .length = 1,
531 .data = &null_byte,
533 #endif
535 /* The user account may be set not to want the PAC */
536 if (logon_blob == NULL) {
537 return 0;
540 ret = smb_krb5_copy_data_contents(&logon_data,
541 logon_blob->data,
542 logon_blob->length);
543 if (ret != 0) {
544 return ret;
547 ZERO_STRUCT(cred_data);
548 if (cred_blob != NULL) {
549 ret = smb_krb5_copy_data_contents(&cred_data,
550 cred_blob->data,
551 cred_blob->length);
552 if (ret != 0) {
553 smb_krb5_free_data_contents(context, &logon_data);
554 return ret;
558 ZERO_STRUCT(upn_data);
559 if (upn_blob != NULL) {
560 ret = smb_krb5_copy_data_contents(&upn_data,
561 upn_blob->data,
562 upn_blob->length);
563 if (ret != 0) {
564 smb_krb5_free_data_contents(context, &logon_data);
565 smb_krb5_free_data_contents(context, &cred_data);
566 return ret;
570 ZERO_STRUCT(pac_attrs_data);
571 if (pac_attrs_blob != NULL) {
572 ret = smb_krb5_copy_data_contents(&pac_attrs_data,
573 pac_attrs_blob->data,
574 pac_attrs_blob->length);
575 if (ret != 0) {
576 smb_krb5_free_data_contents(context, &logon_data);
577 smb_krb5_free_data_contents(context, &cred_data);
578 smb_krb5_free_data_contents(context, &upn_data);
579 return ret;
583 ZERO_STRUCT(requester_sid_data);
584 if (requester_sid_blob != NULL) {
585 ret = smb_krb5_copy_data_contents(&requester_sid_data,
586 requester_sid_blob->data,
587 requester_sid_blob->length);
588 if (ret != 0) {
589 smb_krb5_free_data_contents(context, &logon_data);
590 smb_krb5_free_data_contents(context, &cred_data);
591 smb_krb5_free_data_contents(context, &upn_data);
592 smb_krb5_free_data_contents(context, &pac_attrs_data);
593 return ret;
597 ZERO_STRUCT(deleg_data);
598 if (deleg_blob != NULL) {
599 ret = smb_krb5_copy_data_contents(&deleg_data,
600 deleg_blob->data,
601 deleg_blob->length);
602 if (ret != 0) {
603 smb_krb5_free_data_contents(context, &logon_data);
604 smb_krb5_free_data_contents(context, &cred_data);
605 smb_krb5_free_data_contents(context, &upn_data);
606 smb_krb5_free_data_contents(context, &pac_attrs_data);
607 smb_krb5_free_data_contents(context, &requester_sid_data);
608 return ret;
612 ret = krb5_pac_add_buffer(context, pac, PAC_TYPE_LOGON_INFO, &logon_data);
613 smb_krb5_free_data_contents(context, &logon_data);
614 if (ret != 0) {
615 smb_krb5_free_data_contents(context, &cred_data);
616 smb_krb5_free_data_contents(context, &upn_data);
617 smb_krb5_free_data_contents(context, &pac_attrs_data);
618 smb_krb5_free_data_contents(context, &requester_sid_data);
619 smb_krb5_free_data_contents(context, &deleg_data);
620 return ret;
623 if (cred_blob != NULL) {
624 ret = krb5_pac_add_buffer(context, pac,
625 PAC_TYPE_CREDENTIAL_INFO,
626 &cred_data);
627 smb_krb5_free_data_contents(context, &cred_data);
628 if (ret != 0) {
629 smb_krb5_free_data_contents(context, &upn_data);
630 smb_krb5_free_data_contents(context, &pac_attrs_data);
631 smb_krb5_free_data_contents(context, &requester_sid_data);
632 smb_krb5_free_data_contents(context, &deleg_data);
633 return ret;
637 #ifdef SAMBA4_USES_HEIMDAL
639 * null_data will be filled by the generic KDC code in the caller
640 * here we just add it in order to have it before
641 * PAC_TYPE_UPN_DNS_INFO
643 * Not needed with MIT Kerberos - asn
645 ret = krb5_pac_add_buffer(context, pac,
646 PAC_TYPE_LOGON_NAME,
647 &null_data);
648 if (ret != 0) {
649 smb_krb5_free_data_contents(context, &upn_data);
650 smb_krb5_free_data_contents(context, &pac_attrs_data);
651 smb_krb5_free_data_contents(context, &requester_sid_data);
652 smb_krb5_free_data_contents(context, &deleg_data);
653 return ret;
655 #endif
657 if (upn_blob != NULL) {
658 ret = krb5_pac_add_buffer(context, pac,
659 PAC_TYPE_UPN_DNS_INFO,
660 &upn_data);
661 smb_krb5_free_data_contents(context, &upn_data);
662 if (ret != 0) {
663 smb_krb5_free_data_contents(context, &pac_attrs_data);
664 smb_krb5_free_data_contents(context, &requester_sid_data);
665 smb_krb5_free_data_contents(context, &deleg_data);
666 return ret;
670 if (pac_attrs_blob != NULL) {
671 ret = krb5_pac_add_buffer(context, pac,
672 PAC_TYPE_ATTRIBUTES_INFO,
673 &pac_attrs_data);
674 smb_krb5_free_data_contents(context, &pac_attrs_data);
675 if (ret != 0) {
676 smb_krb5_free_data_contents(context, &requester_sid_data);
677 smb_krb5_free_data_contents(context, &deleg_data);
678 return ret;
682 if (requester_sid_blob != NULL) {
683 ret = krb5_pac_add_buffer(context, pac,
684 PAC_TYPE_REQUESTER_SID,
685 &requester_sid_data);
686 smb_krb5_free_data_contents(context, &requester_sid_data);
687 if (ret != 0) {
688 smb_krb5_free_data_contents(context, &deleg_data);
689 return ret;
693 if (deleg_blob != NULL) {
694 ret = krb5_pac_add_buffer(context, pac,
695 PAC_TYPE_CONSTRAINED_DELEGATION,
696 &deleg_data);
697 smb_krb5_free_data_contents(context, &deleg_data);
698 if (ret != 0) {
699 return ret;
703 return ret;
706 bool samba_princ_needs_pac(struct samba_kdc_entry *skdc_entry)
709 uint32_t userAccountControl;
711 /* The service account may be set not to want the PAC */
712 userAccountControl = ldb_msg_find_attr_as_uint(skdc_entry->msg, "userAccountControl", 0);
713 if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
714 return false;
717 return true;
720 int samba_client_requested_pac(krb5_context context,
721 const krb5_pac *pac,
722 TALLOC_CTX *mem_ctx,
723 bool *requested_pac)
725 enum ndr_err_code ndr_err;
726 krb5_data k5pac_attrs_in;
727 DATA_BLOB pac_attrs_in;
728 union PAC_INFO pac_attrs;
729 int ret;
731 *requested_pac = true;
733 ret = krb5_pac_get_buffer(context, *pac, PAC_TYPE_ATTRIBUTES_INFO,
734 &k5pac_attrs_in);
735 if (ret != 0) {
736 return ret == ENOENT ? 0 : ret;
739 pac_attrs_in = data_blob_const(k5pac_attrs_in.data,
740 k5pac_attrs_in.length);
742 ndr_err = ndr_pull_union_blob(&pac_attrs_in, mem_ctx, &pac_attrs,
743 PAC_TYPE_ATTRIBUTES_INFO,
744 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
745 smb_krb5_free_data_contents(context, &k5pac_attrs_in);
746 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
747 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
748 DEBUG(0,("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status)));
749 return EINVAL;
752 if (pac_attrs.attributes_info.flags & (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
753 | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED)) {
754 *requested_pac = true;
755 } else {
756 *requested_pac = false;
759 return 0;
762 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
763 int samba_krbtgt_is_in_db(struct samba_kdc_entry *p,
764 bool *is_in_db,
765 bool *is_untrusted)
767 NTSTATUS status;
768 int rodc_krbtgt_number, trust_direction;
769 uint32_t rid;
771 TALLOC_CTX *mem_ctx = talloc_new(NULL);
772 if (!mem_ctx) {
773 return ENOMEM;
776 trust_direction = ldb_msg_find_attr_as_int(p->msg, "trustDirection", 0);
778 if (trust_direction != 0) {
779 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
781 This is exactly where we should flag for SID
782 validation when we do inter-foreest trusts
784 talloc_free(mem_ctx);
785 *is_untrusted = false;
786 *is_in_db = false;
787 return 0;
790 /* The lack of password controls etc applies to krbtgt by
791 * virtue of being that particular RID */
792 status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, p->msg, "objectSid"), NULL, &rid);
794 if (!NT_STATUS_IS_OK(status)) {
795 talloc_free(mem_ctx);
796 return EINVAL;
799 rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1);
801 if (p->kdc_db_ctx->my_krbtgt_number == 0) {
802 if (rid == DOMAIN_RID_KRBTGT) {
803 *is_untrusted = false;
804 *is_in_db = true;
805 talloc_free(mem_ctx);
806 return 0;
807 } else if (rodc_krbtgt_number != -1) {
808 *is_in_db = true;
809 *is_untrusted = true;
810 talloc_free(mem_ctx);
811 return 0;
813 } else if ((rid != DOMAIN_RID_KRBTGT) && (rodc_krbtgt_number == p->kdc_db_ctx->my_krbtgt_number)) {
814 talloc_free(mem_ctx);
815 *is_untrusted = false;
816 *is_in_db = true;
817 return 0;
818 } else if (rid == DOMAIN_RID_KRBTGT) {
819 /* krbtgt viewed from an RODC */
820 talloc_free(mem_ctx);
821 *is_untrusted = false;
822 *is_in_db = false;
823 return 0;
826 /* Another RODC */
827 talloc_free(mem_ctx);
828 *is_untrusted = true;
829 *is_in_db = false;
830 return 0;
834 * Because the KDC does not limit protocol transition, two new well-known SIDs
835 * were introduced to give this control to the resource administrator. These
836 * SIDs identify whether protocol transition has occurred, and can be used with
837 * standard access control lists to grant or limit access as needed.
839 * https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview
841 static NTSTATUS samba_add_asserted_identity(TALLOC_CTX *mem_ctx,
842 enum samba_asserted_identity ai,
843 struct auth_user_info_dc *user_info_dc)
845 struct dom_sid ai_sid;
846 const char *sid_str = NULL;
848 switch (ai) {
849 case SAMBA_ASSERTED_IDENTITY_SERVICE:
850 sid_str = SID_SERVICE_ASSERTED_IDENTITY;
851 break;
852 case SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY:
853 sid_str = SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY;
854 break;
855 case SAMBA_ASSERTED_IDENTITY_IGNORE:
856 return NT_STATUS_OK;
859 dom_sid_parse(sid_str, &ai_sid);
861 return add_sid_to_array_unique(user_info_dc,
862 &ai_sid,
863 &user_info_dc->sids,
864 &user_info_dc->num_sids);
868 * Look up the user's info in the database and create a auth_user_info_dc
869 * structure. If the resulting structure is not talloc_free()d, it will be
870 * reused on future calls to this function.
872 NTSTATUS samba_kdc_get_user_info_from_db(struct samba_kdc_entry *skdc_entry,
873 struct ldb_message *msg,
874 struct auth_user_info_dc **user_info_dc)
876 if (skdc_entry->user_info_dc == NULL) {
877 NTSTATUS nt_status;
878 struct loadparm_context *lp_ctx = skdc_entry->kdc_db_ctx->lp_ctx;
880 nt_status = authsam_make_user_info_dc(skdc_entry,
881 skdc_entry->kdc_db_ctx->samdb,
882 lpcfg_netbios_name(lp_ctx),
883 lpcfg_sam_name(lp_ctx),
884 lpcfg_sam_dnsname(lp_ctx),
885 skdc_entry->realm_dn,
886 msg,
887 data_blob_null,
888 data_blob_null,
889 &skdc_entry->user_info_dc);
890 if (!NT_STATUS_IS_OK(nt_status)) {
891 return nt_status;
895 *user_info_dc = skdc_entry->user_info_dc;
896 return NT_STATUS_OK;
899 NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
900 struct samba_kdc_entry *p,
901 enum samba_asserted_identity asserted_identity,
902 DATA_BLOB **_logon_info_blob,
903 DATA_BLOB **_cred_ndr_blob,
904 DATA_BLOB **_upn_info_blob,
905 DATA_BLOB **_pac_attrs_blob,
906 uint64_t pac_attributes,
907 DATA_BLOB **_requester_sid_blob)
909 struct auth_user_info_dc *user_info_dc = NULL;
910 DATA_BLOB *logon_blob = NULL;
911 DATA_BLOB *cred_blob = NULL;
912 DATA_BLOB *upn_blob = NULL;
913 DATA_BLOB *pac_attrs_blob = NULL;
914 DATA_BLOB *requester_sid_blob = NULL;
915 NTSTATUS nt_status;
917 *_logon_info_blob = NULL;
918 if (_cred_ndr_blob != NULL) {
919 *_cred_ndr_blob = NULL;
921 *_upn_info_blob = NULL;
922 if (_pac_attrs_blob != NULL) {
923 *_pac_attrs_blob = NULL;
925 if (_requester_sid_blob != NULL) {
926 *_requester_sid_blob = NULL;
929 logon_blob = talloc_zero(mem_ctx, DATA_BLOB);
930 if (logon_blob == NULL) {
931 return NT_STATUS_NO_MEMORY;
934 if (_cred_ndr_blob != NULL) {
935 cred_blob = talloc_zero(mem_ctx, DATA_BLOB);
936 if (cred_blob == NULL) {
937 return NT_STATUS_NO_MEMORY;
941 upn_blob = talloc_zero(mem_ctx, DATA_BLOB);
942 if (upn_blob == NULL) {
943 return NT_STATUS_NO_MEMORY;
946 if (_pac_attrs_blob != NULL) {
947 pac_attrs_blob = talloc_zero(mem_ctx, DATA_BLOB);
948 if (pac_attrs_blob == NULL) {
949 return NT_STATUS_NO_MEMORY;
953 if (_requester_sid_blob != NULL) {
954 requester_sid_blob = talloc_zero(mem_ctx, DATA_BLOB);
955 if (requester_sid_blob == NULL) {
956 return NT_STATUS_NO_MEMORY;
960 nt_status = samba_kdc_get_user_info_from_db(p,
961 p->msg,
962 &user_info_dc);
963 if (!NT_STATUS_IS_OK(nt_status)) {
964 DEBUG(0, ("Getting user info for PAC failed: %s\n",
965 nt_errstr(nt_status)));
966 return nt_status;
969 nt_status = samba_add_asserted_identity(mem_ctx,
970 asserted_identity,
971 user_info_dc);
972 if (!NT_STATUS_IS_OK(nt_status)) {
973 DBG_ERR("Failed to add assertied identity!\n");
974 return nt_status;
977 nt_status = samba_get_logon_info_pac_blob(logon_blob,
978 user_info_dc,
979 logon_blob,
980 requester_sid_blob);
981 if (!NT_STATUS_IS_OK(nt_status)) {
982 DEBUG(0, ("Building PAC LOGON INFO failed: %s\n",
983 nt_errstr(nt_status)));
984 return nt_status;
987 if (cred_blob != NULL) {
988 nt_status = samba_get_cred_info_ndr_blob(cred_blob,
989 p->msg,
990 cred_blob);
991 if (!NT_STATUS_IS_OK(nt_status)) {
992 DEBUG(0, ("Building PAC CRED INFO failed: %s\n",
993 nt_errstr(nt_status)));
994 return nt_status;
998 nt_status = samba_get_upn_info_pac_blob(upn_blob,
999 user_info_dc,
1000 upn_blob);
1001 if (!NT_STATUS_IS_OK(nt_status)) {
1002 DEBUG(0, ("Building PAC UPN INFO failed: %s\n",
1003 nt_errstr(nt_status)));
1004 return nt_status;
1007 if (pac_attrs_blob != NULL) {
1008 nt_status = samba_get_pac_attrs_blob(pac_attrs_blob,
1009 pac_attributes,
1010 pac_attrs_blob);
1012 if (!NT_STATUS_IS_OK(nt_status)) {
1013 DEBUG(0, ("Building PAC ATTRIBUTES failed: %s\n",
1014 nt_errstr(nt_status)));
1015 return nt_status;
1019 *_logon_info_blob = logon_blob;
1020 if (_cred_ndr_blob != NULL) {
1021 *_cred_ndr_blob = cred_blob;
1023 *_upn_info_blob = upn_blob;
1024 if (_pac_attrs_blob != NULL) {
1025 *_pac_attrs_blob = pac_attrs_blob;
1027 if (_requester_sid_blob != NULL) {
1028 *_requester_sid_blob = requester_sid_blob;
1030 return NT_STATUS_OK;
1033 NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
1034 krb5_context context,
1035 struct ldb_context *samdb,
1036 const krb5_pac pac, DATA_BLOB *pac_blob,
1037 struct PAC_SIGNATURE_DATA *pac_srv_sig,
1038 struct PAC_SIGNATURE_DATA *pac_kdc_sig)
1040 struct auth_user_info_dc *user_info_dc;
1041 krb5_error_code ret;
1042 NTSTATUS nt_status;
1044 ret = kerberos_pac_to_user_info_dc(mem_ctx, pac,
1045 context, &user_info_dc, pac_srv_sig, pac_kdc_sig);
1046 if (ret) {
1047 return NT_STATUS_UNSUCCESSFUL;
1051 * We need to expand group memberships within our local domain,
1052 * as the token might be generated by a trusted domain.
1054 nt_status = authsam_update_user_info_dc(mem_ctx,
1055 samdb,
1056 user_info_dc);
1057 if (!NT_STATUS_IS_OK(nt_status)) {
1058 return nt_status;
1061 nt_status = samba_get_logon_info_pac_blob(mem_ctx,
1062 user_info_dc, pac_blob, NULL);
1064 return nt_status;
1067 NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx,
1068 krb5_context context,
1069 const krb5_pac pac,
1070 const krb5_principal server_principal,
1071 const krb5_principal proxy_principal,
1072 DATA_BLOB *new_blob)
1074 krb5_data old_data;
1075 DATA_BLOB old_blob;
1076 krb5_error_code ret;
1077 NTSTATUS nt_status;
1078 enum ndr_err_code ndr_err;
1079 union PAC_INFO info;
1080 struct PAC_CONSTRAINED_DELEGATION _d;
1081 struct PAC_CONSTRAINED_DELEGATION *d = NULL;
1082 char *server = NULL;
1083 char *proxy = NULL;
1084 uint32_t i;
1085 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1087 if (tmp_ctx == NULL) {
1088 return NT_STATUS_NO_MEMORY;
1091 ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_CONSTRAINED_DELEGATION, &old_data);
1092 if (ret == ENOENT) {
1093 ZERO_STRUCT(old_data);
1094 } else if (ret) {
1095 talloc_free(tmp_ctx);
1096 return NT_STATUS_UNSUCCESSFUL;
1099 old_blob.length = old_data.length;
1100 old_blob.data = (uint8_t *)old_data.data;
1102 ZERO_STRUCT(info);
1103 if (old_blob.length > 0) {
1104 ndr_err = ndr_pull_union_blob(&old_blob, mem_ctx,
1105 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
1106 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1107 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1108 smb_krb5_free_data_contents(context, &old_data);
1109 nt_status = ndr_map_error2ntstatus(ndr_err);
1110 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
1111 talloc_free(tmp_ctx);
1112 return nt_status;
1114 } else {
1115 ZERO_STRUCT(_d);
1116 info.constrained_delegation.info = &_d;
1118 smb_krb5_free_data_contents(context, &old_data);
1120 ret = krb5_unparse_name_flags(context, server_principal,
1121 KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server);
1122 if (ret) {
1123 talloc_free(tmp_ctx);
1124 return NT_STATUS_INTERNAL_ERROR;
1127 ret = krb5_unparse_name(context, proxy_principal, &proxy);
1128 if (ret) {
1129 SAFE_FREE(server);
1130 talloc_free(tmp_ctx);
1131 return NT_STATUS_INTERNAL_ERROR;
1134 d = info.constrained_delegation.info;
1135 i = d->num_transited_services;
1136 d->proxy_target.string = server;
1137 d->transited_services = talloc_realloc(mem_ctx, d->transited_services,
1138 struct lsa_String, i + 1);
1139 d->transited_services[i].string = proxy;
1140 d->num_transited_services = i + 1;
1142 ndr_err = ndr_push_union_blob(new_blob, mem_ctx,
1143 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
1144 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
1145 SAFE_FREE(server);
1146 SAFE_FREE(proxy);
1147 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1148 smb_krb5_free_data_contents(context, &old_data);
1149 nt_status = ndr_map_error2ntstatus(ndr_err);
1150 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
1151 talloc_free(tmp_ctx);
1152 return nt_status;
1155 talloc_free(tmp_ctx);
1156 return NT_STATUS_OK;
1159 /* function to map policy errors */
1160 krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status)
1162 krb5_error_code ret;
1164 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE))
1165 ret = KRB5KDC_ERR_KEY_EXP;
1166 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED))
1167 ret = KRB5KDC_ERR_KEY_EXP;
1168 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED))
1169 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1170 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED))
1171 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1172 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS))
1173 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1174 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT))
1175 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1176 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION))
1177 ret = KRB5KDC_ERR_POLICY;
1178 else
1179 ret = KRB5KDC_ERR_POLICY;
1181 return ret;
1184 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
1185 * for consistency */
1186 NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry,
1187 const char *client_name,
1188 const char *workstation,
1189 bool password_change)
1191 TALLOC_CTX *tmp_ctx;
1192 NTSTATUS nt_status;
1194 tmp_ctx = talloc_named(NULL, 0, "samba_kdc_check_client_access");
1195 if (!tmp_ctx) {
1196 return NT_STATUS_NO_MEMORY;
1199 /* we allow all kinds of trusts here */
1200 nt_status = authsam_account_ok(tmp_ctx,
1201 kdc_entry->kdc_db_ctx->samdb,
1202 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
1203 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
1204 kdc_entry->realm_dn, kdc_entry->msg,
1205 workstation, client_name,
1206 true, password_change);
1208 kdc_entry->reject_status = nt_status;
1209 talloc_free(tmp_ctx);
1210 return nt_status;
1213 static krb5_error_code samba_get_requester_sid(TALLOC_CTX *mem_ctx,
1214 krb5_pac pac,
1215 krb5_context context,
1216 struct dom_sid *sid)
1218 NTSTATUS nt_status;
1219 enum ndr_err_code ndr_err;
1220 krb5_error_code ret;
1222 DATA_BLOB pac_requester_sid_in;
1223 krb5_data k5pac_requester_sid_in;
1225 union PAC_INFO info;
1227 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1228 if (tmp_ctx == NULL) {
1229 return ENOMEM;
1232 ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_REQUESTER_SID,
1233 &k5pac_requester_sid_in);
1234 if (ret != 0) {
1235 talloc_free(tmp_ctx);
1236 return ret;
1239 pac_requester_sid_in = data_blob_const(k5pac_requester_sid_in.data,
1240 k5pac_requester_sid_in.length);
1242 ndr_err = ndr_pull_union_blob(&pac_requester_sid_in, tmp_ctx, &info,
1243 PAC_TYPE_REQUESTER_SID,
1244 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1245 smb_krb5_free_data_contents(context, &k5pac_requester_sid_in);
1246 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1247 nt_status = ndr_map_error2ntstatus(ndr_err);
1248 DEBUG(0,("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status)));
1249 talloc_free(tmp_ctx);
1250 return EINVAL;
1253 *sid = info.requester_sid.sid;
1255 talloc_free(tmp_ctx);
1256 return 0;
1259 /* Does a parse and SID check, but no crypto. */
1260 krb5_error_code samba_kdc_validate_pac_blob(
1261 krb5_context context,
1262 struct samba_kdc_entry *client_skdc_entry,
1263 const krb5_pac pac)
1265 TALLOC_CTX *frame = talloc_stackframe();
1266 struct auth_user_info_dc *pac_user_info = NULL;
1267 struct dom_sid *client_sid = NULL;
1268 struct dom_sid pac_sid;
1269 krb5_error_code code;
1270 bool ok;
1273 * First, try to get the SID from the requester SID buffer in the PAC.
1275 code = samba_get_requester_sid(frame, pac, context, &pac_sid);
1277 if (code == ENOENT) {
1279 * If the requester SID buffer isn't present, fall back to the
1280 * SID in the LOGON_INFO PAC buffer.
1282 code = kerberos_pac_to_user_info_dc(frame,
1283 pac,
1284 context,
1285 &pac_user_info,
1286 NULL,
1287 NULL);
1288 if (code != 0) {
1289 goto out;
1292 if (pac_user_info->num_sids == 0) {
1293 code = EINVAL;
1294 goto out;
1297 pac_sid = pac_user_info->sids[0];
1298 } else if (code != 0) {
1299 goto out;
1302 client_sid = samdb_result_dom_sid(frame,
1303 client_skdc_entry->msg,
1304 "objectSid");
1306 ok = dom_sid_equal(&pac_sid, client_sid);
1307 if (!ok) {
1308 struct dom_sid_buf buf1;
1309 struct dom_sid_buf buf2;
1311 DBG_ERR("SID mismatch between PAC and looked up client: "
1312 "PAC[%s] != CLI[%s]\n",
1313 dom_sid_str_buf(&pac_sid, &buf1),
1314 dom_sid_str_buf(client_sid, &buf2));
1315 code = KRB5KDC_ERR_TGT_REVOKED;
1316 goto out;
1319 code = 0;
1320 out:
1321 TALLOC_FREE(frame);
1322 return code;
1327 * In the RODC case, to confirm that the returned user is permitted to
1328 * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
1330 WERROR samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids,
1331 struct dom_sid *object_sids,
1332 struct samba_kdc_entry *rodc,
1333 struct samba_kdc_entry *object)
1335 int ret;
1336 WERROR werr;
1337 TALLOC_CTX *frame = talloc_stackframe();
1338 const char *rodc_attrs[] = { "msDS-KrbTgtLink",
1339 "msDS-NeverRevealGroup",
1340 "msDS-RevealOnDemandGroup",
1341 "userAccountControl",
1342 "objectSid",
1343 NULL };
1344 struct ldb_result *rodc_machine_account = NULL;
1345 struct ldb_dn *rodc_machine_account_dn = samdb_result_dn(rodc->kdc_db_ctx->samdb,
1346 frame,
1347 rodc->msg,
1348 "msDS-KrbTgtLinkBL",
1349 NULL);
1350 const struct dom_sid *rodc_machine_account_sid = NULL;
1352 if (rodc_machine_account_dn == NULL) {
1353 DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
1354 ldb_dn_get_linearized(rodc->msg->dn));
1355 TALLOC_FREE(frame);
1356 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1360 * Follow the link and get the RODC account (the krbtgt
1361 * account is the krbtgt_XXX account, but the
1362 * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
1363 * the RODC$ account)
1365 * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
1366 * out of the extended DNs
1369 ret = dsdb_search_dn(rodc->kdc_db_ctx->samdb,
1370 frame,
1371 &rodc_machine_account,
1372 rodc_machine_account_dn,
1373 rodc_attrs,
1374 DSDB_SEARCH_SHOW_EXTENDED_DN);
1375 if (ret != LDB_SUCCESS) {
1376 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
1377 ldb_dn_get_linearized(rodc_machine_account_dn),
1378 ldb_dn_get_linearized(rodc->msg->dn),
1379 ldb_errstring(rodc->kdc_db_ctx->samdb));
1380 TALLOC_FREE(frame);
1381 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1384 if (rodc_machine_account->count != 1) {
1385 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
1386 ldb_dn_get_linearized(rodc_machine_account_dn),
1387 ldb_dn_get_linearized(rodc->msg->dn),
1388 rodc_machine_account->count);
1389 TALLOC_FREE(frame);
1390 return WERR_DS_DRA_BAD_DN;
1393 /* if the object SID is equal to the user_sid, allow */
1394 rodc_machine_account_sid = samdb_result_dom_sid(frame,
1395 rodc_machine_account->msgs[0],
1396 "objectSid");
1397 if (rodc_machine_account_sid == NULL) {
1398 return WERR_DS_DRA_BAD_DN;
1401 werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc->kdc_db_ctx->samdb,
1402 rodc_machine_account_sid,
1403 rodc_machine_account->msgs[0],
1404 object->msg,
1405 num_object_sids,
1406 object_sids);
1408 TALLOC_FREE(frame);
1409 return werr;
1413 * @brief Update a PAC
1415 * @param mem_ctx A talloc memory context
1417 * @param context A krb5 context
1419 * @param samdb An open samdb connection.
1421 * @param flags Bitwise OR'ed flags
1423 * @param client The client samba kdc entry.
1425 * @param server_principal The server principal
1427 * @param server The server samba kdc entry.
1429 * @param krbtgt The krbtgt samba kdc entry.
1431 * @param delegated_proxy_principal The delegated proxy principal used for
1432 * updating the constrained delegation PAC
1433 * buffer.
1435 * @param old_pac The old PAC
1437 * @param new_pac The new already allocated PAC
1439 * @return A Kerberos error code. If no PAC should be returned, the code will be
1440 * ENODATA!
1442 krb5_error_code samba_kdc_update_pac(TALLOC_CTX *mem_ctx,
1443 krb5_context context,
1444 struct ldb_context *samdb,
1445 uint32_t flags,
1446 struct samba_kdc_entry *client,
1447 const krb5_principal server_principal,
1448 struct samba_kdc_entry *server,
1449 struct samba_kdc_entry *krbtgt,
1450 const krb5_principal delegated_proxy_principal,
1451 const krb5_pac old_pac,
1452 krb5_pac new_pac)
1454 krb5_error_code code = EINVAL;
1455 NTSTATUS nt_status;
1456 DATA_BLOB *pac_blob = NULL;
1457 DATA_BLOB *upn_blob = NULL;
1458 DATA_BLOB *deleg_blob = NULL;
1459 DATA_BLOB *requester_sid_blob = NULL;
1460 bool is_untrusted = flags & SAMBA_KDC_FLAG_KRBTGT_IS_UNTRUSTED;
1461 int is_tgs = false;
1462 size_t num_types = 0;
1463 uint32_t *types = NULL;
1465 * FIXME: Do we really still need forced_next_type? With MIT Kerberos
1466 * the PAC buffers do not get ordered and it works just fine. We are
1467 * not aware of any issues in this regard. This might be just ancient
1468 * code.
1470 uint32_t forced_next_type = 0;
1471 size_t i = 0;
1472 ssize_t logon_info_idx = -1;
1473 ssize_t delegation_idx = -1;
1474 ssize_t logon_name_idx = -1;
1475 ssize_t upn_dns_info_idx = -1;
1476 ssize_t srv_checksum_idx = -1;
1477 ssize_t kdc_checksum_idx = -1;
1478 ssize_t tkt_checksum_idx = -1;
1479 ssize_t attrs_info_idx = -1;
1480 ssize_t requester_sid_idx = -1;
1482 if (client != NULL) {
1484 * Check the objectSID of the client and pac data are the same.
1485 * Does a parse and SID check, but no crypto.
1487 code = samba_kdc_validate_pac_blob(context,
1488 client,
1489 old_pac);
1490 if (code != 0) {
1491 goto done;
1495 if (delegated_proxy_principal != NULL) {
1496 deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
1497 if (deleg_blob == NULL) {
1498 code = ENOMEM;
1499 goto done;
1502 nt_status = samba_kdc_update_delegation_info_blob(
1503 mem_ctx,
1504 context,
1505 old_pac,
1506 server_principal,
1507 delegated_proxy_principal,
1508 deleg_blob);
1509 if (!NT_STATUS_IS_OK(nt_status)) {
1510 DBG_ERR("update delegation info blob failed: %s\n",
1511 nt_errstr(nt_status));
1512 code = EINVAL;
1513 goto done;
1517 if (is_untrusted) {
1518 struct auth_user_info_dc *user_info_dc = NULL;
1519 WERROR werr;
1521 * In this case the RWDC discards the PAC an RODC generated.
1522 * Windows adds the asserted_identity in this case too.
1524 * Note that SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
1525 * generates KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN.
1526 * So we can always use
1527 * SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
1528 * here.
1530 enum samba_asserted_identity asserted_identity =
1531 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY;
1533 if (client == NULL) {
1534 code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1535 goto done;
1538 nt_status = samba_kdc_get_pac_blobs(mem_ctx,
1539 client,
1540 asserted_identity,
1541 &pac_blob,
1542 NULL,
1543 &upn_blob,
1544 NULL,
1545 PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY,
1546 &requester_sid_blob);
1547 if (!NT_STATUS_IS_OK(nt_status)) {
1548 DBG_ERR("samba_kdc_get_pac_blobs failed: %s\n",
1549 nt_errstr(nt_status));
1550 code = KRB5KDC_ERR_TGT_REVOKED;
1551 goto done;
1554 nt_status = samba_kdc_get_user_info_from_db(client,
1555 client->msg,
1556 &user_info_dc);
1557 if (!NT_STATUS_IS_OK(nt_status)) {
1558 DBG_ERR("samba_kdc_get_user_info_from_db failed: %s\n",
1559 nt_errstr(nt_status));
1560 code = KRB5KDC_ERR_TGT_REVOKED;
1561 goto done;
1565 * Check if the SID list in the user_info_dc intersects
1566 * correctly with the RODC allow/deny lists.
1568 werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids,
1569 user_info_dc->sids,
1570 krbtgt,
1571 client);
1572 TALLOC_FREE(user_info_dc);
1573 if (!W_ERROR_IS_OK(werr)) {
1574 code = KRB5KDC_ERR_TGT_REVOKED;
1575 if (W_ERROR_EQUAL(werr,
1576 WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
1577 code = KRB5KDC_ERR_POLICY;
1579 goto done;
1583 * The RODC PAC data isn't trusted for authorization as it may
1584 * be stale. The only thing meaningful we can do with an RODC
1585 * account on a full DC is exchange the RODC TGT for a 'real'
1586 * TGT.
1588 * So we match Windows (at least server 2022) and
1589 * don't allow S4U2Self.
1591 * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
1593 if (flags & SAMBA_KDC_FLAG_PROTOCOL_TRANSITION) {
1594 code = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
1595 goto done;
1597 } else {
1598 pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
1599 if (pac_blob == NULL) {
1600 code = ENOMEM;
1601 goto done;
1604 nt_status = samba_kdc_update_pac_blob(mem_ctx,
1605 context,
1606 samdb,
1607 old_pac,
1608 pac_blob,
1609 NULL,
1610 NULL);
1611 if (!NT_STATUS_IS_OK(nt_status)) {
1612 DBG_ERR("samba_kdc_update_pac_blob failed: %s\n",
1613 nt_errstr(nt_status));
1614 code = EINVAL;
1615 goto done;
1619 /* Check the types of the given PAC */
1620 code = krb5_pac_get_types(context, old_pac, &num_types, &types);
1621 if (code != 0) {
1622 DBG_ERR("krb5_pac_get_types failed\n");
1623 goto done;
1626 for (i = 0; i < num_types; i++) {
1627 switch (types[i]) {
1628 case PAC_TYPE_LOGON_INFO:
1629 if (logon_info_idx != -1) {
1630 DBG_WARNING("logon info type[%u] twice [%zd] "
1631 "and [%zu]: \n",
1632 types[i],
1633 logon_info_idx,
1635 code = EINVAL;
1636 goto done;
1638 logon_info_idx = i;
1639 break;
1640 case PAC_TYPE_CONSTRAINED_DELEGATION:
1641 if (delegation_idx != -1) {
1642 DBG_WARNING("constrained delegation type[%u] "
1643 "twice [%zd] and [%zu]: \n",
1644 types[i],
1645 delegation_idx,
1647 code = EINVAL;
1648 goto done;
1650 delegation_idx = i;
1651 break;
1652 case PAC_TYPE_LOGON_NAME:
1653 if (logon_name_idx != -1) {
1654 DBG_WARNING("logon name type[%u] twice [%zd] "
1655 "and [%zu]: \n",
1656 types[i],
1657 logon_name_idx,
1659 code = EINVAL;
1660 goto done;
1662 logon_name_idx = i;
1663 break;
1664 case PAC_TYPE_UPN_DNS_INFO:
1665 if (upn_dns_info_idx != -1) {
1666 DBG_WARNING("upn dns info type[%u] twice [%zd] "
1667 "and [%zu]: \n",
1668 types[i],
1669 upn_dns_info_idx,
1671 code = EINVAL;
1672 goto done;
1674 upn_dns_info_idx = i;
1675 break;
1676 case PAC_TYPE_SRV_CHECKSUM:
1677 if (srv_checksum_idx != -1) {
1678 DBG_WARNING("srv checksum type[%u] twice [%zd] "
1679 "and [%zu]: \n",
1680 types[i],
1681 srv_checksum_idx,
1683 code = EINVAL;
1684 goto done;
1686 srv_checksum_idx = i;
1687 break;
1688 case PAC_TYPE_KDC_CHECKSUM:
1689 if (kdc_checksum_idx != -1) {
1690 DBG_WARNING("kdc checksum type[%u] twice [%zd] "
1691 "and [%zu]: \n",
1692 types[i],
1693 kdc_checksum_idx,
1695 code = EINVAL;
1696 goto done;
1698 kdc_checksum_idx = i;
1699 break;
1700 case PAC_TYPE_TICKET_CHECKSUM:
1701 if (tkt_checksum_idx != -1) {
1702 DBG_WARNING("ticket checksum type[%u] twice "
1703 "[%zd] and [%zu]: \n",
1704 types[i],
1705 tkt_checksum_idx,
1707 code = EINVAL;
1708 goto done;
1710 tkt_checksum_idx = i;
1711 break;
1712 case PAC_TYPE_ATTRIBUTES_INFO:
1713 if (attrs_info_idx != -1) {
1714 DBG_WARNING("attributes info type[%u] twice "
1715 "[%zd] and [%zu]: \n",
1716 types[i],
1717 attrs_info_idx,
1719 code = EINVAL;
1720 goto done;
1722 attrs_info_idx = i;
1723 break;
1724 case PAC_TYPE_REQUESTER_SID:
1725 if (requester_sid_idx != -1) {
1726 DBG_WARNING("requester sid type[%u] twice"
1727 "[%zd] and [%zu]: \n",
1728 types[i],
1729 requester_sid_idx,
1731 code = EINVAL;
1732 goto done;
1734 requester_sid_idx = i;
1735 break;
1736 default:
1737 continue;
1741 if (logon_info_idx == -1) {
1742 DBG_WARNING("PAC_TYPE_LOGON_INFO missing\n");
1743 code = EINVAL;
1744 goto done;
1746 if (logon_name_idx == -1) {
1747 DBG_WARNING("PAC_TYPE_LOGON_NAME missing\n");
1748 code = EINVAL;
1749 goto done;
1751 if (srv_checksum_idx == -1) {
1752 DBG_WARNING("PAC_TYPE_SRV_CHECKSUM missing\n");
1753 code = EINVAL;
1754 goto done;
1756 if (kdc_checksum_idx == -1) {
1757 DBG_WARNING("PAC_TYPE_KDC_CHECKSUM missing\n");
1758 code = EINVAL;
1759 goto done;
1761 if (!(flags & SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION) &&
1762 requester_sid_idx == -1) {
1763 DBG_WARNING("PAC_TYPE_REQUESTER_SID missing\n");
1764 code = KRB5KDC_ERR_TGT_REVOKED;
1765 goto done;
1769 * The server account may be set not to want the PAC.
1771 * While this is wasteful if the above cacluations were done
1772 * and now thrown away, this is cleaner as we do any ticket
1773 * signature checking etc always.
1775 * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
1776 * time (eg not accepting a ticket from the RODC) we do not
1777 * need to re-generate anything anyway.
1779 if (!samba_princ_needs_pac(server)) {
1780 code = ENODATA;
1781 goto done;
1784 is_tgs = smb_krb5_principal_is_tgs(context, server_principal);
1785 if (is_tgs == -1) {
1786 code = ENOMEM;
1787 goto done;
1790 if (!is_untrusted && !is_tgs) {
1792 * The client may have requested no PAC when obtaining the
1793 * TGT.
1795 bool requested_pac = false;
1797 code = samba_client_requested_pac(context,
1798 &old_pac,
1799 mem_ctx,
1800 &requested_pac);
1801 if (code != 0 || !requested_pac) {
1802 if (!requested_pac) {
1803 code = ENODATA;
1805 goto done;
1809 #define MAX_PAC_BUFFERS 128 /* Avoid infinite loops */
1811 for (i = 0; i < MAX_PAC_BUFFERS;) {
1812 const uint8_t zero_byte = 0;
1813 krb5_data type_data;
1814 DATA_BLOB type_blob = data_blob_null;
1815 uint32_t type;
1817 if (forced_next_type != 0) {
1819 * We need to inject possible missing types
1821 type = forced_next_type;
1822 forced_next_type = 0;
1823 } else if (i < num_types) {
1824 type = types[i];
1825 i++;
1826 } else {
1827 break;
1830 switch (type) {
1831 case PAC_TYPE_LOGON_INFO:
1832 type_blob = *pac_blob;
1834 if (delegation_idx == -1 && deleg_blob != NULL) {
1835 /* inject CONSTRAINED_DELEGATION behind */
1836 forced_next_type =
1837 PAC_TYPE_CONSTRAINED_DELEGATION;
1839 break;
1840 case PAC_TYPE_CONSTRAINED_DELEGATION:
1842 * This is generated in the main KDC code
1844 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1845 continue;
1848 if (deleg_blob != NULL) {
1849 type_blob = *deleg_blob;
1851 break;
1852 case PAC_TYPE_CREDENTIAL_INFO:
1854 * Note that we copy the credential blob,
1855 * as it's only usable with the PKINIT based
1856 * AS-REP reply key, it's only available on the
1857 * host which did the AS-REQ/AS-REP exchange.
1859 * This matches Windows 2008R2...
1861 break;
1862 case PAC_TYPE_LOGON_NAME:
1864 * This is generated in the main KDC code
1866 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1867 continue;
1870 type_blob = data_blob_const(&zero_byte, 1);
1872 if (upn_dns_info_idx == -1 && upn_blob != NULL) {
1873 /* inject UPN_DNS_INFO behind */
1874 forced_next_type = PAC_TYPE_UPN_DNS_INFO;
1876 break;
1877 case PAC_TYPE_UPN_DNS_INFO:
1879 * Replace in the RODC case, otherwise
1880 * upn_blob is NULL and we just copy.
1882 if (upn_blob != NULL) {
1883 type_blob = *upn_blob;
1885 break;
1886 case PAC_TYPE_SRV_CHECKSUM:
1888 * This is generated in the main KDC code
1890 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1891 continue;
1894 type_blob = data_blob_const(&zero_byte, 1);
1896 if (requester_sid_idx == -1 && requester_sid_blob != NULL) {
1897 /* inject REQUESTER_SID behind */
1898 forced_next_type = PAC_TYPE_REQUESTER_SID;
1900 break;
1901 case PAC_TYPE_KDC_CHECKSUM:
1903 * This is generated in the main KDC code
1905 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1906 continue;
1909 type_blob = data_blob_const(&zero_byte, 1);
1911 break;
1912 case PAC_TYPE_TICKET_CHECKSUM:
1914 * This is generated in the main KDC code
1916 if (flags & SAMBA_KDC_FLAG_SKIP_PAC_BUFFER) {
1917 continue;
1920 type_blob = data_blob_const(&zero_byte, 1);
1922 break;
1923 case PAC_TYPE_ATTRIBUTES_INFO:
1924 if (!is_untrusted && is_tgs) {
1925 /* just copy... */
1926 break;
1929 continue;
1930 case PAC_TYPE_REQUESTER_SID:
1931 if (!is_tgs) {
1932 continue;
1936 * Replace in the RODC case, otherwise
1937 * requester_sid_blob is NULL and we just copy.
1939 if (requester_sid_blob != NULL) {
1940 type_blob = *requester_sid_blob;
1942 break;
1943 default:
1944 /* just copy... */
1945 break;
1948 if (type_blob.length != 0) {
1949 code = smb_krb5_copy_data_contents(&type_data,
1950 type_blob.data,
1951 type_blob.length);
1952 if (code != 0) {
1953 goto done;
1955 } else {
1956 code = krb5_pac_get_buffer(context,
1957 old_pac,
1958 type,
1959 &type_data);
1960 if (code != 0) {
1961 goto done;
1965 code = krb5_pac_add_buffer(context,
1966 new_pac,
1967 type,
1968 &type_data);
1969 smb_krb5_free_data_contents(context, &type_data);
1970 if (code != 0) {
1971 goto done;
1975 code = 0;
1976 done:
1977 TALLOC_FREE(pac_blob);
1978 TALLOC_FREE(upn_blob);
1979 TALLOC_FREE(deleg_blob);
1980 SAFE_FREE(types);
1981 return code;