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"
46 NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
47 const struct auth_user_info_dc *info,
49 DATA_BLOB *requester_sid_blob)
51 struct netr_SamInfo3 *info3;
52 union PAC_INFO pac_info;
53 enum ndr_err_code ndr_err;
56 ZERO_STRUCT(pac_info);
58 *pac_data = data_blob_null;
59 if (requester_sid_blob != NULL) {
60 *requester_sid_blob = data_blob_null;
63 nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, info, &info3);
64 if (!NT_STATUS_IS_OK(nt_status)) {
65 DEBUG(1, ("Getting Samba info failed: %s\n",
66 nt_errstr(nt_status)));
70 pac_info.logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO);
71 if (!pac_info.logon_info.info) {
72 return NT_STATUS_NO_MEMORY;
75 pac_info.logon_info.info->info3 = *info3;
77 ndr_err = ndr_push_union_blob(pac_data, mem_ctx, &pac_info,
79 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
80 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
81 nt_status = ndr_map_error2ntstatus(ndr_err);
82 DEBUG(1, ("PAC_LOGON_INFO (presig) push failed: %s\n",
83 nt_errstr(nt_status)));
87 if (requester_sid_blob != NULL && info->num_sids > 0) {
88 union PAC_INFO pac_requester_sid;
90 ZERO_STRUCT(pac_requester_sid);
92 pac_requester_sid.requester_sid.sid = info->sids[0];
94 ndr_err = ndr_push_union_blob(requester_sid_blob, mem_ctx,
96 PAC_TYPE_REQUESTER_SID,
97 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
98 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
99 nt_status = ndr_map_error2ntstatus(ndr_err);
100 DEBUG(1, ("PAC_REQUESTER_SID (presig) push failed: %s\n",
101 nt_errstr(nt_status)));
110 NTSTATUS samba_get_upn_info_pac_blob(TALLOC_CTX *mem_ctx,
111 const struct auth_user_info_dc *info,
114 union PAC_INFO pac_upn;
115 enum ndr_err_code ndr_err;
119 ZERO_STRUCT(pac_upn);
121 *upn_data = data_blob_null;
123 pac_upn.upn_dns_info.upn_name = info->info->user_principal_name;
124 pac_upn.upn_dns_info.dns_domain_name = strupper_talloc(mem_ctx,
125 info->info->dns_domain_name);
126 if (pac_upn.upn_dns_info.dns_domain_name == NULL) {
127 return NT_STATUS_NO_MEMORY;
129 if (info->info->user_principal_constructed) {
130 pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED;
133 pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_HAS_SAM_NAME_AND_SID;
135 pac_upn.upn_dns_info.ex.sam_name_and_sid.samaccountname
136 = info->info->account_name;
138 pac_upn.upn_dns_info.ex.sam_name_and_sid.objectsid
141 ndr_err = ndr_push_union_blob(upn_data, mem_ctx, &pac_upn,
142 PAC_TYPE_UPN_DNS_INFO,
143 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
144 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
145 nt_status = ndr_map_error2ntstatus(ndr_err);
146 DEBUG(1, ("PAC UPN_DNS_INFO (presig) push failed: %s\n",
147 nt_errstr(nt_status)));
151 ok = data_blob_pad(mem_ctx, upn_data, 8);
153 return NT_STATUS_NO_MEMORY;
160 NTSTATUS samba_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
161 uint64_t pac_attributes,
162 DATA_BLOB *pac_attrs_data)
164 union PAC_INFO pac_attrs;
165 enum ndr_err_code ndr_err;
168 ZERO_STRUCT(pac_attrs);
170 *pac_attrs_data = data_blob_null;
172 /* Set the length of the flags in bits. */
173 pac_attrs.attributes_info.flags_length = 2;
174 pac_attrs.attributes_info.flags = pac_attributes;
176 ndr_err = ndr_push_union_blob(pac_attrs_data, mem_ctx, &pac_attrs,
177 PAC_TYPE_ATTRIBUTES_INFO,
178 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
179 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
180 nt_status = ndr_map_error2ntstatus(ndr_err);
181 DEBUG(1, ("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
182 nt_errstr(nt_status)));
190 NTSTATUS samba_get_cred_info_ndr_blob(TALLOC_CTX *mem_ctx,
191 const struct ldb_message *msg,
192 DATA_BLOB *cred_blob)
194 enum ndr_err_code ndr_err;
196 struct samr_Password *lm_hash = NULL;
197 struct samr_Password *nt_hash = NULL;
198 struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg = {
201 DATA_BLOB ntlm_blob = data_blob_null;
202 struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs[1] = {{
203 .credential_size = 0,
205 struct PAC_CREDENTIAL_DATA cred_data = {
206 .credential_count = 0,
208 struct PAC_CREDENTIAL_DATA_NDR cred_ndr;
210 ZERO_STRUCT(cred_ndr);
212 *cred_blob = data_blob_null;
214 lm_hash = samdb_result_hash(mem_ctx, msg, "dBCSPwd");
215 if (lm_hash != NULL) {
216 bool zero = all_zero(lm_hash->hash, 16);
221 if (lm_hash != NULL) {
222 DEBUG(5, ("Passing LM password hash through credentials set\n"));
223 ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_LM_HASH;
224 ntlm_secpkg.lm_password = *lm_hash;
225 ZERO_STRUCTP(lm_hash);
226 TALLOC_FREE(lm_hash);
229 nt_hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
230 if (nt_hash != NULL) {
231 bool zero = all_zero(nt_hash->hash, 16);
236 if (nt_hash != NULL) {
237 DEBUG(5, ("Passing LM password hash through credentials set\n"));
238 ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_NT_HASH;
239 ntlm_secpkg.nt_password = *nt_hash;
240 ZERO_STRUCTP(nt_hash);
241 TALLOC_FREE(nt_hash);
244 if (ntlm_secpkg.flags == 0) {
248 #ifdef DEBUG_PASSWORD
250 NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG, &ntlm_secpkg);
254 ndr_err = ndr_push_struct_blob(&ntlm_blob, mem_ctx, &ntlm_secpkg,
255 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG);
256 ZERO_STRUCT(ntlm_secpkg);
257 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
258 nt_status = ndr_map_error2ntstatus(ndr_err);
259 DEBUG(1, ("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
260 nt_errstr(nt_status)));
264 DEBUG(10, ("NTLM credential BLOB (len %zu) for user\n",
266 dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
267 ntlm_blob.data, ntlm_blob.length);
269 secpkgs[0].package_name.string = discard_const_p(char, "NTLM");
270 secpkgs[0].credential_size = ntlm_blob.length;
271 secpkgs[0].credential = ntlm_blob.data;
273 cred_data.credential_count = ARRAY_SIZE(secpkgs);
274 cred_data.credentials = secpkgs;
276 #ifdef DEBUG_PASSWORD
278 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA, &cred_data);
282 cred_ndr.ctr.data = &cred_data;
284 #ifdef DEBUG_PASSWORD
286 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR, &cred_ndr);
290 ndr_err = ndr_push_struct_blob(cred_blob, mem_ctx, &cred_ndr,
291 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_DATA_NDR);
292 data_blob_clear(&ntlm_blob);
293 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
294 nt_status = ndr_map_error2ntstatus(ndr_err);
295 DEBUG(1, ("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
296 nt_errstr(nt_status)));
300 DEBUG(10, ("Created credential BLOB (len %zu) for user\n",
302 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
303 cred_blob->data, cred_blob->length);
308 #ifdef SAMBA4_USES_HEIMDAL
309 krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
310 const krb5_keyblock *pkreplykey,
311 const DATA_BLOB *cred_ndr_blob,
313 DATA_BLOB *cred_info_blob)
315 krb5_crypto cred_crypto;
316 krb5_enctype cred_enctype;
317 krb5_data cred_ndr_crypt;
318 struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
321 enum ndr_err_code ndr_err;
324 *cred_info_blob = data_blob_null;
326 ret = krb5_crypto_init(context, pkreplykey, ETYPE_NULL,
329 krb5err = krb5_get_error_message(context, ret);
330 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
331 krb5_free_error_message(context, krb5err);
335 ret = krb5_crypto_getenctype(context, cred_crypto, &cred_enctype);
337 DEBUG(1, ("Failed getting crypto type for key\n"));
338 krb5_crypto_destroy(context, cred_crypto);
342 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
343 cred_ndr_blob->length));
344 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
345 cred_ndr_blob->data, cred_ndr_blob->length);
347 ret = krb5_encrypt(context, cred_crypto,
348 KRB5_KU_OTHER_ENCRYPTED,
349 cred_ndr_blob->data, cred_ndr_blob->length,
351 krb5_crypto_destroy(context, cred_crypto);
353 krb5err = krb5_get_error_message(context, ret);
354 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err));
355 krb5_free_error_message(context, krb5err);
359 pac_cred_info.encryption_type = cred_enctype;
360 pac_cred_info.encrypted_data.length = cred_ndr_crypt.length;
361 pac_cred_info.encrypted_data.data = (uint8_t *)cred_ndr_crypt.data;
364 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
367 ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
368 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
369 krb5_data_free(&cred_ndr_crypt);
370 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
371 nt_status = ndr_map_error2ntstatus(ndr_err);
372 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
373 nt_errstr(nt_status)));
374 return KRB5KDC_ERR_SVC_UNAVAILABLE;
377 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
378 cred_info_blob->length, (int)pac_cred_info.encryption_type));
379 dump_data_pw("PAC_CREDENTIAL_INFO",
380 cred_info_blob->data, cred_info_blob->length);
384 #else /* SAMBA4_USES_HEIMDAL */
385 krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
386 const krb5_keyblock *pkreplykey,
387 const DATA_BLOB *cred_ndr_blob,
389 DATA_BLOB *cred_info_blob)
392 krb5_enctype cred_enctype;
393 struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
394 krb5_error_code code;
396 enum ndr_err_code ndr_err;
398 krb5_data cred_ndr_data;
399 krb5_enc_data cred_ndr_crypt;
402 *cred_info_blob = data_blob_null;
404 code = krb5_k_create_key(context,
408 krb5err = krb5_get_error_message(context, code);
409 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
410 krb5_free_error_message(context, krb5err);
414 cred_enctype = krb5_k_key_enctype(context, cred_key);
416 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
417 cred_ndr_blob->length));
418 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
419 cred_ndr_blob->data, cred_ndr_blob->length);
421 pac_cred_info.encryption_type = cred_enctype;
423 cred_ndr_data.magic = 0;
424 cred_ndr_data.data = (char *)cred_ndr_blob->data;
425 cred_ndr_data.length = cred_ndr_blob->length;
427 code = krb5_c_encrypt_length(context,
429 cred_ndr_data.length,
432 krb5err = krb5_get_error_message(context, code);
433 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
434 krb5_free_error_message(context, krb5err);
438 pac_cred_info.encrypted_data = data_blob_talloc_zero(mem_ctx, enc_len);
439 if (pac_cred_info.encrypted_data.data == NULL) {
440 DBG_ERR("Out of memory\n");
444 cred_ndr_crypt.ciphertext.length = enc_len;
445 cred_ndr_crypt.ciphertext.data = (char *)pac_cred_info.encrypted_data.data;
447 code = krb5_k_encrypt(context,
449 KRB5_KU_OTHER_ENCRYPTED,
453 krb5_k_free_key(context, cred_key);
455 krb5err = krb5_get_error_message(context, code);
456 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err));
457 krb5_free_error_message(context, krb5err);
462 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
465 ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
466 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
467 TALLOC_FREE(pac_cred_info.encrypted_data.data);
468 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
469 nt_status = ndr_map_error2ntstatus(ndr_err);
470 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
471 nt_errstr(nt_status)));
472 return KRB5KDC_ERR_SVC_UNAVAILABLE;
475 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
476 cred_info_blob->length, (int)pac_cred_info.encryption_type));
477 dump_data_pw("PAC_CREDENTIAL_INFO",
478 cred_info_blob->data, cred_info_blob->length);
482 #endif /* SAMBA4_USES_HEIMDAL */
486 * @brief Create a PAC with the given blobs (logon, credentials, upn and
489 * @param[in] context The KRB5 context to use.
491 * @param[in] logon_blob Fill the logon info PAC buffer with the given blob,
492 * use NULL to ignore it.
494 * @param[in] cred_blob Fill the credentials info PAC buffer with the given
495 * blob, use NULL to ignore it.
497 * @param[in] upn_blob Fill the UPN info PAC buffer with the given blob, use
500 * @param[in] deleg_blob Fill the delegation info PAC buffer with the given
501 * blob, use NULL to ignore it.
503 * @param[in] pac The pac buffer to fill. This should be allocated with
504 * krb5_pac_init() already.
506 * @returns 0 on success or a corresponding KRB5 error.
508 krb5_error_code samba_make_krb5_pac(krb5_context context,
509 const DATA_BLOB *logon_blob,
510 const DATA_BLOB *cred_blob,
511 const DATA_BLOB *upn_blob,
512 const DATA_BLOB *pac_attrs_blob,
513 const DATA_BLOB *requester_sid_blob,
514 const DATA_BLOB *deleg_blob,
517 krb5_data logon_data;
520 krb5_data pac_attrs_data;
521 krb5_data requester_sid_data;
522 krb5_data deleg_data;
524 #ifdef SAMBA4_USES_HEIMDAL
525 char null_byte = '\0';
526 krb5_data null_data = {
532 /* The user account may be set not to want the PAC */
533 if (logon_blob == NULL) {
537 ret = smb_krb5_copy_data_contents(&logon_data,
544 ZERO_STRUCT(cred_data);
545 if (cred_blob != NULL) {
546 ret = smb_krb5_copy_data_contents(&cred_data,
550 smb_krb5_free_data_contents(context, &logon_data);
555 ZERO_STRUCT(upn_data);
556 if (upn_blob != NULL) {
557 ret = smb_krb5_copy_data_contents(&upn_data,
561 smb_krb5_free_data_contents(context, &logon_data);
562 smb_krb5_free_data_contents(context, &cred_data);
567 ZERO_STRUCT(pac_attrs_data);
568 if (pac_attrs_blob != NULL) {
569 ret = smb_krb5_copy_data_contents(&pac_attrs_data,
570 pac_attrs_blob->data,
571 pac_attrs_blob->length);
573 smb_krb5_free_data_contents(context, &logon_data);
574 smb_krb5_free_data_contents(context, &cred_data);
575 smb_krb5_free_data_contents(context, &upn_data);
580 ZERO_STRUCT(requester_sid_data);
581 if (requester_sid_blob != NULL) {
582 ret = smb_krb5_copy_data_contents(&requester_sid_data,
583 requester_sid_blob->data,
584 requester_sid_blob->length);
586 smb_krb5_free_data_contents(context, &logon_data);
587 smb_krb5_free_data_contents(context, &cred_data);
588 smb_krb5_free_data_contents(context, &upn_data);
589 smb_krb5_free_data_contents(context, &pac_attrs_data);
594 ZERO_STRUCT(deleg_data);
595 if (deleg_blob != NULL) {
596 ret = smb_krb5_copy_data_contents(&deleg_data,
600 smb_krb5_free_data_contents(context, &logon_data);
601 smb_krb5_free_data_contents(context, &cred_data);
602 smb_krb5_free_data_contents(context, &upn_data);
603 smb_krb5_free_data_contents(context, &pac_attrs_data);
604 smb_krb5_free_data_contents(context, &requester_sid_data);
609 ret = krb5_pac_add_buffer(context, pac, PAC_TYPE_LOGON_INFO, &logon_data);
610 smb_krb5_free_data_contents(context, &logon_data);
612 smb_krb5_free_data_contents(context, &cred_data);
613 smb_krb5_free_data_contents(context, &upn_data);
614 smb_krb5_free_data_contents(context, &pac_attrs_data);
615 smb_krb5_free_data_contents(context, &requester_sid_data);
616 smb_krb5_free_data_contents(context, &deleg_data);
620 if (cred_blob != NULL) {
621 ret = krb5_pac_add_buffer(context, pac,
622 PAC_TYPE_CREDENTIAL_INFO,
624 smb_krb5_free_data_contents(context, &cred_data);
626 smb_krb5_free_data_contents(context, &upn_data);
627 smb_krb5_free_data_contents(context, &pac_attrs_data);
628 smb_krb5_free_data_contents(context, &requester_sid_data);
629 smb_krb5_free_data_contents(context, &deleg_data);
634 #ifdef SAMBA4_USES_HEIMDAL
636 * null_data will be filled by the generic KDC code in the caller
637 * here we just add it in order to have it before
638 * PAC_TYPE_UPN_DNS_INFO
640 * Not needed with MIT Kerberos - asn
642 ret = krb5_pac_add_buffer(context, pac,
646 smb_krb5_free_data_contents(context, &upn_data);
647 smb_krb5_free_data_contents(context, &pac_attrs_data);
648 smb_krb5_free_data_contents(context, &requester_sid_data);
649 smb_krb5_free_data_contents(context, &deleg_data);
654 if (upn_blob != NULL) {
655 ret = krb5_pac_add_buffer(context, pac,
656 PAC_TYPE_UPN_DNS_INFO,
658 smb_krb5_free_data_contents(context, &upn_data);
660 smb_krb5_free_data_contents(context, &pac_attrs_data);
661 smb_krb5_free_data_contents(context, &requester_sid_data);
662 smb_krb5_free_data_contents(context, &deleg_data);
667 if (pac_attrs_blob != NULL) {
668 ret = krb5_pac_add_buffer(context, pac,
669 PAC_TYPE_ATTRIBUTES_INFO,
671 smb_krb5_free_data_contents(context, &pac_attrs_data);
673 smb_krb5_free_data_contents(context, &requester_sid_data);
674 smb_krb5_free_data_contents(context, &deleg_data);
679 if (requester_sid_blob != NULL) {
680 ret = krb5_pac_add_buffer(context, pac,
681 PAC_TYPE_REQUESTER_SID,
682 &requester_sid_data);
683 smb_krb5_free_data_contents(context, &requester_sid_data);
685 smb_krb5_free_data_contents(context, &deleg_data);
690 if (deleg_blob != NULL) {
691 ret = krb5_pac_add_buffer(context, pac,
692 PAC_TYPE_CONSTRAINED_DELEGATION,
694 smb_krb5_free_data_contents(context, &deleg_data);
703 bool samba_princ_needs_pac(struct samba_kdc_entry *skdc_entry)
706 uint32_t userAccountControl;
708 /* The service account may be set not to want the PAC */
709 userAccountControl = ldb_msg_find_attr_as_uint(skdc_entry->msg, "userAccountControl", 0);
710 if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
717 int samba_client_requested_pac(krb5_context context,
722 enum ndr_err_code ndr_err;
723 krb5_data k5pac_attrs_in;
724 DATA_BLOB pac_attrs_in;
725 union PAC_INFO pac_attrs;
728 *requested_pac = true;
730 ret = krb5_pac_get_buffer(context, *pac, PAC_TYPE_ATTRIBUTES_INFO,
733 return ret == ENOENT ? 0 : ret;
736 pac_attrs_in = data_blob_const(k5pac_attrs_in.data,
737 k5pac_attrs_in.length);
739 ndr_err = ndr_pull_union_blob(&pac_attrs_in, mem_ctx, &pac_attrs,
740 PAC_TYPE_ATTRIBUTES_INFO,
741 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
742 smb_krb5_free_data_contents(context, &k5pac_attrs_in);
743 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
744 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
745 DEBUG(0,("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status)));
749 if (pac_attrs.attributes_info.flags & (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
750 | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED)) {
751 *requested_pac = true;
753 *requested_pac = false;
759 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
760 int samba_krbtgt_is_in_db(struct samba_kdc_entry *p,
765 int rodc_krbtgt_number, trust_direction;
768 TALLOC_CTX *mem_ctx = talloc_new(NULL);
773 trust_direction = ldb_msg_find_attr_as_int(p->msg, "trustDirection", 0);
775 if (trust_direction != 0) {
776 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
778 This is exactly where we should flag for SID
779 validation when we do inter-foreest trusts
781 talloc_free(mem_ctx);
782 *is_untrusted = false;
787 /* The lack of password controls etc applies to krbtgt by
788 * virtue of being that particular RID */
789 status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, p->msg, "objectSid"), NULL, &rid);
791 if (!NT_STATUS_IS_OK(status)) {
792 talloc_free(mem_ctx);
796 rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1);
798 if (p->kdc_db_ctx->my_krbtgt_number == 0) {
799 if (rid == DOMAIN_RID_KRBTGT) {
800 *is_untrusted = false;
802 talloc_free(mem_ctx);
804 } else if (rodc_krbtgt_number != -1) {
806 *is_untrusted = true;
807 talloc_free(mem_ctx);
810 } else if ((rid != DOMAIN_RID_KRBTGT) && (rodc_krbtgt_number == p->kdc_db_ctx->my_krbtgt_number)) {
811 talloc_free(mem_ctx);
812 *is_untrusted = false;
815 } else if (rid == DOMAIN_RID_KRBTGT) {
816 /* krbtgt viewed from an RODC */
817 talloc_free(mem_ctx);
818 *is_untrusted = false;
824 talloc_free(mem_ctx);
825 *is_untrusted = true;
831 * We return not just the blobs, but also the user_info_dc because we
832 * will need, in the RODC case, to confirm that the returned user is
833 * permitted to be replicated to the KDC
835 NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
836 struct samba_kdc_entry *p,
837 DATA_BLOB **_logon_info_blob,
838 DATA_BLOB **_cred_ndr_blob,
839 DATA_BLOB **_upn_info_blob,
840 DATA_BLOB **_pac_attrs_blob,
841 uint64_t pac_attributes,
842 DATA_BLOB **_requester_sid_blob,
843 struct auth_user_info_dc **_user_info_dc)
845 struct auth_user_info_dc *user_info_dc;
846 DATA_BLOB *logon_blob = NULL;
847 DATA_BLOB *cred_blob = NULL;
848 DATA_BLOB *upn_blob = NULL;
849 DATA_BLOB *pac_attrs_blob = NULL;
850 DATA_BLOB *requester_sid_blob = NULL;
853 *_logon_info_blob = NULL;
854 if (_cred_ndr_blob != NULL) {
855 *_cred_ndr_blob = NULL;
857 *_upn_info_blob = NULL;
858 if (_pac_attrs_blob != NULL) {
859 *_pac_attrs_blob = NULL;
861 if (_requester_sid_blob != NULL) {
862 *_requester_sid_blob = NULL;
865 logon_blob = talloc_zero(mem_ctx, DATA_BLOB);
866 if (logon_blob == NULL) {
867 return NT_STATUS_NO_MEMORY;
870 if (_cred_ndr_blob != NULL) {
871 cred_blob = talloc_zero(mem_ctx, DATA_BLOB);
872 if (cred_blob == NULL) {
873 return NT_STATUS_NO_MEMORY;
877 upn_blob = talloc_zero(mem_ctx, DATA_BLOB);
878 if (upn_blob == NULL) {
879 return NT_STATUS_NO_MEMORY;
882 if (_pac_attrs_blob != NULL) {
883 pac_attrs_blob = talloc_zero(mem_ctx, DATA_BLOB);
884 if (pac_attrs_blob == NULL) {
885 return NT_STATUS_NO_MEMORY;
889 if (_requester_sid_blob != NULL) {
890 requester_sid_blob = talloc_zero(mem_ctx, DATA_BLOB);
891 if (requester_sid_blob == NULL) {
892 return NT_STATUS_NO_MEMORY;
896 nt_status = authsam_make_user_info_dc(mem_ctx, p->kdc_db_ctx->samdb,
897 lpcfg_netbios_name(p->kdc_db_ctx->lp_ctx),
898 lpcfg_sam_name(p->kdc_db_ctx->lp_ctx),
899 lpcfg_sam_dnsname(p->kdc_db_ctx->lp_ctx),
905 if (!NT_STATUS_IS_OK(nt_status)) {
906 DEBUG(0, ("Getting user info for PAC failed: %s\n",
907 nt_errstr(nt_status)));
911 nt_status = samba_get_logon_info_pac_blob(logon_blob,
915 if (!NT_STATUS_IS_OK(nt_status)) {
916 DEBUG(0, ("Building PAC LOGON INFO failed: %s\n",
917 nt_errstr(nt_status)));
921 if (cred_blob != NULL) {
922 nt_status = samba_get_cred_info_ndr_blob(cred_blob,
925 if (!NT_STATUS_IS_OK(nt_status)) {
926 DEBUG(0, ("Building PAC CRED INFO failed: %s\n",
927 nt_errstr(nt_status)));
932 nt_status = samba_get_upn_info_pac_blob(upn_blob,
935 if (!NT_STATUS_IS_OK(nt_status)) {
936 DEBUG(0, ("Building PAC UPN INFO failed: %s\n",
937 nt_errstr(nt_status)));
941 if (pac_attrs_blob != NULL) {
942 nt_status = samba_get_pac_attrs_blob(pac_attrs_blob,
946 if (!NT_STATUS_IS_OK(nt_status)) {
947 DEBUG(0, ("Building PAC ATTRIBUTES failed: %s\n",
948 nt_errstr(nt_status)));
954 * Return to the caller to allow a check on the allowed/denied
955 * RODC replication groups
957 if (_user_info_dc == NULL) {
958 TALLOC_FREE(user_info_dc);
960 *_user_info_dc = user_info_dc;
962 *_logon_info_blob = logon_blob;
963 if (_cred_ndr_blob != NULL) {
964 *_cred_ndr_blob = cred_blob;
966 *_upn_info_blob = upn_blob;
967 if (_pac_attrs_blob != NULL) {
968 *_pac_attrs_blob = pac_attrs_blob;
970 if (_requester_sid_blob != NULL) {
971 *_requester_sid_blob = requester_sid_blob;
976 NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
977 krb5_context context,
978 struct ldb_context *samdb,
979 const krb5_pac pac, DATA_BLOB *pac_blob,
980 struct PAC_SIGNATURE_DATA *pac_srv_sig,
981 struct PAC_SIGNATURE_DATA *pac_kdc_sig)
983 struct auth_user_info_dc *user_info_dc;
987 ret = kerberos_pac_to_user_info_dc(mem_ctx, pac,
988 context, &user_info_dc, pac_srv_sig, pac_kdc_sig);
990 return NT_STATUS_UNSUCCESSFUL;
994 * We need to expand group memberships within our local domain,
995 * as the token might be generated by a trusted domain.
997 nt_status = authsam_update_user_info_dc(mem_ctx,
1000 if (!NT_STATUS_IS_OK(nt_status)) {
1004 nt_status = samba_get_logon_info_pac_blob(mem_ctx,
1005 user_info_dc, pac_blob, NULL);
1010 NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx,
1011 krb5_context context,
1013 const krb5_principal server_principal,
1014 const krb5_principal proxy_principal,
1015 DATA_BLOB *new_blob)
1019 krb5_error_code ret;
1021 enum ndr_err_code ndr_err;
1022 union PAC_INFO info;
1023 struct PAC_CONSTRAINED_DELEGATION _d;
1024 struct PAC_CONSTRAINED_DELEGATION *d = NULL;
1025 char *server = NULL;
1028 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1030 if (tmp_ctx == NULL) {
1031 return NT_STATUS_NO_MEMORY;
1034 ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_CONSTRAINED_DELEGATION, &old_data);
1035 if (ret == ENOENT) {
1036 ZERO_STRUCT(old_data);
1038 talloc_free(tmp_ctx);
1039 return NT_STATUS_UNSUCCESSFUL;
1042 old_blob.length = old_data.length;
1043 old_blob.data = (uint8_t *)old_data.data;
1046 if (old_blob.length > 0) {
1047 ndr_err = ndr_pull_union_blob(&old_blob, mem_ctx,
1048 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
1049 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1050 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1051 smb_krb5_free_data_contents(context, &old_data);
1052 nt_status = ndr_map_error2ntstatus(ndr_err);
1053 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
1054 talloc_free(tmp_ctx);
1059 info.constrained_delegation.info = &_d;
1061 smb_krb5_free_data_contents(context, &old_data);
1063 ret = krb5_unparse_name_flags(context, server_principal,
1064 KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server);
1066 talloc_free(tmp_ctx);
1067 return NT_STATUS_INTERNAL_ERROR;
1070 ret = krb5_unparse_name(context, proxy_principal, &proxy);
1073 talloc_free(tmp_ctx);
1074 return NT_STATUS_INTERNAL_ERROR;
1077 d = info.constrained_delegation.info;
1078 i = d->num_transited_services;
1079 d->proxy_target.string = server;
1080 d->transited_services = talloc_realloc(mem_ctx, d->transited_services,
1081 struct lsa_String, i + 1);
1082 d->transited_services[i].string = proxy;
1083 d->num_transited_services = i + 1;
1085 ndr_err = ndr_push_union_blob(new_blob, mem_ctx,
1086 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
1087 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
1090 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1091 smb_krb5_free_data_contents(context, &old_data);
1092 nt_status = ndr_map_error2ntstatus(ndr_err);
1093 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
1094 talloc_free(tmp_ctx);
1098 talloc_free(tmp_ctx);
1099 return NT_STATUS_OK;
1102 /* function to map policy errors */
1103 krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status)
1105 krb5_error_code ret;
1107 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE))
1108 ret = KRB5KDC_ERR_KEY_EXP;
1109 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED))
1110 ret = KRB5KDC_ERR_KEY_EXP;
1111 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED))
1112 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1113 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED))
1114 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1115 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS))
1116 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1117 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT))
1118 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1119 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION))
1120 ret = KRB5KDC_ERR_POLICY;
1122 ret = KRB5KDC_ERR_POLICY;
1127 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
1128 * for consistency */
1129 NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry,
1130 const char *client_name,
1131 const char *workstation,
1132 bool password_change)
1134 TALLOC_CTX *tmp_ctx;
1137 tmp_ctx = talloc_named(NULL, 0, "samba_kdc_check_client_access");
1139 return NT_STATUS_NO_MEMORY;
1142 /* we allow all kinds of trusts here */
1143 nt_status = authsam_account_ok(tmp_ctx,
1144 kdc_entry->kdc_db_ctx->samdb,
1145 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
1146 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
1147 kdc_entry->realm_dn, kdc_entry->msg,
1148 workstation, client_name,
1149 true, password_change);
1151 kdc_entry->reject_status = nt_status;
1152 talloc_free(tmp_ctx);
1156 static krb5_error_code samba_get_requester_sid(TALLOC_CTX *mem_ctx,
1158 krb5_context context,
1159 struct dom_sid *sid)
1162 enum ndr_err_code ndr_err;
1163 krb5_error_code ret;
1165 DATA_BLOB pac_requester_sid_in;
1166 krb5_data k5pac_requester_sid_in;
1168 union PAC_INFO info;
1170 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1171 if (tmp_ctx == NULL) {
1175 ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_REQUESTER_SID,
1176 &k5pac_requester_sid_in);
1178 talloc_free(tmp_ctx);
1182 pac_requester_sid_in = data_blob_const(k5pac_requester_sid_in.data,
1183 k5pac_requester_sid_in.length);
1185 ndr_err = ndr_pull_union_blob(&pac_requester_sid_in, tmp_ctx, &info,
1186 PAC_TYPE_REQUESTER_SID,
1187 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1188 smb_krb5_free_data_contents(context, &k5pac_requester_sid_in);
1189 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1190 nt_status = ndr_map_error2ntstatus(ndr_err);
1191 DEBUG(0,("can't parse the PAC REQUESTER_SID: %s\n", nt_errstr(nt_status)));
1192 talloc_free(tmp_ctx);
1196 *sid = info.requester_sid.sid;
1198 talloc_free(tmp_ctx);
1202 /* Does a parse and SID check, but no crypto. */
1203 krb5_error_code samba_kdc_validate_pac_blob(
1204 krb5_context context,
1205 struct samba_kdc_entry *client_skdc_entry,
1208 TALLOC_CTX *frame = talloc_stackframe();
1209 struct auth_user_info_dc *pac_user_info = NULL;
1210 struct dom_sid *client_sid = NULL;
1211 struct dom_sid pac_sid;
1212 krb5_error_code code;
1216 * First, try to get the SID from the requester SID buffer in the PAC.
1218 code = samba_get_requester_sid(frame, pac, context, &pac_sid);
1220 if (code == ENOENT) {
1222 * If the requester SID buffer isn't present, fall back to the
1223 * SID in the LOGON_INFO PAC buffer.
1225 code = kerberos_pac_to_user_info_dc(frame,
1235 if (pac_user_info->num_sids == 0) {
1240 pac_sid = pac_user_info->sids[0];
1241 } else if (code != 0) {
1245 client_sid = samdb_result_dom_sid(frame,
1246 client_skdc_entry->msg,
1249 ok = dom_sid_equal(&pac_sid, client_sid);
1251 struct dom_sid_buf buf1;
1252 struct dom_sid_buf buf2;
1254 DBG_ERR("SID mismatch between PAC and looked up client: "
1255 "PAC[%s] != CLI[%s]\n",
1256 dom_sid_str_buf(&pac_sid, &buf1),
1257 dom_sid_str_buf(client_sid, &buf2));
1258 code = KRB5KDC_ERR_TGT_REVOKED;
1270 * In the RODC case, to confirm that the returned user is permitted to
1271 * be replicated to the KDC (krbgtgt_xxx user) represented by *rodc
1273 WERROR samba_rodc_confirm_user_is_allowed(uint32_t num_object_sids,
1274 struct dom_sid *object_sids,
1275 struct samba_kdc_entry *rodc,
1276 struct samba_kdc_entry *object)
1280 TALLOC_CTX *frame = talloc_stackframe();
1281 const char *rodc_attrs[] = { "msDS-KrbTgtLink",
1282 "msDS-NeverRevealGroup",
1283 "msDS-RevealOnDemandGroup",
1284 "userAccountControl",
1287 struct ldb_result *rodc_machine_account = NULL;
1288 struct ldb_dn *rodc_machine_account_dn = samdb_result_dn(rodc->kdc_db_ctx->samdb,
1291 "msDS-KrbTgtLinkBL",
1293 const struct dom_sid *rodc_machine_account_sid = NULL;
1295 if (rodc_machine_account_dn == NULL) {
1296 DBG_ERR("krbtgt account %s has no msDS-KrbTgtLinkBL to find RODC machine account for allow/deny list\n",
1297 ldb_dn_get_linearized(rodc->msg->dn));
1299 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1303 * Follow the link and get the RODC account (the krbtgt
1304 * account is the krbtgt_XXX account, but the
1305 * msDS-NeverRevealGroup and msDS-RevealOnDemandGroup is on
1306 * the RODC$ account)
1308 * We need DSDB_SEARCH_SHOW_EXTENDED_DN as we get a SID lists
1309 * out of the extended DNs
1312 ret = dsdb_search_dn(rodc->kdc_db_ctx->samdb,
1314 &rodc_machine_account,
1315 rodc_machine_account_dn,
1317 DSDB_SEARCH_SHOW_EXTENDED_DN);
1318 if (ret != LDB_SUCCESS) {
1319 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: %s\n",
1320 ldb_dn_get_linearized(rodc_machine_account_dn),
1321 ldb_dn_get_linearized(rodc->msg->dn),
1322 ldb_errstring(rodc->kdc_db_ctx->samdb));
1324 return WERR_DOMAIN_CONTROLLER_NOT_FOUND;
1327 if (rodc_machine_account->count != 1) {
1328 DBG_ERR("Failed to fetch RODC machine account %s pointed to by %s to check allow/deny list: (%d)\n",
1329 ldb_dn_get_linearized(rodc_machine_account_dn),
1330 ldb_dn_get_linearized(rodc->msg->dn),
1331 rodc_machine_account->count);
1333 return WERR_DS_DRA_BAD_DN;
1336 /* if the object SID is equal to the user_sid, allow */
1337 rodc_machine_account_sid = samdb_result_dom_sid(frame,
1338 rodc_machine_account->msgs[0],
1340 if (rodc_machine_account_sid == NULL) {
1341 return WERR_DS_DRA_BAD_DN;
1344 werr = samdb_confirm_rodc_allowed_to_repl_to_sid_list(rodc->kdc_db_ctx->samdb,
1345 rodc_machine_account_sid,
1346 rodc_machine_account->msgs[0],