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/replace/system/filesys.h"
27 #include "lib/util/debug.h"
28 #include "lib/util/samba_util.h"
29 #include "lib/util/talloc_stack.h"
31 #include "auth/auth_sam_reply.h"
32 #include "auth/kerberos/kerberos.h"
33 #include "auth/kerberos/pac_utils.h"
34 #include "libcli/security/security.h"
35 #include "libds/common/flags.h"
36 #include "librpc/gen_ndr/ndr_krb5pac.h"
37 #include "param/param.h"
38 #include "source4/auth/auth.h"
39 #include "source4/dsdb/common/util.h"
40 #include "source4/dsdb/samdb/samdb.h"
41 #include "source4/kdc/samba_kdc.h"
42 #include "source4/kdc/pac-glue.h"
47 #define DBGC_CLASS DBGC_KERBEROS
50 NTSTATUS
samba_get_logon_info_pac_blob(TALLOC_CTX
*mem_ctx
,
51 const struct auth_user_info_dc
*info
,
52 const struct PAC_DOMAIN_GROUP_MEMBERSHIP
*override_resource_groups
,
53 const enum auth_group_inclusion group_inclusion
,
55 DATA_BLOB
*requester_sid_blob
)
57 struct netr_SamInfo3
*info3
= NULL
;
58 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*_resource_groups
= NULL
;
59 struct PAC_DOMAIN_GROUP_MEMBERSHIP
**resource_groups
= NULL
;
60 union PAC_INFO pac_info
;
61 enum ndr_err_code ndr_err
;
64 ZERO_STRUCT(pac_info
);
66 *pac_data
= data_blob_null
;
67 if (requester_sid_blob
!= NULL
) {
68 *requester_sid_blob
= data_blob_null
;
71 if (override_resource_groups
== NULL
) {
72 resource_groups
= &_resource_groups
;
73 } else if (group_inclusion
!= AUTH_EXCLUDE_RESOURCE_GROUPS
) {
75 * It doesn't make sense to override resource groups if we claim
76 * to want resource groups from user_info_dc.
78 DBG_ERR("supplied resource groups with invalid group inclusion parameter: %u\n",
80 return NT_STATUS_INVALID_PARAMETER
;
83 nt_status
= auth_convert_user_info_dc_saminfo3(mem_ctx
, info
,
87 if (!NT_STATUS_IS_OK(nt_status
)) {
88 DEBUG(1, ("Getting Samba info failed: %s\n",
89 nt_errstr(nt_status
)));
93 pac_info
.logon_info
.info
= talloc_zero(mem_ctx
, struct PAC_LOGON_INFO
);
94 if (!pac_info
.logon_info
.info
) {
95 return NT_STATUS_NO_MEMORY
;
98 pac_info
.logon_info
.info
->info3
= *info3
;
99 if (_resource_groups
!= NULL
) {
100 pac_info
.logon_info
.info
->resource_groups
= *_resource_groups
;
103 if (override_resource_groups
!= NULL
) {
104 pac_info
.logon_info
.info
->resource_groups
= *override_resource_groups
;
107 if (group_inclusion
!= AUTH_EXCLUDE_RESOURCE_GROUPS
) {
109 * Set the resource groups flag based on whether any groups are
110 * present. Otherwise, the flag is propagated from the
113 if (pac_info
.logon_info
.info
->resource_groups
.groups
.count
> 0) {
114 pac_info
.logon_info
.info
->info3
.base
.user_flags
|= NETLOGON_RESOURCE_GROUPS
;
116 pac_info
.logon_info
.info
->info3
.base
.user_flags
&= ~NETLOGON_RESOURCE_GROUPS
;
120 ndr_err
= ndr_push_union_blob(pac_data
, mem_ctx
, &pac_info
,
122 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
123 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
124 nt_status
= ndr_map_error2ntstatus(ndr_err
);
125 DEBUG(1, ("PAC_LOGON_INFO (presig) push failed: %s\n",
126 nt_errstr(nt_status
)));
130 if (requester_sid_blob
!= NULL
&& info
->num_sids
> 0) {
131 union PAC_INFO pac_requester_sid
;
133 ZERO_STRUCT(pac_requester_sid
);
135 pac_requester_sid
.requester_sid
.sid
= info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
137 ndr_err
= ndr_push_union_blob(requester_sid_blob
, mem_ctx
,
139 PAC_TYPE_REQUESTER_SID
,
140 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
141 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
142 nt_status
= ndr_map_error2ntstatus(ndr_err
);
143 DEBUG(1, ("PAC_REQUESTER_SID (presig) push failed: %s\n",
144 nt_errstr(nt_status
)));
153 NTSTATUS
samba_get_upn_info_pac_blob(TALLOC_CTX
*mem_ctx
,
154 const struct auth_user_info_dc
*info
,
157 union PAC_INFO pac_upn
;
158 enum ndr_err_code ndr_err
;
162 ZERO_STRUCT(pac_upn
);
164 *upn_data
= data_blob_null
;
166 pac_upn
.upn_dns_info
.upn_name
= info
->info
->user_principal_name
;
167 pac_upn
.upn_dns_info
.dns_domain_name
= strupper_talloc(mem_ctx
,
168 info
->info
->dns_domain_name
);
169 if (pac_upn
.upn_dns_info
.dns_domain_name
== NULL
) {
170 return NT_STATUS_NO_MEMORY
;
172 if (info
->info
->user_principal_constructed
) {
173 pac_upn
.upn_dns_info
.flags
|= PAC_UPN_DNS_FLAG_CONSTRUCTED
;
176 pac_upn
.upn_dns_info
.flags
|= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID
;
178 pac_upn
.upn_dns_info
.ex
.sam_name_and_sid
.samaccountname
179 = info
->info
->account_name
;
181 pac_upn
.upn_dns_info
.ex
.sam_name_and_sid
.objectsid
182 = &info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
184 ndr_err
= ndr_push_union_blob(upn_data
, mem_ctx
, &pac_upn
,
185 PAC_TYPE_UPN_DNS_INFO
,
186 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
187 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
188 nt_status
= ndr_map_error2ntstatus(ndr_err
);
189 DEBUG(1, ("PAC UPN_DNS_INFO (presig) push failed: %s\n",
190 nt_errstr(nt_status
)));
194 ok
= data_blob_pad(mem_ctx
, upn_data
, 8);
196 return NT_STATUS_NO_MEMORY
;
203 NTSTATUS
samba_get_pac_attrs_blob(TALLOC_CTX
*mem_ctx
,
204 uint64_t pac_attributes
,
205 DATA_BLOB
*pac_attrs_data
)
207 union PAC_INFO pac_attrs
;
208 enum ndr_err_code ndr_err
;
211 ZERO_STRUCT(pac_attrs
);
213 *pac_attrs_data
= data_blob_null
;
215 /* Set the length of the flags in bits. */
216 pac_attrs
.attributes_info
.flags_length
= 2;
217 pac_attrs
.attributes_info
.flags
= pac_attributes
;
219 ndr_err
= ndr_push_union_blob(pac_attrs_data
, mem_ctx
, &pac_attrs
,
220 PAC_TYPE_ATTRIBUTES_INFO
,
221 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
222 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
223 nt_status
= ndr_map_error2ntstatus(ndr_err
);
224 DEBUG(1, ("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
225 nt_errstr(nt_status
)));
233 NTSTATUS
samba_get_cred_info_ndr_blob(TALLOC_CTX
*mem_ctx
,
234 const struct ldb_message
*msg
,
235 DATA_BLOB
*cred_blob
)
237 enum ndr_err_code ndr_err
;
239 struct samr_Password
*lm_hash
= NULL
;
240 struct samr_Password
*nt_hash
= NULL
;
241 struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg
= {
244 DATA_BLOB ntlm_blob
= data_blob_null
;
245 struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs
[1] = {{
246 .credential_size
= 0,
248 struct PAC_CREDENTIAL_DATA cred_data
= {
249 .credential_count
= 0,
251 struct PAC_CREDENTIAL_DATA_NDR cred_ndr
;
253 ZERO_STRUCT(cred_ndr
);
255 *cred_blob
= data_blob_null
;
257 lm_hash
= samdb_result_hash(mem_ctx
, msg
, "dBCSPwd");
258 if (lm_hash
!= NULL
) {
259 bool zero
= all_zero(lm_hash
->hash
, 16);
264 if (lm_hash
!= NULL
) {
265 DEBUG(5, ("Passing LM password hash through credentials set\n"));
266 ntlm_secpkg
.flags
|= PAC_CREDENTIAL_NTLM_HAS_LM_HASH
;
267 ntlm_secpkg
.lm_password
= *lm_hash
;
268 ZERO_STRUCTP(lm_hash
);
269 TALLOC_FREE(lm_hash
);
272 nt_hash
= samdb_result_hash(mem_ctx
, msg
, "unicodePwd");
273 if (nt_hash
!= NULL
) {
274 bool zero
= all_zero(nt_hash
->hash
, 16);
279 if (nt_hash
!= NULL
) {
280 DEBUG(5, ("Passing LM password hash through credentials set\n"));
281 ntlm_secpkg
.flags
|= PAC_CREDENTIAL_NTLM_HAS_NT_HASH
;
282 ntlm_secpkg
.nt_password
= *nt_hash
;
283 ZERO_STRUCTP(nt_hash
);
284 TALLOC_FREE(nt_hash
);
287 if (ntlm_secpkg
.flags
== 0) {
291 #ifdef DEBUG_PASSWORD
293 NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG
, &ntlm_secpkg
);
297 ndr_err
= ndr_push_struct_blob(&ntlm_blob
, mem_ctx
, &ntlm_secpkg
,
298 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG
);
299 ZERO_STRUCT(ntlm_secpkg
);
300 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
301 nt_status
= ndr_map_error2ntstatus(ndr_err
);
302 DEBUG(1, ("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
303 nt_errstr(nt_status
)));
307 DEBUG(10, ("NTLM credential BLOB (len %zu) for user\n",
309 dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
310 ntlm_blob
.data
, ntlm_blob
.length
);
312 secpkgs
[0].package_name
.string
= discard_const_p(char, "NTLM");
313 secpkgs
[0].credential_size
= ntlm_blob
.length
;
314 secpkgs
[0].credential
= ntlm_blob
.data
;
316 cred_data
.credential_count
= ARRAY_SIZE(secpkgs
);
317 cred_data
.credentials
= secpkgs
;
319 #ifdef DEBUG_PASSWORD
321 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA
, &cred_data
);
325 cred_ndr
.ctr
.data
= &cred_data
;
327 #ifdef DEBUG_PASSWORD
329 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR
, &cred_ndr
);
333 ndr_err
= ndr_push_struct_blob(cred_blob
, mem_ctx
, &cred_ndr
,
334 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_DATA_NDR
);
335 data_blob_clear(&ntlm_blob
);
336 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
337 nt_status
= ndr_map_error2ntstatus(ndr_err
);
338 DEBUG(1, ("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
339 nt_errstr(nt_status
)));
343 DEBUG(10, ("Created credential BLOB (len %zu) for user\n",
345 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
346 cred_blob
->data
, cred_blob
->length
);
351 #ifdef SAMBA4_USES_HEIMDAL
352 krb5_error_code
samba_kdc_encrypt_pac_credentials(krb5_context context
,
353 const krb5_keyblock
*pkreplykey
,
354 const DATA_BLOB
*cred_ndr_blob
,
356 DATA_BLOB
*cred_info_blob
)
358 krb5_crypto cred_crypto
;
359 krb5_enctype cred_enctype
;
360 krb5_data cred_ndr_crypt
;
361 struct PAC_CREDENTIAL_INFO pac_cred_info
= { .version
= 0, };
364 enum ndr_err_code ndr_err
;
367 *cred_info_blob
= data_blob_null
;
369 ret
= krb5_crypto_init(context
, pkreplykey
, ETYPE_NULL
,
372 krb5err
= krb5_get_error_message(context
, ret
);
373 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err
));
374 krb5_free_error_message(context
, krb5err
);
378 ret
= krb5_crypto_getenctype(context
, cred_crypto
, &cred_enctype
);
380 DEBUG(1, ("Failed getting crypto type for key\n"));
381 krb5_crypto_destroy(context
, cred_crypto
);
385 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
386 cred_ndr_blob
->length
));
387 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
388 cred_ndr_blob
->data
, cred_ndr_blob
->length
);
390 ret
= krb5_encrypt(context
, cred_crypto
,
391 KRB5_KU_OTHER_ENCRYPTED
,
392 cred_ndr_blob
->data
, cred_ndr_blob
->length
,
394 krb5_crypto_destroy(context
, cred_crypto
);
396 krb5err
= krb5_get_error_message(context
, ret
);
397 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err
));
398 krb5_free_error_message(context
, krb5err
);
402 pac_cred_info
.encryption_type
= cred_enctype
;
403 pac_cred_info
.encrypted_data
.length
= cred_ndr_crypt
.length
;
404 pac_cred_info
.encrypted_data
.data
= (uint8_t *)cred_ndr_crypt
.data
;
407 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO
, &pac_cred_info
);
410 ndr_err
= ndr_push_struct_blob(cred_info_blob
, mem_ctx
, &pac_cred_info
,
411 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_INFO
);
412 krb5_data_free(&cred_ndr_crypt
);
413 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
414 nt_status
= ndr_map_error2ntstatus(ndr_err
);
415 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
416 nt_errstr(nt_status
)));
417 return KRB5KDC_ERR_SVC_UNAVAILABLE
;
420 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
421 cred_info_blob
->length
, (int)pac_cred_info
.encryption_type
));
422 dump_data_pw("PAC_CREDENTIAL_INFO",
423 cred_info_blob
->data
, cred_info_blob
->length
);
427 #else /* SAMBA4_USES_HEIMDAL */
428 krb5_error_code
samba_kdc_encrypt_pac_credentials(krb5_context context
,
429 const krb5_keyblock
*pkreplykey
,
430 const DATA_BLOB
*cred_ndr_blob
,
432 DATA_BLOB
*cred_info_blob
)
435 krb5_enctype cred_enctype
;
436 struct PAC_CREDENTIAL_INFO pac_cred_info
= { .version
= 0, };
437 krb5_error_code code
;
439 enum ndr_err_code ndr_err
;
441 krb5_data cred_ndr_data
;
442 krb5_enc_data cred_ndr_crypt
;
445 *cred_info_blob
= data_blob_null
;
447 code
= krb5_k_create_key(context
,
451 krb5err
= krb5_get_error_message(context
, code
);
452 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err
));
453 krb5_free_error_message(context
, krb5err
);
457 cred_enctype
= krb5_k_key_enctype(context
, cred_key
);
459 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
460 cred_ndr_blob
->length
));
461 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
462 cred_ndr_blob
->data
, cred_ndr_blob
->length
);
464 pac_cred_info
.encryption_type
= cred_enctype
;
466 cred_ndr_data
.magic
= 0;
467 cred_ndr_data
.data
= (char *)cred_ndr_blob
->data
;
468 cred_ndr_data
.length
= cred_ndr_blob
->length
;
470 code
= krb5_c_encrypt_length(context
,
472 cred_ndr_data
.length
,
475 krb5err
= krb5_get_error_message(context
, code
);
476 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err
));
477 krb5_free_error_message(context
, krb5err
);
481 pac_cred_info
.encrypted_data
= data_blob_talloc_zero(mem_ctx
, enc_len
);
482 if (pac_cred_info
.encrypted_data
.data
== NULL
) {
483 DBG_ERR("Out of memory\n");
487 cred_ndr_crypt
.ciphertext
.length
= enc_len
;
488 cred_ndr_crypt
.ciphertext
.data
= (char *)pac_cred_info
.encrypted_data
.data
;
490 code
= krb5_k_encrypt(context
,
492 KRB5_KU_OTHER_ENCRYPTED
,
496 krb5_k_free_key(context
, cred_key
);
498 krb5err
= krb5_get_error_message(context
, code
);
499 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err
));
500 krb5_free_error_message(context
, krb5err
);
505 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO
, &pac_cred_info
);
508 ndr_err
= ndr_push_struct_blob(cred_info_blob
, mem_ctx
, &pac_cred_info
,
509 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_INFO
);
510 TALLOC_FREE(pac_cred_info
.encrypted_data
.data
);
511 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
512 nt_status
= ndr_map_error2ntstatus(ndr_err
);
513 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
514 nt_errstr(nt_status
)));
515 return KRB5KDC_ERR_SVC_UNAVAILABLE
;
518 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
519 cred_info_blob
->length
, (int)pac_cred_info
.encryption_type
));
520 dump_data_pw("PAC_CREDENTIAL_INFO",
521 cred_info_blob
->data
, cred_info_blob
->length
);
525 #endif /* SAMBA4_USES_HEIMDAL */
529 * @brief Create a PAC with the given blobs (logon, credentials, upn and
532 * @param[in] context The KRB5 context to use.
534 * @param[in] logon_blob Fill the logon info PAC buffer with the given blob,
535 * use NULL to ignore it.
537 * @param[in] cred_blob Fill the credentials info PAC buffer with the given
538 * blob, use NULL to ignore it.
540 * @param[in] upn_blob Fill the UPN info PAC buffer with the given blob, use
543 * @param[in] deleg_blob Fill the delegation info PAC buffer with the given
544 * blob, use NULL to ignore it.
546 * @param[in] client_claims_blob Fill the client claims info PAC buffer with the
547 * given blob, use NULL to ignore it.
549 * @param[in] device_info_blob Fill the device info PAC buffer with the given
550 * blob, use NULL to ignore it.
552 * @param[in] device_claims_blob Fill the device claims info PAC buffer with the given
553 * blob, use NULL to ignore it.
555 * @param[in] pac The pac buffer to fill. This should be allocated with
556 * krb5_pac_init() already.
558 * @returns 0 on success or a corresponding KRB5 error.
560 krb5_error_code
samba_make_krb5_pac(krb5_context context
,
561 const DATA_BLOB
*logon_blob
,
562 const DATA_BLOB
*cred_blob
,
563 const DATA_BLOB
*upn_blob
,
564 const DATA_BLOB
*pac_attrs_blob
,
565 const DATA_BLOB
*requester_sid_blob
,
566 const DATA_BLOB
*deleg_blob
,
567 const DATA_BLOB
*client_claims_blob
,
568 const DATA_BLOB
*device_info_blob
,
569 const DATA_BLOB
*device_claims_blob
,
572 krb5_data logon_data
;
574 #ifdef SAMBA4_USES_HEIMDAL
575 char null_byte
= '\0';
576 krb5_data null_data
= smb_krb5_make_data(&null_byte
, 0);
579 /* The user account may be set not to want the PAC */
580 if (logon_blob
== NULL
) {
584 logon_data
= smb_krb5_data_from_blob(*logon_blob
);
585 ret
= krb5_pac_add_buffer(context
, pac
, PAC_TYPE_LOGON_INFO
, &logon_data
);
590 if (device_info_blob
!= NULL
) {
591 krb5_data device_info_data
= smb_krb5_data_from_blob(*device_info_blob
);
592 ret
= krb5_pac_add_buffer(context
, pac
,
593 PAC_TYPE_DEVICE_INFO
,
600 if (client_claims_blob
!= NULL
) {
601 krb5_data client_claims_data
= smb_krb5_data_from_blob(*client_claims_blob
);
602 ret
= krb5_pac_add_buffer(context
, pac
,
603 PAC_TYPE_CLIENT_CLAIMS_INFO
,
604 &client_claims_data
);
610 if (device_claims_blob
!= NULL
) {
611 krb5_data device_claims_data
= smb_krb5_data_from_blob(*device_claims_blob
);
612 ret
= krb5_pac_add_buffer(context
, pac
,
613 PAC_TYPE_DEVICE_CLAIMS_INFO
,
614 &device_claims_data
);
620 if (cred_blob
!= NULL
) {
621 krb5_data cred_data
= smb_krb5_data_from_blob(*cred_blob
);
622 ret
= krb5_pac_add_buffer(context
, pac
,
623 PAC_TYPE_CREDENTIAL_INFO
,
630 #ifdef SAMBA4_USES_HEIMDAL
632 * null_data will be filled by the generic KDC code in the caller
633 * here we just add it in order to have it before
634 * PAC_TYPE_UPN_DNS_INFO
636 * Not needed with MIT Kerberos - asn
638 ret
= krb5_pac_add_buffer(context
, pac
,
646 if (upn_blob
!= NULL
) {
647 krb5_data upn_data
= smb_krb5_data_from_blob(*upn_blob
);
648 ret
= krb5_pac_add_buffer(context
, pac
,
649 PAC_TYPE_UPN_DNS_INFO
,
656 if (pac_attrs_blob
!= NULL
) {
657 krb5_data pac_attrs_data
= smb_krb5_data_from_blob(*pac_attrs_blob
);
658 ret
= krb5_pac_add_buffer(context
, pac
,
659 PAC_TYPE_ATTRIBUTES_INFO
,
666 if (requester_sid_blob
!= NULL
) {
667 krb5_data requester_sid_data
= smb_krb5_data_from_blob(*requester_sid_blob
);
668 ret
= krb5_pac_add_buffer(context
, pac
,
669 PAC_TYPE_REQUESTER_SID
,
670 &requester_sid_data
);
676 if (deleg_blob
!= NULL
) {
677 krb5_data deleg_data
= smb_krb5_data_from_blob(*deleg_blob
);
678 ret
= krb5_pac_add_buffer(context
, pac
,
679 PAC_TYPE_CONSTRAINED_DELEGATION
,
689 bool samba_princ_needs_pac(const struct samba_kdc_entry
*skdc_entry
)
692 uint32_t userAccountControl
;
694 /* The service account may be set not to want the PAC */
695 userAccountControl
= ldb_msg_find_attr_as_uint(skdc_entry
->msg
, "userAccountControl", 0);
696 if (userAccountControl
& UF_NO_AUTH_DATA_REQUIRED
) {
703 int samba_client_requested_pac(krb5_context context
,
704 const krb5_const_pac pac
,
708 enum ndr_err_code ndr_err
;
709 krb5_data k5pac_attrs_in
;
710 DATA_BLOB pac_attrs_in
;
711 union PAC_INFO pac_attrs
;
714 *requested_pac
= true;
716 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_ATTRIBUTES_INFO
,
719 return ret
== ENOENT
? 0 : ret
;
722 pac_attrs_in
= data_blob_const(k5pac_attrs_in
.data
,
723 k5pac_attrs_in
.length
);
725 ndr_err
= ndr_pull_union_blob(&pac_attrs_in
, mem_ctx
, &pac_attrs
,
726 PAC_TYPE_ATTRIBUTES_INFO
,
727 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
728 smb_krb5_free_data_contents(context
, &k5pac_attrs_in
);
729 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
730 NTSTATUS nt_status
= ndr_map_error2ntstatus(ndr_err
);
731 DEBUG(0,("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status
)));
735 if (pac_attrs
.attributes_info
.flags
& (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
736 | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED
)) {
737 *requested_pac
= true;
739 *requested_pac
= false;
745 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
746 int samba_krbtgt_is_in_db(struct samba_kdc_entry
*p
,
751 int rodc_krbtgt_number
, trust_direction
;
754 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
759 trust_direction
= ldb_msg_find_attr_as_int(p
->msg
, "trustDirection", 0);
761 if (trust_direction
!= 0) {
762 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
764 This is exactly where we should flag for SID
765 validation when we do inter-foreest trusts
767 talloc_free(mem_ctx
);
773 /* The lack of password controls etc applies to krbtgt by
774 * virtue of being that particular RID */
775 status
= dom_sid_split_rid(NULL
, samdb_result_dom_sid(mem_ctx
, p
->msg
, "objectSid"), NULL
, &rid
);
777 if (!NT_STATUS_IS_OK(status
)) {
778 talloc_free(mem_ctx
);
782 rodc_krbtgt_number
= ldb_msg_find_attr_as_int(p
->msg
, "msDS-SecondaryKrbTgtNumber", -1);
784 if (p
->kdc_db_ctx
->my_krbtgt_number
== 0) {
785 if (rid
== DOMAIN_RID_KRBTGT
) {
788 talloc_free(mem_ctx
);
790 } else if (rodc_krbtgt_number
!= -1) {
793 talloc_free(mem_ctx
);
796 } else if ((rid
!= DOMAIN_RID_KRBTGT
) && (rodc_krbtgt_number
== p
->kdc_db_ctx
->my_krbtgt_number
)) {
797 talloc_free(mem_ctx
);
801 } else if (rid
== DOMAIN_RID_KRBTGT
) {
802 /* krbtgt viewed from an RODC */
803 talloc_free(mem_ctx
);
810 talloc_free(mem_ctx
);
817 * Because the KDC does not limit protocol transition, two new well-known SIDs
818 * were introduced to give this control to the resource administrator. These
819 * SIDs identify whether protocol transition has occurred, and can be used with
820 * standard access control lists to grant or limit access as needed.
822 * https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview
824 static NTSTATUS
samba_add_asserted_identity(TALLOC_CTX
*mem_ctx
,
825 enum samba_asserted_identity ai
,
826 struct auth_user_info_dc
*user_info_dc
)
828 struct dom_sid ai_sid
;
829 const char *sid_str
= NULL
;
832 case SAMBA_ASSERTED_IDENTITY_SERVICE
:
833 sid_str
= SID_SERVICE_ASSERTED_IDENTITY
;
835 case SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
:
836 sid_str
= SID_AUTHENTICATION_AUTHORITY_ASSERTED_IDENTITY
;
838 case SAMBA_ASSERTED_IDENTITY_IGNORE
:
842 dom_sid_parse(sid_str
, &ai_sid
);
844 return add_sid_to_array_attrs_unique(
847 SE_GROUP_DEFAULT_FLAGS
,
849 &user_info_dc
->num_sids
);
853 * Look up the user's info in the database and create a auth_user_info_dc
854 * structure. If the resulting structure is not talloc_free()d, it will be
855 * reused on future calls to this function.
857 NTSTATUS
samba_kdc_get_user_info_from_db(struct samba_kdc_entry
*skdc_entry
,
858 const struct ldb_message
*msg
,
859 struct auth_user_info_dc
**user_info_dc
)
861 if (skdc_entry
->user_info_dc
== NULL
) {
863 struct loadparm_context
*lp_ctx
= skdc_entry
->kdc_db_ctx
->lp_ctx
;
865 nt_status
= authsam_make_user_info_dc(skdc_entry
,
866 skdc_entry
->kdc_db_ctx
->samdb
,
867 lpcfg_netbios_name(lp_ctx
),
868 lpcfg_sam_name(lp_ctx
),
869 lpcfg_sam_dnsname(lp_ctx
),
870 skdc_entry
->realm_dn
,
874 &skdc_entry
->user_info_dc
);
875 if (!NT_STATUS_IS_OK(nt_status
)) {
880 *user_info_dc
= skdc_entry
->user_info_dc
;
884 NTSTATUS
samba_kdc_get_pac_blobs(TALLOC_CTX
*mem_ctx
,
885 struct samba_kdc_entry
*p
,
886 enum samba_asserted_identity asserted_identity
,
887 const enum auth_group_inclusion group_inclusion
,
888 DATA_BLOB
**_logon_info_blob
,
889 DATA_BLOB
**_cred_ndr_blob
,
890 DATA_BLOB
**_upn_info_blob
,
891 DATA_BLOB
**_pac_attrs_blob
,
892 uint64_t pac_attributes
,
893 DATA_BLOB
**_requester_sid_blob
,
894 DATA_BLOB
**_client_claims_blob
)
896 struct auth_user_info_dc
*user_info_dc
= NULL
;
897 DATA_BLOB
*logon_blob
= NULL
;
898 DATA_BLOB
*cred_blob
= NULL
;
899 DATA_BLOB
*upn_blob
= NULL
;
900 DATA_BLOB
*pac_attrs_blob
= NULL
;
901 DATA_BLOB
*requester_sid_blob
= NULL
;
902 DATA_BLOB
*client_claims_blob
= NULL
;
905 *_logon_info_blob
= NULL
;
906 if (_cred_ndr_blob
!= NULL
) {
907 *_cred_ndr_blob
= NULL
;
909 *_upn_info_blob
= NULL
;
910 if (_pac_attrs_blob
!= NULL
) {
911 *_pac_attrs_blob
= NULL
;
913 if (_requester_sid_blob
!= NULL
) {
914 *_requester_sid_blob
= NULL
;
916 if (_client_claims_blob
!= NULL
) {
917 *_client_claims_blob
= NULL
;
920 logon_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
921 if (logon_blob
== NULL
) {
922 return NT_STATUS_NO_MEMORY
;
925 if (_cred_ndr_blob
!= NULL
) {
926 cred_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
927 if (cred_blob
== NULL
) {
928 return NT_STATUS_NO_MEMORY
;
932 upn_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
933 if (upn_blob
== NULL
) {
934 return NT_STATUS_NO_MEMORY
;
937 if (_pac_attrs_blob
!= NULL
) {
938 pac_attrs_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
939 if (pac_attrs_blob
== NULL
) {
940 return NT_STATUS_NO_MEMORY
;
944 if (_requester_sid_blob
!= NULL
) {
945 requester_sid_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
946 if (requester_sid_blob
== NULL
) {
947 return NT_STATUS_NO_MEMORY
;
951 if (_client_claims_blob
!= NULL
) {
953 * Until we support claims we just
954 * return an empty blob,
955 * that matches what Windows is doing
956 * without defined claims
958 client_claims_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
959 if (client_claims_blob
== NULL
) {
960 return NT_STATUS_NO_MEMORY
;
964 nt_status
= samba_kdc_get_user_info_from_db(p
,
967 if (!NT_STATUS_IS_OK(nt_status
)) {
968 DEBUG(0, ("Getting user info for PAC failed: %s\n",
969 nt_errstr(nt_status
)));
973 nt_status
= samba_add_asserted_identity(mem_ctx
,
976 if (!NT_STATUS_IS_OK(nt_status
)) {
977 DBG_ERR("Failed to add assertied identity!\n");
981 nt_status
= samba_get_logon_info_pac_blob(logon_blob
,
987 if (!NT_STATUS_IS_OK(nt_status
)) {
988 DEBUG(0, ("Building PAC LOGON INFO failed: %s\n",
989 nt_errstr(nt_status
)));
993 if (cred_blob
!= NULL
) {
994 nt_status
= samba_get_cred_info_ndr_blob(cred_blob
,
997 if (!NT_STATUS_IS_OK(nt_status
)) {
998 DEBUG(0, ("Building PAC CRED INFO failed: %s\n",
999 nt_errstr(nt_status
)));
1004 nt_status
= samba_get_upn_info_pac_blob(upn_blob
,
1007 if (!NT_STATUS_IS_OK(nt_status
)) {
1008 DEBUG(0, ("Building PAC UPN INFO failed: %s\n",
1009 nt_errstr(nt_status
)));
1013 if (pac_attrs_blob
!= NULL
) {
1014 nt_status
= samba_get_pac_attrs_blob(pac_attrs_blob
,
1018 if (!NT_STATUS_IS_OK(nt_status
)) {
1019 DEBUG(0, ("Building PAC ATTRIBUTES failed: %s\n",
1020 nt_errstr(nt_status
)));
1025 *_logon_info_blob
= logon_blob
;
1026 if (_cred_ndr_blob
!= NULL
) {
1027 *_cred_ndr_blob
= cred_blob
;
1029 *_upn_info_blob
= upn_blob
;
1030 if (_pac_attrs_blob
!= NULL
) {
1031 *_pac_attrs_blob
= pac_attrs_blob
;
1033 if (_requester_sid_blob
!= NULL
) {
1034 *_requester_sid_blob
= requester_sid_blob
;
1036 if (_client_claims_blob
!= NULL
) {
1037 *_client_claims_blob
= client_claims_blob
;
1039 return NT_STATUS_OK
;
1042 NTSTATUS
samba_kdc_update_pac_blob(TALLOC_CTX
*mem_ctx
,
1043 krb5_context context
,
1044 struct ldb_context
*samdb
,
1045 const enum auth_group_inclusion group_inclusion
,
1046 const krb5_pac pac
, DATA_BLOB
*pac_blob
,
1047 struct PAC_SIGNATURE_DATA
*pac_srv_sig
,
1048 struct PAC_SIGNATURE_DATA
*pac_kdc_sig
)
1050 struct auth_user_info_dc
*user_info_dc
;
1051 krb5_error_code ret
;
1053 struct PAC_DOMAIN_GROUP_MEMBERSHIP
*_resource_groups
= NULL
;
1054 struct PAC_DOMAIN_GROUP_MEMBERSHIP
**resource_groups
= NULL
;
1056 if (group_inclusion
== AUTH_EXCLUDE_RESOURCE_GROUPS
) {
1058 * Since we are creating a TGT, resource groups from our domain
1059 * are not to be put into the PAC. Instead, we take the resource
1060 * groups directly from the original PAC and copy them
1061 * unmodified into the new one.
1063 resource_groups
= &_resource_groups
;
1066 ret
= kerberos_pac_to_user_info_dc(mem_ctx
,
1070 AUTH_EXCLUDE_RESOURCE_GROUPS
,
1075 return NT_STATUS_UNSUCCESSFUL
;
1079 * We need to expand group memberships within our local domain,
1080 * as the token might be generated by a trusted domain.
1082 nt_status
= authsam_update_user_info_dc(mem_ctx
,
1085 if (!NT_STATUS_IS_OK(nt_status
)) {
1086 TALLOC_FREE(user_info_dc
);
1090 nt_status
= samba_get_logon_info_pac_blob(mem_ctx
,
1097 * The infomation from this is now in the PAC, this memory is
1098 * not used any longer and not passed to the caller
1100 TALLOC_FREE(user_info_dc
);
1105 NTSTATUS
samba_kdc_update_delegation_info_blob(TALLOC_CTX
*mem_ctx
,
1106 krb5_context context
,
1107 const krb5_const_pac pac
,
1108 const krb5_principal server_principal
,
1109 const krb5_principal proxy_principal
,
1110 DATA_BLOB
*new_blob
)
1114 krb5_error_code ret
;
1116 enum ndr_err_code ndr_err
;
1117 union PAC_INFO info
;
1118 struct PAC_CONSTRAINED_DELEGATION _d
;
1119 struct PAC_CONSTRAINED_DELEGATION
*d
= NULL
;
1120 char *server
= NULL
;
1123 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1125 if (tmp_ctx
== NULL
) {
1126 return NT_STATUS_NO_MEMORY
;
1129 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_CONSTRAINED_DELEGATION
, &old_data
);
1130 if (ret
== ENOENT
) {
1131 ZERO_STRUCT(old_data
);
1133 talloc_free(tmp_ctx
);
1134 return NT_STATUS_UNSUCCESSFUL
;
1137 old_blob
.length
= old_data
.length
;
1138 old_blob
.data
= (uint8_t *)old_data
.data
;
1141 if (old_blob
.length
> 0) {
1142 ndr_err
= ndr_pull_union_blob(&old_blob
, mem_ctx
,
1143 &info
, PAC_TYPE_CONSTRAINED_DELEGATION
,
1144 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1145 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1146 smb_krb5_free_data_contents(context
, &old_data
);
1147 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1148 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status
)));
1149 talloc_free(tmp_ctx
);
1154 info
.constrained_delegation
.info
= &_d
;
1156 smb_krb5_free_data_contents(context
, &old_data
);
1158 ret
= krb5_unparse_name_flags(context
, server_principal
,
1159 KRB5_PRINCIPAL_UNPARSE_NO_REALM
, &server
);
1161 talloc_free(tmp_ctx
);
1162 return NT_STATUS_INTERNAL_ERROR
;
1165 ret
= krb5_unparse_name(context
, proxy_principal
, &proxy
);
1168 talloc_free(tmp_ctx
);
1169 return NT_STATUS_INTERNAL_ERROR
;
1172 d
= info
.constrained_delegation
.info
;
1173 i
= d
->num_transited_services
;
1174 d
->proxy_target
.string
= server
;
1175 d
->transited_services
= talloc_realloc(mem_ctx
, d
->transited_services
,
1176 struct lsa_String
, i
+ 1);
1177 d
->transited_services
[i
].string
= proxy
;
1178 d
->num_transited_services
= i
+ 1;
1180 ndr_err
= ndr_push_union_blob(new_blob
, mem_ctx
,
1181 &info
, PAC_TYPE_CONSTRAINED_DELEGATION
,
1182 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
1185 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1186 smb_krb5_free_data_contents(context
, &old_data
);
1187 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1188 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status
)));
1189 talloc_free(tmp_ctx
);
1193 talloc_free(tmp_ctx
);
1194 return NT_STATUS_OK
;
1197 /* function to map policy errors */
1198 krb5_error_code
samba_kdc_map_policy_err(NTSTATUS nt_status
)
1200 krb5_error_code ret
;
1202 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_PASSWORD_MUST_CHANGE
))
1203 ret
= KRB5KDC_ERR_KEY_EXP
;
1204 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_PASSWORD_EXPIRED
))
1205 ret
= KRB5KDC_ERR_KEY_EXP
;
1206 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_EXPIRED
))
1207 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1208 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_DISABLED
))
1209 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1210 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_LOGON_HOURS
))
1211 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1212 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_LOCKED_OUT
))
1213 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
1214 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_WORKSTATION
))
1215 ret
= KRB5KDC_ERR_POLICY
;
1217 ret
= KRB5KDC_ERR_POLICY
;
1222 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
1223 * for consistency */
1224 NTSTATUS
samba_kdc_check_client_access(struct samba_kdc_entry
*kdc_entry
,
1225 const char *client_name
,
1226 const char *workstation
,
1227 bool password_change
)
1229 TALLOC_CTX
*tmp_ctx
;
1232 tmp_ctx
= talloc_named(NULL
, 0, "samba_kdc_check_client_access");
1234 return NT_STATUS_NO_MEMORY
;
1237 /* we allow all kinds of trusts here */
1238 nt_status
= authsam_account_ok(tmp_ctx
,
1239 kdc_entry
->kdc_db_ctx
->samdb
,
1240 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
|
1241 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
,
1242 kdc_entry
->realm_dn
, kdc_entry
->msg
,
1243 workstation
, client_name
,
1244 true, password_change
);
1246 kdc_entry
->reject_status
= nt_status
;
1247 talloc_free(tmp_ctx
);
1251 static krb5_error_code
samba_get_requester_sid(TALLOC_CTX
*mem_ctx
,
1253 krb5_context context
,
1254 struct dom_sid
*sid
)
1257 enum ndr_err_code ndr_err
;
1258 krb5_error_code ret
;
1260 DATA_BLOB pac_requester_sid_in
;
1261 krb5_data k5pac_requester_sid_in
;
1263 union PAC_INFO info
;
1265 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
1266 if (tmp_ctx
== NULL
) {
1270 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_REQUESTER_SID
,
1271 &k5pac_requester_sid_in
);
1273 talloc_free(tmp_ctx
);
1277 pac_requester_sid_in
= data_blob_const(k5pac_requester_sid_in
.data
,
1278 k5pac_requester_sid_in
.length
);
1280 ndr_err
= ndr_pull_union_blob(&pac_requester_sid_in
, tmp_ctx
, &info
,
1281 PAC_TYPE_REQUESTER_SID
,
1282 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
1283 smb_krb5_free_data_contents(context
, &k5pac_requester_sid_in
);
1284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1285 nt_status
= ndr_map_error2ntstatus(ndr_err
);
1286 DEBUG(0,("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status
)));
1287 talloc_free(tmp_ctx
);
1291 *sid
= info
.requester_sid
.sid
;
1293 talloc_free(tmp_ctx
);
1297 /* Does a parse and SID check, but no crypto. */
1298 krb5_error_code
samba_kdc_validate_pac_blob(
1299 krb5_context context
,
1300 const struct samba_kdc_entry
*client_skdc_entry
,
1301 const krb5_const_pac pac
)
1303 TALLOC_CTX
*frame
= talloc_stackframe();
1304 struct auth_user_info_dc
*pac_user_info
= NULL
;
1305 struct dom_sid
*client_sid
= NULL
;
1306 struct dom_sid pac_sid
;
1307 krb5_error_code code
;
1311 * First, try to get the SID from the requester SID buffer in the PAC.
1313 code
= samba_get_requester_sid(frame
, pac
, context
, &pac_sid
);
1315 if (code
== ENOENT
) {
1317 * If the requester SID buffer isn't present, fall back to the
1318 * SID in the LOGON_INFO PAC buffer.
1320 code
= kerberos_pac_to_user_info_dc(frame
,
1324 AUTH_EXCLUDE_RESOURCE_GROUPS
,
1332 if (pac_user_info
->num_sids
== 0) {
1337 pac_sid
= pac_user_info
->sids
[PRIMARY_USER_SID_INDEX
].sid
;
1338 } else if (code
!= 0) {
1342 client_sid
= samdb_result_dom_sid(frame
,
1343 client_skdc_entry
->msg
,
1346 ok
= dom_sid_equal(&pac_sid
, client_sid
);
1348 struct dom_sid_buf buf1
;
1349 struct dom_sid_buf buf2
;
1351 DBG_ERR("SID mismatch between PAC and looked up client: "
1352 "PAC[%s] != CLI[%s]\n",
1353 dom_sid_str_buf(&pac_sid
, &buf1
),
1354 dom_sid_str_buf(client_sid
, &buf2
));
1355 code
= KRB5KDC_ERR_TGT_REVOKED
;
1367 * In the RODC case, to confirm that the returned user is permitted to
1368 * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
1370 WERROR
samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids
,
1371 const struct dom_sid
*object_sids
,
1372 const struct samba_kdc_entry
*rodc
,
1373 const struct samba_kdc_entry
*object
)
1377 TALLOC_CTX
*frame
= talloc_stackframe();
1378 const char *rodc_attrs
[] = { "msDS-KrbTgtLink",
1379 "msDS-NeverRevealGroup",
1380 "msDS-RevealOnDemandGroup",
1381 "userAccountControl",
1384 struct ldb_result
*rodc_machine_account
= NULL
;
1385 struct ldb_dn
*rodc_machine_account_dn
= samdb_result_dn(rodc
->kdc_db_ctx
->samdb
,
1388 "msDS-KrbTgtLinkBL",
1390 const struct dom_sid
*rodc_machine_account_sid
= NULL
;
1392 if (rodc_machine_account_dn
== NULL
) {
1393 DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
1394 ldb_dn_get_linearized(rodc
->msg
->dn
));
1396 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1400 * Follow the link and get the RODC account (the krbtgt
1401 * account is the krbtgt_XXX account, but the
1402 * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
1403 * the RODC$ account)
1405 * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
1406 * out of the extended DNs
1409 ret
= dsdb_search_dn(rodc
->kdc_db_ctx
->samdb
,
1411 &rodc_machine_account
,
1412 rodc_machine_account_dn
,
1414 DSDB_SEARCH_SHOW_EXTENDED_DN
);
1415 if (ret
!= LDB_SUCCESS
) {
1416 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
1417 ldb_dn_get_linearized(rodc_machine_account_dn
),
1418 ldb_dn_get_linearized(rodc
->msg
->dn
),
1419 ldb_errstring(rodc
->kdc_db_ctx
->samdb
));
1421 return WERR_DOMAIN_CONTROLLER_NOT_FOUND
;
1424 if (rodc_machine_account
->count
!= 1) {
1425 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
1426 ldb_dn_get_linearized(rodc_machine_account_dn
),
1427 ldb_dn_get_linearized(rodc
->msg
->dn
),
1428 rodc_machine_account
->count
);
1430 return WERR_DS_DRA_BAD_DN
;
1433 /* if the object SID is equal to the user_sid, allow */
1434 rodc_machine_account_sid
= samdb_result_dom_sid(frame
,
1435 rodc_machine_account
->msgs
[0],
1437 if (rodc_machine_account_sid
== NULL
) {
1438 return WERR_DS_DRA_BAD_DN
;
1441 werr
= samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc
->kdc_db_ctx
->samdb
,
1442 rodc_machine_account_sid
,
1443 rodc_machine_account
->msgs
[0],
1453 * @brief Update a PAC
1455 * @param mem_ctx A talloc memory context
1457 * @param context A krb5 context
1459 * @param samdb An open samdb connection.
1461 * @param flags Bitwise OR'ed flags
1463 * @param client The client samba kdc entry.
1465 * @param server_principal The server principal
1467 * @param server The server samba kdc entry.
1469 * @param krbtgt The krbtgt samba kdc entry.
1471 * @param delegated_proxy_principal The delegated proxy principal used for
1472 * updating the constrained delegation PAC
1475 * @param old_pac The old PAC
1477 * @param new_pac The new already allocated PAC
1479 * @return A Kerberos error code. If no PAC should be returned, the code will be
1482 krb5_error_code
samba_kdc_update_pac(TALLOC_CTX
*mem_ctx
,
1483 krb5_context context
,
1484 struct ldb_context
*samdb
,
1486 struct samba_kdc_entry
*client
,
1487 const krb5_principal server_principal
,
1488 const struct samba_kdc_entry
*server
,
1489 const struct samba_kdc_entry
*krbtgt
,
1490 const krb5_principal delegated_proxy_principal
,
1491 const krb5_pac old_pac
,
1492 const krb5_pac new_pac
)
1494 krb5_error_code code
= EINVAL
;
1496 DATA_BLOB
*pac_blob
= NULL
;
1497 DATA_BLOB
*upn_blob
= NULL
;
1498 DATA_BLOB
*deleg_blob
= NULL
;
1499 DATA_BLOB
*requester_sid_blob
= NULL
;
1500 DATA_BLOB
*client_claims_blob
= NULL
;
1501 bool is_trusted
= flags
& SAMBA_KDC_FLAG_KRBTGT_IS_TRUSTED
;
1503 enum auth_group_inclusion group_inclusion
;
1504 size_t num_types
= 0;
1505 uint32_t *types
= NULL
;
1507 * FIXME: Do we really still need forced_next_type? With MIT Kerberos
1508 * the PAC buffers do not get ordered and it works just fine. We are
1509 * not aware of any issues in this regard. This might be just ancient
1512 uint32_t forced_next_type
= 0;
1514 ssize_t logon_info_idx
= -1;
1515 ssize_t delegation_idx
= -1;
1516 ssize_t logon_name_idx
= -1;
1517 ssize_t upn_dns_info_idx
= -1;
1518 ssize_t srv_checksum_idx
= -1;
1519 ssize_t kdc_checksum_idx
= -1;
1520 ssize_t tkt_checksum_idx
= -1;
1521 ssize_t attrs_info_idx
= -1;
1522 ssize_t requester_sid_idx
= -1;
1523 ssize_t full_checksum_idx
= -1;
1525 is_tgs
= smb_krb5_principal_is_tgs(context
, server_principal
);
1531 /* Only include resource groups in a service ticket. */
1533 group_inclusion
= AUTH_EXCLUDE_RESOURCE_GROUPS
;
1534 } else if (server
->supported_enctypes
& KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED
) {
1535 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS
;
1537 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
;
1540 if (client
!= NULL
) {
1542 * Check the objectSID of the client and pac data are the same.
1543 * Does a parse and SID check, but no crypto.
1545 code
= samba_kdc_validate_pac_blob(context
,
1553 if (delegated_proxy_principal
!= NULL
) {
1554 deleg_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1555 if (deleg_blob
== NULL
) {
1560 nt_status
= samba_kdc_update_delegation_info_blob(
1565 delegated_proxy_principal
,
1567 if (!NT_STATUS_IS_OK(nt_status
)) {
1568 DBG_ERR("update delegation info blob failed: %s\n",
1569 nt_errstr(nt_status
));
1576 struct auth_user_info_dc
*user_info_dc
= NULL
;
1579 struct dom_sid
*object_sids
= NULL
;
1583 * In this case the RWDC discards the PAC an RODC generated.
1584 * Windows adds the asserted_identity in this case too.
1586 * Note that SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
1587 * generates KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN.
1588 * So we can always use
1589 * SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
1592 enum samba_asserted_identity asserted_identity
=
1593 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
;
1595 if (client
== NULL
) {
1596 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1600 nt_status
= samba_kdc_get_pac_blobs(mem_ctx
,
1608 PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
,
1609 &requester_sid_blob
,
1610 &client_claims_blob
);
1611 if (!NT_STATUS_IS_OK(nt_status
)) {
1612 DBG_ERR("samba_kdc_get_pac_blobs failed: %s\n",
1613 nt_errstr(nt_status
));
1614 code
= KRB5KDC_ERR_TGT_REVOKED
;
1618 nt_status
= samba_kdc_get_user_info_from_db(client
,
1621 if (!NT_STATUS_IS_OK(nt_status
)) {
1622 DBG_ERR("samba_kdc_get_user_info_from_db failed: %s\n",
1623 nt_errstr(nt_status
));
1624 code
= KRB5KDC_ERR_TGT_REVOKED
;
1629 * Check if the SID list in the user_info_dc intersects
1630 * correctly with the RODC allow/deny lists.
1632 object_sids
= talloc_array(mem_ctx
, struct dom_sid
, user_info_dc
->num_sids
);
1633 if (object_sids
== NULL
) {
1638 for (j
= 0; j
< user_info_dc
->num_sids
; ++j
) {
1639 object_sids
[j
] = user_info_dc
->sids
[j
].sid
;
1642 werr
= samba_rodc_confirm_user_is_allowed(user_info_dc
->num_sids
,
1646 TALLOC_FREE(object_sids
);
1647 TALLOC_FREE(user_info_dc
);
1648 if (!W_ERROR_IS_OK(werr
)) {
1649 code
= KRB5KDC_ERR_TGT_REVOKED
;
1650 if (W_ERROR_EQUAL(werr
,
1651 WERR_DOMAIN_CONTROLLER_NOT_FOUND
)) {
1652 code
= KRB5KDC_ERR_POLICY
;
1658 * The RODC PAC data isn't trusted for authorization as it may
1659 * be stale. The only thing meaningful we can do with an RODC
1660 * account on a full DC is exchange the RODC TGT for a 'real'
1663 * So we match Windows (at least server 2022) and
1664 * don't allow S4U2Self.
1666 * https://lists.samba.org/archive/cifs-protocol/2022-April/003673.html
1668 if (flags
& SAMBA_KDC_FLAG_PROTOCOL_TRANSITION
) {
1669 code
= KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN
;
1673 pac_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
1674 if (pac_blob
== NULL
) {
1679 nt_status
= samba_kdc_update_pac_blob(mem_ctx
,
1687 if (!NT_STATUS_IS_OK(nt_status
)) {
1688 DBG_ERR("samba_kdc_update_pac_blob failed: %s\n",
1689 nt_errstr(nt_status
));
1695 /* Check the types of the given PAC */
1696 code
= krb5_pac_get_types(context
, old_pac
, &num_types
, &types
);
1698 DBG_ERR("krb5_pac_get_types failed\n");
1702 for (i
= 0; i
< num_types
; i
++) {
1704 case PAC_TYPE_LOGON_INFO
:
1705 if (logon_info_idx
!= -1) {
1706 DBG_WARNING("logon info type[%u] twice [%zd] "
1716 case PAC_TYPE_CONSTRAINED_DELEGATION
:
1717 if (delegation_idx
!= -1) {
1718 DBG_WARNING("constrained delegation type[%u] "
1719 "twice [%zd] and [%zu]: \n",
1728 case PAC_TYPE_LOGON_NAME
:
1729 if (logon_name_idx
!= -1) {
1730 DBG_WARNING("logon name type[%u] twice [%zd] "
1740 case PAC_TYPE_UPN_DNS_INFO
:
1741 if (upn_dns_info_idx
!= -1) {
1742 DBG_WARNING("upn dns info type[%u] twice [%zd] "
1750 upn_dns_info_idx
= i
;
1752 case PAC_TYPE_SRV_CHECKSUM
:
1753 if (srv_checksum_idx
!= -1) {
1754 DBG_WARNING("srv checksum type[%u] twice [%zd] "
1762 srv_checksum_idx
= i
;
1764 case PAC_TYPE_KDC_CHECKSUM
:
1765 if (kdc_checksum_idx
!= -1) {
1766 DBG_WARNING("kdc checksum type[%u] twice [%zd] "
1774 kdc_checksum_idx
= i
;
1776 case PAC_TYPE_TICKET_CHECKSUM
:
1777 if (tkt_checksum_idx
!= -1) {
1778 DBG_WARNING("ticket checksum type[%u] twice "
1779 "[%zd] and [%zu]: \n",
1786 tkt_checksum_idx
= i
;
1788 case PAC_TYPE_ATTRIBUTES_INFO
:
1789 if (attrs_info_idx
!= -1) {
1790 DBG_WARNING("attributes info type[%u] twice "
1791 "[%zd] and [%zu]: \n",
1800 case PAC_TYPE_REQUESTER_SID
:
1801 if (requester_sid_idx
!= -1) {
1802 DBG_WARNING("requester sid type[%u] twice"
1803 "[%zd] and [%zu]: \n",
1810 requester_sid_idx
= i
;
1812 case PAC_TYPE_FULL_CHECKSUM
:
1813 if (full_checksum_idx
!= -1) {
1814 DBG_WARNING("full checksum type[%u] twice "
1815 "[%zd] and [%zu]: \n",
1822 full_checksum_idx
= i
;
1829 if (logon_info_idx
== -1) {
1830 DBG_WARNING("PAC_TYPE_LOGON_INFO missing\n");
1834 if (logon_name_idx
== -1) {
1835 DBG_WARNING("PAC_TYPE_LOGON_NAME missing\n");
1839 if (srv_checksum_idx
== -1) {
1840 DBG_WARNING("PAC_TYPE_SRV_CHECKSUM missing\n");
1844 if (kdc_checksum_idx
== -1) {
1845 DBG_WARNING("PAC_TYPE_KDC_CHECKSUM missing\n");
1849 if (!(flags
& SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
) &&
1850 requester_sid_idx
== -1) {
1851 DBG_WARNING("PAC_TYPE_REQUESTER_SID missing\n");
1852 code
= KRB5KDC_ERR_TGT_REVOKED
;
1857 * The server account may be set not to want the PAC.
1859 * While this is wasteful if the above cacluations were done
1860 * and now thrown away, this is cleaner as we do any ticket
1861 * signature checking etc always.
1863 * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
1864 * time (eg not accepting a ticket from the RODC) we do not
1865 * need to re-generate anything anyway.
1867 if (!samba_princ_needs_pac(server
)) {
1872 if (is_trusted
&& !is_tgs
) {
1874 * The client may have requested no PAC when obtaining the
1877 bool requested_pac
= false;
1879 code
= samba_client_requested_pac(context
,
1883 if (code
!= 0 || !requested_pac
) {
1884 if (!requested_pac
) {
1891 #define MAX_PAC_BUFFERS 128 /* Avoid infinite loops */
1893 for (i
= 0; i
< MAX_PAC_BUFFERS
;) {
1894 const uint8_t zero_byte
= 0;
1895 krb5_data type_data
;
1896 DATA_BLOB type_blob
= data_blob_null
;
1899 if (forced_next_type
!= 0) {
1901 * We need to inject possible missing types
1903 type
= forced_next_type
;
1904 forced_next_type
= 0;
1905 } else if (i
< num_types
) {
1913 case PAC_TYPE_LOGON_INFO
:
1914 type_blob
= *pac_blob
;
1916 if (delegation_idx
== -1 && deleg_blob
!= NULL
) {
1917 /* inject CONSTRAINED_DELEGATION behind */
1919 PAC_TYPE_CONSTRAINED_DELEGATION
;
1922 case PAC_TYPE_CONSTRAINED_DELEGATION
:
1924 * This is generated in the main KDC code
1926 if (flags
& SAMBA_KDC_FLAG_SKIP_PAC_BUFFER
) {
1930 if (deleg_blob
!= NULL
) {
1931 type_blob
= *deleg_blob
;
1934 case PAC_TYPE_CREDENTIAL_INFO
:
1936 * Note that we copy the credential blob,
1937 * as it's only usable with the PKINIT based
1938 * AS-REP reply key, it's only available on the
1939 * host which did the AS-REQ/AS-REP exchange.
1941 * This matches Windows 2008R2...
1944 case PAC_TYPE_LOGON_NAME
:
1946 * This is generated in the main KDC code
1948 if (flags
& SAMBA_KDC_FLAG_SKIP_PAC_BUFFER
) {
1952 type_blob
= data_blob_const(&zero_byte
, 1);
1954 if (upn_dns_info_idx
== -1 && upn_blob
!= NULL
) {
1955 /* inject UPN_DNS_INFO behind */
1956 forced_next_type
= PAC_TYPE_UPN_DNS_INFO
;
1959 case PAC_TYPE_UPN_DNS_INFO
:
1961 * Replace in the RODC case, otherwise
1962 * upn_blob is NULL and we just copy.
1964 if (upn_blob
!= NULL
) {
1965 type_blob
= *upn_blob
;
1968 case PAC_TYPE_SRV_CHECKSUM
:
1970 * This is generated in the main KDC code
1972 if (flags
& SAMBA_KDC_FLAG_SKIP_PAC_BUFFER
) {
1976 type_blob
= data_blob_const(&zero_byte
, 1);
1978 if (requester_sid_idx
== -1 && requester_sid_blob
!= NULL
) {
1979 /* inject REQUESTER_SID behind */
1980 forced_next_type
= PAC_TYPE_REQUESTER_SID
;
1983 case PAC_TYPE_KDC_CHECKSUM
:
1985 * This is generated in the main KDC code
1987 if (flags
& SAMBA_KDC_FLAG_SKIP_PAC_BUFFER
) {
1991 type_blob
= data_blob_const(&zero_byte
, 1);
1994 case PAC_TYPE_TICKET_CHECKSUM
:
1996 * This is generated in the main KDC code
1998 if (flags
& SAMBA_KDC_FLAG_SKIP_PAC_BUFFER
) {
2002 type_blob
= data_blob_const(&zero_byte
, 1);
2005 case PAC_TYPE_ATTRIBUTES_INFO
:
2006 if (is_trusted
&& is_tgs
) {
2012 case PAC_TYPE_REQUESTER_SID
:
2018 * Replace in the RODC case, otherwise
2019 * requester_sid_blob is NULL and we just copy.
2021 if (requester_sid_blob
!= NULL
) {
2022 type_blob
= *requester_sid_blob
;
2025 case PAC_TYPE_FULL_CHECKSUM
:
2027 * This is generated in the main KDC code
2029 if (flags
& SAMBA_KDC_FLAG_SKIP_PAC_BUFFER
) {
2033 type_blob
= data_blob_const(&zero_byte
, 1);
2041 if (type_blob
.length
!= 0) {
2042 code
= smb_krb5_copy_data_contents(&type_data
,
2049 code
= krb5_pac_get_buffer(context
,
2058 code
= krb5_pac_add_buffer(context
,
2062 smb_krb5_free_data_contents(context
, &type_data
);
2070 TALLOC_FREE(pac_blob
);
2071 TALLOC_FREE(upn_blob
);
2072 TALLOC_FREE(deleg_blob
);