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/>.
25 #include "../libds/common/flags.h"
27 #include "auth/auth.h"
28 #include "auth/auth_sam_reply.h"
29 #include "system/kerberos.h"
30 #include "auth/kerberos/kerberos.h"
31 #include "kdc/samba_kdc.h"
32 #include "kdc/pac-glue.h"
33 #include "param/param.h"
34 #include "librpc/gen_ndr/ndr_krb5pac.h"
35 #include "libcli/security/security.h"
36 #include "dsdb/samdb/samdb.h"
37 #include "auth/kerberos/pac_utils.h"
40 NTSTATUS samba_get_logon_info_pac_blob(TALLOC_CTX *mem_ctx,
41 const struct auth_user_info_dc *info,
44 struct netr_SamInfo3 *info3;
45 union PAC_INFO pac_info;
46 enum ndr_err_code ndr_err;
49 ZERO_STRUCT(pac_info);
51 *pac_data = data_blob_null;
53 nt_status = auth_convert_user_info_dc_saminfo3(mem_ctx, info, &info3);
54 if (!NT_STATUS_IS_OK(nt_status)) {
55 DEBUG(1, ("Getting Samba info failed: %s\n",
56 nt_errstr(nt_status)));
60 pac_info.logon_info.info = talloc_zero(mem_ctx, struct PAC_LOGON_INFO);
61 if (!pac_info.logon_info.info) {
62 return NT_STATUS_NO_MEMORY;
65 pac_info.logon_info.info->info3 = *info3;
67 ndr_err = ndr_push_union_blob(pac_data, mem_ctx, &pac_info,
69 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
70 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
71 nt_status = ndr_map_error2ntstatus(ndr_err);
72 DEBUG(1, ("PAC_LOGON_INFO (presig) push failed: %s\n",
73 nt_errstr(nt_status)));
81 NTSTATUS samba_get_upn_info_pac_blob(TALLOC_CTX *mem_ctx,
82 const struct auth_user_info_dc *info,
85 union PAC_INFO pac_upn;
86 enum ndr_err_code ndr_err;
91 *upn_data = data_blob_null;
93 pac_upn.upn_dns_info.upn_name = info->info->user_principal_name;
94 pac_upn.upn_dns_info.dns_domain_name = strupper_talloc(mem_ctx,
95 info->info->dns_domain_name);
96 if (pac_upn.upn_dns_info.dns_domain_name == NULL) {
97 return NT_STATUS_NO_MEMORY;
99 if (info->info->user_principal_constructed) {
100 pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED;
103 ndr_err = ndr_push_union_blob(upn_data, mem_ctx, &pac_upn,
104 PAC_TYPE_UPN_DNS_INFO,
105 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
106 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
107 nt_status = ndr_map_error2ntstatus(ndr_err);
108 DEBUG(1, ("PAC UPN_DNS_INFO (presig) push failed: %s\n",
109 nt_errstr(nt_status)));
117 NTSTATUS samba_get_pac_attrs_blob(TALLOC_CTX *mem_ctx,
118 const krb5_boolean *pac_request,
119 DATA_BLOB *pac_attrs_data)
121 union PAC_INFO pac_attrs;
122 enum ndr_err_code ndr_err;
125 ZERO_STRUCT(pac_attrs);
127 *pac_attrs_data = data_blob_null;
129 /* Set the length of the flags in bits. */
130 pac_attrs.attributes_info.flags_length = 2;
132 if (pac_request == NULL) {
133 pac_attrs.attributes_info.flags
134 |= PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY;
135 } else if (*pac_request) {
136 pac_attrs.attributes_info.flags
137 |= PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED;
140 ndr_err = ndr_push_union_blob(pac_attrs_data, mem_ctx, &pac_attrs,
141 PAC_TYPE_ATTRIBUTES_INFO,
142 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
143 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
144 nt_status = ndr_map_error2ntstatus(ndr_err);
145 DEBUG(1, ("PAC ATTRIBUTES_INFO (presig) push failed: %s\n",
146 nt_errstr(nt_status)));
154 NTSTATUS samba_get_cred_info_ndr_blob(TALLOC_CTX *mem_ctx,
155 const struct ldb_message *msg,
156 DATA_BLOB *cred_blob)
158 enum ndr_err_code ndr_err;
160 struct samr_Password *lm_hash = NULL;
161 struct samr_Password *nt_hash = NULL;
162 struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg = {
165 DATA_BLOB ntlm_blob = data_blob_null;
166 struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs[1] = {{
167 .credential_size = 0,
169 struct PAC_CREDENTIAL_DATA cred_data = {
170 .credential_count = 0,
172 struct PAC_CREDENTIAL_DATA_NDR cred_ndr;
174 ZERO_STRUCT(cred_ndr);
176 *cred_blob = data_blob_null;
178 lm_hash = samdb_result_hash(mem_ctx, msg, "dBCSPwd");
179 if (lm_hash != NULL) {
180 bool zero = all_zero(lm_hash->hash, 16);
185 if (lm_hash != NULL) {
186 DEBUG(5, ("Passing LM password hash through credentials set\n"));
187 ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_LM_HASH;
188 ntlm_secpkg.lm_password = *lm_hash;
189 ZERO_STRUCTP(lm_hash);
190 TALLOC_FREE(lm_hash);
193 nt_hash = samdb_result_hash(mem_ctx, msg, "unicodePwd");
194 if (nt_hash != NULL) {
195 bool zero = all_zero(nt_hash->hash, 16);
200 if (nt_hash != NULL) {
201 DEBUG(5, ("Passing LM password hash through credentials set\n"));
202 ntlm_secpkg.flags |= PAC_CREDENTIAL_NTLM_HAS_NT_HASH;
203 ntlm_secpkg.nt_password = *nt_hash;
204 ZERO_STRUCTP(nt_hash);
205 TALLOC_FREE(nt_hash);
208 if (ntlm_secpkg.flags == 0) {
212 #ifdef DEBUG_PASSWORD
214 NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG, &ntlm_secpkg);
218 ndr_err = ndr_push_struct_blob(&ntlm_blob, mem_ctx, &ntlm_secpkg,
219 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG);
220 ZERO_STRUCT(ntlm_secpkg);
221 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
222 nt_status = ndr_map_error2ntstatus(ndr_err);
223 DEBUG(1, ("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
224 nt_errstr(nt_status)));
228 DEBUG(10, ("NTLM credential BLOB (len %zu) for user\n",
230 dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
231 ntlm_blob.data, ntlm_blob.length);
233 secpkgs[0].package_name.string = discard_const_p(char, "NTLM");
234 secpkgs[0].credential_size = ntlm_blob.length;
235 secpkgs[0].credential = ntlm_blob.data;
237 cred_data.credential_count = ARRAY_SIZE(secpkgs);
238 cred_data.credentials = secpkgs;
240 #ifdef DEBUG_PASSWORD
242 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA, &cred_data);
246 cred_ndr.ctr.data = &cred_data;
248 #ifdef DEBUG_PASSWORD
250 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR, &cred_ndr);
254 ndr_err = ndr_push_struct_blob(cred_blob, mem_ctx, &cred_ndr,
255 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_DATA_NDR);
256 data_blob_clear(&ntlm_blob);
257 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
258 nt_status = ndr_map_error2ntstatus(ndr_err);
259 DEBUG(1, ("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
260 nt_errstr(nt_status)));
264 DEBUG(10, ("Created credential BLOB (len %zu) for user\n",
266 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
267 cred_blob->data, cred_blob->length);
272 #ifdef SAMBA4_USES_HEIMDAL
273 krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
274 const krb5_keyblock *pkreplykey,
275 const DATA_BLOB *cred_ndr_blob,
277 DATA_BLOB *cred_info_blob)
279 krb5_crypto cred_crypto;
280 krb5_enctype cred_enctype;
281 krb5_data cred_ndr_crypt;
282 struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
285 enum ndr_err_code ndr_err;
288 *cred_info_blob = data_blob_null;
290 ret = krb5_crypto_init(context, pkreplykey, ETYPE_NULL,
293 krb5err = krb5_get_error_message(context, ret);
294 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
295 krb5_free_error_message(context, krb5err);
299 ret = krb5_crypto_getenctype(context, cred_crypto, &cred_enctype);
301 DEBUG(1, ("Failed getting crypto type for key\n"));
302 krb5_crypto_destroy(context, cred_crypto);
306 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
307 cred_ndr_blob->length));
308 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
309 cred_ndr_blob->data, cred_ndr_blob->length);
311 ret = krb5_encrypt(context, cred_crypto,
312 KRB5_KU_OTHER_ENCRYPTED,
313 cred_ndr_blob->data, cred_ndr_blob->length,
315 krb5_crypto_destroy(context, cred_crypto);
317 krb5err = krb5_get_error_message(context, ret);
318 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err));
319 krb5_free_error_message(context, krb5err);
323 pac_cred_info.encryption_type = cred_enctype;
324 pac_cred_info.encrypted_data.length = cred_ndr_crypt.length;
325 pac_cred_info.encrypted_data.data = (uint8_t *)cred_ndr_crypt.data;
328 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
331 ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
332 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
333 krb5_data_free(&cred_ndr_crypt);
334 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
335 nt_status = ndr_map_error2ntstatus(ndr_err);
336 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
337 nt_errstr(nt_status)));
338 return KRB5KDC_ERR_SVC_UNAVAILABLE;
341 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
342 cred_info_blob->length, (int)pac_cred_info.encryption_type));
343 dump_data_pw("PAC_CREDENTIAL_INFO",
344 cred_info_blob->data, cred_info_blob->length);
348 #else /* SAMBA4_USES_HEIMDAL */
349 krb5_error_code samba_kdc_encrypt_pac_credentials(krb5_context context,
350 const krb5_keyblock *pkreplykey,
351 const DATA_BLOB *cred_ndr_blob,
353 DATA_BLOB *cred_info_blob)
356 krb5_enctype cred_enctype;
357 struct PAC_CREDENTIAL_INFO pac_cred_info = { .version = 0, };
358 krb5_error_code code;
360 enum ndr_err_code ndr_err;
362 krb5_data cred_ndr_data;
363 krb5_enc_data cred_ndr_crypt;
366 *cred_info_blob = data_blob_null;
368 code = krb5_k_create_key(context,
372 krb5err = krb5_get_error_message(context, code);
373 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
374 krb5_free_error_message(context, krb5err);
378 cred_enctype = krb5_k_key_enctype(context, cred_key);
380 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
381 cred_ndr_blob->length));
382 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
383 cred_ndr_blob->data, cred_ndr_blob->length);
385 pac_cred_info.encryption_type = cred_enctype;
387 cred_ndr_data.magic = 0;
388 cred_ndr_data.data = (char *)cred_ndr_blob->data;
389 cred_ndr_data.length = cred_ndr_blob->length;
391 code = krb5_c_encrypt_length(context,
393 cred_ndr_data.length,
396 krb5err = krb5_get_error_message(context, code);
397 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err));
398 krb5_free_error_message(context, krb5err);
402 pac_cred_info.encrypted_data = data_blob_talloc_zero(mem_ctx, enc_len);
403 if (pac_cred_info.encrypted_data.data == NULL) {
404 DBG_ERR("Out of memory\n");
408 cred_ndr_crypt.ciphertext.length = enc_len;
409 cred_ndr_crypt.ciphertext.data = (char *)pac_cred_info.encrypted_data.data;
411 code = krb5_k_encrypt(context,
413 KRB5_KU_OTHER_ENCRYPTED,
417 krb5_k_free_key(context, cred_key);
419 krb5err = krb5_get_error_message(context, code);
420 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err));
421 krb5_free_error_message(context, krb5err);
426 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO, &pac_cred_info);
429 ndr_err = ndr_push_struct_blob(cred_info_blob, mem_ctx, &pac_cred_info,
430 (ndr_push_flags_fn_t)ndr_push_PAC_CREDENTIAL_INFO);
431 TALLOC_FREE(pac_cred_info.encrypted_data.data);
432 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
433 nt_status = ndr_map_error2ntstatus(ndr_err);
434 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
435 nt_errstr(nt_status)));
436 return KRB5KDC_ERR_SVC_UNAVAILABLE;
439 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
440 cred_info_blob->length, (int)pac_cred_info.encryption_type));
441 dump_data_pw("PAC_CREDENTIAL_INFO",
442 cred_info_blob->data, cred_info_blob->length);
446 #endif /* SAMBA4_USES_HEIMDAL */
449 krb5_error_code samba_make_krb5_pac(krb5_context context,
450 const DATA_BLOB *logon_blob,
451 const DATA_BLOB *cred_blob,
452 const DATA_BLOB *upn_blob,
453 const DATA_BLOB *pac_attrs_blob,
454 const DATA_BLOB *deleg_blob,
457 krb5_data logon_data;
460 krb5_data pac_attrs_data;
461 krb5_data deleg_data;
463 #ifdef SAMBA4_USES_HEIMDAL
464 krb5_data null_data = {
470 /* The user account may be set not to want the PAC */
471 if (logon_blob == NULL) {
475 ret = smb_krb5_copy_data_contents(&logon_data,
482 ZERO_STRUCT(cred_data);
483 if (cred_blob != NULL) {
484 ret = smb_krb5_copy_data_contents(&cred_data,
488 smb_krb5_free_data_contents(context, &logon_data);
493 ZERO_STRUCT(upn_data);
494 if (upn_blob != NULL) {
495 ret = smb_krb5_copy_data_contents(&upn_data,
499 smb_krb5_free_data_contents(context, &logon_data);
500 smb_krb5_free_data_contents(context, &cred_data);
505 ZERO_STRUCT(pac_attrs_data);
506 if (pac_attrs_blob != NULL) {
507 ret = smb_krb5_copy_data_contents(&pac_attrs_data,
508 pac_attrs_blob->data,
509 pac_attrs_blob->length);
511 smb_krb5_free_data_contents(context, &logon_data);
512 smb_krb5_free_data_contents(context, &cred_data);
513 smb_krb5_free_data_contents(context, &upn_data);
518 ZERO_STRUCT(deleg_data);
519 if (deleg_blob != NULL) {
520 ret = smb_krb5_copy_data_contents(&deleg_data,
524 smb_krb5_free_data_contents(context, &logon_data);
525 smb_krb5_free_data_contents(context, &cred_data);
526 smb_krb5_free_data_contents(context, &upn_data);
527 smb_krb5_free_data_contents(context, &pac_attrs_data);
532 ret = krb5_pac_init(context, pac);
534 smb_krb5_free_data_contents(context, &logon_data);
535 smb_krb5_free_data_contents(context, &cred_data);
536 smb_krb5_free_data_contents(context, &upn_data);
537 smb_krb5_free_data_contents(context, &pac_attrs_data);
538 smb_krb5_free_data_contents(context, &deleg_data);
542 ret = krb5_pac_add_buffer(context, *pac, PAC_TYPE_LOGON_INFO, &logon_data);
543 smb_krb5_free_data_contents(context, &logon_data);
545 smb_krb5_free_data_contents(context, &cred_data);
546 smb_krb5_free_data_contents(context, &upn_data);
547 smb_krb5_free_data_contents(context, &pac_attrs_data);
548 smb_krb5_free_data_contents(context, &deleg_data);
552 if (cred_blob != NULL) {
553 ret = krb5_pac_add_buffer(context, *pac,
554 PAC_TYPE_CREDENTIAL_INFO,
556 smb_krb5_free_data_contents(context, &cred_data);
558 smb_krb5_free_data_contents(context, &upn_data);
559 smb_krb5_free_data_contents(context, &pac_attrs_data);
560 smb_krb5_free_data_contents(context, &deleg_data);
565 #ifdef SAMBA4_USES_HEIMDAL
567 * null_data will be filled by the generic KDC code in the caller
568 * here we just add it in order to have it before
569 * PAC_TYPE_UPN_DNS_INFO
571 * Not needed with MIT Kerberos - asn
573 ret = krb5_pac_add_buffer(context, *pac,
577 smb_krb5_free_data_contents(context, &upn_data);
578 smb_krb5_free_data_contents(context, &pac_attrs_data);
579 smb_krb5_free_data_contents(context, &deleg_data);
584 if (upn_blob != NULL) {
585 ret = krb5_pac_add_buffer(context, *pac,
586 PAC_TYPE_UPN_DNS_INFO,
588 smb_krb5_free_data_contents(context, &upn_data);
590 smb_krb5_free_data_contents(context, &pac_attrs_data);
591 smb_krb5_free_data_contents(context, &deleg_data);
596 if (pac_attrs_blob != NULL) {
597 ret = krb5_pac_add_buffer(context, *pac,
598 PAC_TYPE_ATTRIBUTES_INFO,
600 smb_krb5_free_data_contents(context, &pac_attrs_data);
602 smb_krb5_free_data_contents(context, &deleg_data);
607 if (deleg_blob != NULL) {
608 ret = krb5_pac_add_buffer(context, *pac,
609 PAC_TYPE_CONSTRAINED_DELEGATION,
611 smb_krb5_free_data_contents(context, &deleg_data);
620 bool samba_princ_needs_pac(struct samba_kdc_entry *skdc_entry)
623 uint32_t userAccountControl;
625 /* The service account may be set not to want the PAC */
626 userAccountControl = ldb_msg_find_attr_as_uint(skdc_entry->msg, "userAccountControl", 0);
627 if (userAccountControl & UF_NO_AUTH_DATA_REQUIRED) {
634 int samba_client_requested_pac(krb5_context context,
639 enum ndr_err_code ndr_err;
640 krb5_data k5pac_attrs_in;
641 DATA_BLOB pac_attrs_in;
642 union PAC_INFO pac_attrs;
645 *requested_pac = true;
647 ret = krb5_pac_get_buffer(context, *pac, PAC_TYPE_ATTRIBUTES_INFO,
650 return ret == ENOENT ? 0 : ret;
653 pac_attrs_in = data_blob_const(k5pac_attrs_in.data,
654 k5pac_attrs_in.length);
656 ndr_err = ndr_pull_union_blob(&pac_attrs_in, mem_ctx, &pac_attrs,
657 PAC_TYPE_ATTRIBUTES_INFO,
658 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
659 smb_krb5_free_data_contents(context, &k5pac_attrs_in);
660 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
661 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
662 DEBUG(0,("can't parse the PAC ATTRIBUTES_INFO: %s\n", nt_errstr(nt_status)));
666 if (pac_attrs.attributes_info.flags & (PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY
667 | PAC_ATTRIBUTE_FLAG_PAC_WAS_REQUESTED)) {
668 *requested_pac = true;
670 *requested_pac = false;
676 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
677 int samba_krbtgt_is_in_db(struct samba_kdc_entry *p,
682 int rodc_krbtgt_number, trust_direction;
685 TALLOC_CTX *mem_ctx = talloc_new(NULL);
690 trust_direction = ldb_msg_find_attr_as_int(p->msg, "trustDirection", 0);
692 if (trust_direction != 0) {
693 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
695 This is exactly where we should flag for SID
696 validation when we do inter-foreest trusts
698 talloc_free(mem_ctx);
699 *is_untrusted = false;
704 /* The lack of password controls etc applies to krbtgt by
705 * virtue of being that particular RID */
706 status = dom_sid_split_rid(NULL, samdb_result_dom_sid(mem_ctx, p->msg, "objectSid"), NULL, &rid);
708 if (!NT_STATUS_IS_OK(status)) {
709 talloc_free(mem_ctx);
713 rodc_krbtgt_number = ldb_msg_find_attr_as_int(p->msg, "msDS-SecondaryKrbTgtNumber", -1);
715 if (p->kdc_db_ctx->my_krbtgt_number == 0) {
716 if (rid == DOMAIN_RID_KRBTGT) {
717 *is_untrusted = false;
719 talloc_free(mem_ctx);
721 } else if (rodc_krbtgt_number != -1) {
723 *is_untrusted = true;
724 talloc_free(mem_ctx);
727 } else if ((rid != DOMAIN_RID_KRBTGT) && (rodc_krbtgt_number == p->kdc_db_ctx->my_krbtgt_number)) {
728 talloc_free(mem_ctx);
729 *is_untrusted = false;
732 } else if (rid == DOMAIN_RID_KRBTGT) {
733 /* krbtgt viewed from an RODC */
734 talloc_free(mem_ctx);
735 *is_untrusted = false;
741 talloc_free(mem_ctx);
742 *is_untrusted = true;
747 NTSTATUS samba_kdc_get_pac_blobs(TALLOC_CTX *mem_ctx,
748 struct samba_kdc_entry *p,
749 DATA_BLOB **_logon_info_blob,
750 DATA_BLOB **_cred_ndr_blob,
751 DATA_BLOB **_upn_info_blob,
752 DATA_BLOB **_pac_attrs_blob,
753 const krb5_boolean *pac_request)
755 struct auth_user_info_dc *user_info_dc;
756 DATA_BLOB *logon_blob = NULL;
757 DATA_BLOB *cred_blob = NULL;
758 DATA_BLOB *upn_blob = NULL;
759 DATA_BLOB *pac_attrs_blob = NULL;
762 *_logon_info_blob = NULL;
763 if (_cred_ndr_blob != NULL) {
764 *_cred_ndr_blob = NULL;
766 *_upn_info_blob = NULL;
767 if (_pac_attrs_blob != NULL) {
768 *_pac_attrs_blob = NULL;
771 logon_blob = talloc_zero(mem_ctx, DATA_BLOB);
772 if (logon_blob == NULL) {
773 return NT_STATUS_NO_MEMORY;
776 if (_cred_ndr_blob != NULL) {
777 cred_blob = talloc_zero(mem_ctx, DATA_BLOB);
778 if (cred_blob == NULL) {
779 return NT_STATUS_NO_MEMORY;
783 upn_blob = talloc_zero(mem_ctx, DATA_BLOB);
784 if (upn_blob == NULL) {
785 return NT_STATUS_NO_MEMORY;
788 if (_pac_attrs_blob != NULL) {
789 pac_attrs_blob = talloc_zero(mem_ctx, DATA_BLOB);
790 if (pac_attrs_blob == NULL) {
791 return NT_STATUS_NO_MEMORY;
795 nt_status = authsam_make_user_info_dc(mem_ctx, p->kdc_db_ctx->samdb,
796 lpcfg_netbios_name(p->kdc_db_ctx->lp_ctx),
797 lpcfg_sam_name(p->kdc_db_ctx->lp_ctx),
798 lpcfg_sam_dnsname(p->kdc_db_ctx->lp_ctx),
804 if (!NT_STATUS_IS_OK(nt_status)) {
805 DEBUG(0, ("Getting user info for PAC failed: %s\n",
806 nt_errstr(nt_status)));
810 nt_status = samba_get_logon_info_pac_blob(logon_blob,
813 if (!NT_STATUS_IS_OK(nt_status)) {
814 DEBUG(0, ("Building PAC LOGON INFO failed: %s\n",
815 nt_errstr(nt_status)));
819 if (cred_blob != NULL) {
820 nt_status = samba_get_cred_info_ndr_blob(cred_blob,
823 if (!NT_STATUS_IS_OK(nt_status)) {
824 DEBUG(0, ("Building PAC CRED INFO failed: %s\n",
825 nt_errstr(nt_status)));
830 nt_status = samba_get_upn_info_pac_blob(upn_blob,
833 if (!NT_STATUS_IS_OK(nt_status)) {
834 DEBUG(0, ("Building PAC UPN INFO failed: %s\n",
835 nt_errstr(nt_status)));
839 if (pac_attrs_blob != NULL) {
840 nt_status = samba_get_pac_attrs_blob(pac_attrs_blob,
844 if (!NT_STATUS_IS_OK(nt_status)) {
845 DEBUG(0, ("Building PAC ATTRIBUTES failed: %s\n",
846 nt_errstr(nt_status)));
851 TALLOC_FREE(user_info_dc);
852 *_logon_info_blob = logon_blob;
853 if (_cred_ndr_blob != NULL) {
854 *_cred_ndr_blob = cred_blob;
856 *_upn_info_blob = upn_blob;
857 if (_pac_attrs_blob != NULL) {
858 *_pac_attrs_blob = pac_attrs_blob;
863 NTSTATUS samba_kdc_get_pac_blob(TALLOC_CTX *mem_ctx,
864 struct samba_kdc_entry *p,
865 DATA_BLOB **_logon_info_blob)
868 DATA_BLOB *upn_blob = NULL;
870 nt_status = samba_kdc_get_pac_blobs(mem_ctx, p,
872 NULL, /* cred_blob */
876 if (!NT_STATUS_IS_OK(nt_status)) {
880 TALLOC_FREE(upn_blob);
884 NTSTATUS samba_kdc_update_pac_blob(TALLOC_CTX *mem_ctx,
885 krb5_context context,
886 struct ldb_context *samdb,
887 const krb5_pac pac, DATA_BLOB *pac_blob,
888 struct PAC_SIGNATURE_DATA *pac_srv_sig,
889 struct PAC_SIGNATURE_DATA *pac_kdc_sig)
891 struct auth_user_info_dc *user_info_dc;
895 ret = kerberos_pac_to_user_info_dc(mem_ctx, pac,
896 context, &user_info_dc, pac_srv_sig, pac_kdc_sig);
898 return NT_STATUS_UNSUCCESSFUL;
902 * We need to expand group memberships within our local domain,
903 * as the token might be generated by a trusted domain.
905 nt_status = authsam_update_user_info_dc(mem_ctx,
908 if (!NT_STATUS_IS_OK(nt_status)) {
912 nt_status = samba_get_logon_info_pac_blob(mem_ctx,
913 user_info_dc, pac_blob);
918 NTSTATUS samba_kdc_update_delegation_info_blob(TALLOC_CTX *mem_ctx,
919 krb5_context context,
921 const krb5_principal server_principal,
922 const krb5_principal proxy_principal,
929 enum ndr_err_code ndr_err;
931 struct PAC_CONSTRAINED_DELEGATION _d;
932 struct PAC_CONSTRAINED_DELEGATION *d = NULL;
936 TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
938 if (tmp_ctx == NULL) {
939 return NT_STATUS_NO_MEMORY;
942 ret = krb5_pac_get_buffer(context, pac, PAC_TYPE_CONSTRAINED_DELEGATION, &old_data);
944 ZERO_STRUCT(old_data);
946 talloc_free(tmp_ctx);
947 return NT_STATUS_UNSUCCESSFUL;
950 old_blob.length = old_data.length;
951 old_blob.data = (uint8_t *)old_data.data;
954 if (old_blob.length > 0) {
955 ndr_err = ndr_pull_union_blob(&old_blob, mem_ctx,
956 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
957 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
958 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
959 smb_krb5_free_data_contents(context, &old_data);
960 nt_status = ndr_map_error2ntstatus(ndr_err);
961 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
962 talloc_free(tmp_ctx);
967 info.constrained_delegation.info = &_d;
969 smb_krb5_free_data_contents(context, &old_data);
971 ret = krb5_unparse_name_flags(context, server_principal,
972 KRB5_PRINCIPAL_UNPARSE_NO_REALM, &server);
974 talloc_free(tmp_ctx);
975 return NT_STATUS_INTERNAL_ERROR;
978 ret = krb5_unparse_name(context, proxy_principal, &proxy);
981 talloc_free(tmp_ctx);
982 return NT_STATUS_INTERNAL_ERROR;
985 d = info.constrained_delegation.info;
986 i = d->num_transited_services;
987 d->proxy_target.string = server;
988 d->transited_services = talloc_realloc(mem_ctx, d->transited_services,
989 struct lsa_String, i + 1);
990 d->transited_services[i].string = proxy;
991 d->num_transited_services = i + 1;
993 ndr_err = ndr_push_union_blob(new_blob, mem_ctx,
994 &info, PAC_TYPE_CONSTRAINED_DELEGATION,
995 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
998 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
999 smb_krb5_free_data_contents(context, &old_data);
1000 nt_status = ndr_map_error2ntstatus(ndr_err);
1001 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status)));
1002 talloc_free(tmp_ctx);
1006 talloc_free(tmp_ctx);
1007 return NT_STATUS_OK;
1010 /* function to map policy errors */
1011 krb5_error_code samba_kdc_map_policy_err(NTSTATUS nt_status)
1013 krb5_error_code ret;
1015 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_MUST_CHANGE))
1016 ret = KRB5KDC_ERR_KEY_EXP;
1017 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_PASSWORD_EXPIRED))
1018 ret = KRB5KDC_ERR_KEY_EXP;
1019 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_EXPIRED))
1020 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1021 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_DISABLED))
1022 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1023 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_LOGON_HOURS))
1024 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1025 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCOUNT_LOCKED_OUT))
1026 ret = KRB5KDC_ERR_CLIENT_REVOKED;
1027 else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_INVALID_WORKSTATION))
1028 ret = KRB5KDC_ERR_POLICY;
1030 ret = KRB5KDC_ERR_POLICY;
1035 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
1036 * for consistency */
1037 NTSTATUS samba_kdc_check_client_access(struct samba_kdc_entry *kdc_entry,
1038 const char *client_name,
1039 const char *workstation,
1040 bool password_change)
1042 TALLOC_CTX *tmp_ctx;
1045 tmp_ctx = talloc_named(NULL, 0, "samba_kdc_check_client_access");
1047 return NT_STATUS_NO_MEMORY;
1050 /* we allow all kinds of trusts here */
1051 nt_status = authsam_account_ok(tmp_ctx,
1052 kdc_entry->kdc_db_ctx->samdb,
1053 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
1054 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT,
1055 kdc_entry->realm_dn, kdc_entry->msg,
1056 workstation, client_name,
1057 true, password_change);
1059 talloc_free(tmp_ctx);
1063 /* Does a parse and SID check, but no crypto. */
1064 krb5_error_code samba_kdc_validate_pac_blob(
1065 krb5_context context,
1066 struct samba_kdc_entry *client_skdc_entry,
1069 TALLOC_CTX *frame = talloc_stackframe();
1070 struct auth_user_info_dc *pac_user_info = NULL;
1071 struct dom_sid *client_sid = NULL;
1072 struct dom_sid pac_sid;
1073 krb5_error_code code;
1076 code = kerberos_pac_to_user_info_dc(frame,
1086 if (pac_user_info->num_sids == 0) {
1091 pac_sid = pac_user_info->sids[0];
1092 client_sid = samdb_result_dom_sid(frame,
1093 client_skdc_entry->msg,
1096 ok = dom_sid_equal(&pac_sid, client_sid);
1098 struct dom_sid_buf buf1;
1099 struct dom_sid_buf buf2;
1101 DBG_ERR("SID mismatch between PAC and looked up client: "
1102 "PAC[%s] != CLI[%s]\n",
1103 dom_sid_str_buf(&pac_sid, &buf1),
1104 dom_sid_str_buf(client_sid, &buf2));
1105 #if defined(KRB5KDC_ERR_CLIENT_NAME_MISMATCH) /* MIT */
1106 code = KRB5KDC_ERR_CLIENT_NAME_MISMATCH;
1107 #else /* Heimdal (where this is an enum) */
1108 code = KRB5_KDC_ERR_CLIENT_NAME_MISMATCH;