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_cred_info_ndr_blob(TALLOC_CTX
*mem_ctx
,
118 const struct ldb_message
*msg
,
119 DATA_BLOB
*cred_blob
)
121 enum ndr_err_code ndr_err
;
123 struct samr_Password
*lm_hash
= NULL
;
124 struct samr_Password
*nt_hash
= NULL
;
125 struct PAC_CREDENTIAL_NTLM_SECPKG ntlm_secpkg
= {
128 DATA_BLOB ntlm_blob
= data_blob_null
;
129 struct PAC_CREDENTIAL_SUPPLEMENTAL_SECPKG secpkgs
[1] = {{
130 .credential_size
= 0,
132 struct PAC_CREDENTIAL_DATA cred_data
= {
133 .credential_count
= 0,
135 struct PAC_CREDENTIAL_DATA_NDR cred_ndr
;
137 ZERO_STRUCT(cred_ndr
);
139 *cred_blob
= data_blob_null
;
141 lm_hash
= samdb_result_hash(mem_ctx
, msg
, "dBCSPwd");
142 if (lm_hash
!= NULL
) {
143 bool zero
= all_zero(lm_hash
->hash
, 16);
148 if (lm_hash
!= NULL
) {
149 DEBUG(5, ("Passing LM password hash through credentials set\n"));
150 ntlm_secpkg
.flags
|= PAC_CREDENTIAL_NTLM_HAS_LM_HASH
;
151 ntlm_secpkg
.lm_password
= *lm_hash
;
152 ZERO_STRUCTP(lm_hash
);
153 TALLOC_FREE(lm_hash
);
156 nt_hash
= samdb_result_hash(mem_ctx
, msg
, "unicodePwd");
157 if (nt_hash
!= NULL
) {
158 bool zero
= all_zero(nt_hash
->hash
, 16);
163 if (nt_hash
!= NULL
) {
164 DEBUG(5, ("Passing LM password hash through credentials set\n"));
165 ntlm_secpkg
.flags
|= PAC_CREDENTIAL_NTLM_HAS_NT_HASH
;
166 ntlm_secpkg
.nt_password
= *nt_hash
;
167 ZERO_STRUCTP(nt_hash
);
168 TALLOC_FREE(nt_hash
);
171 if (ntlm_secpkg
.flags
== 0) {
175 #ifdef DEBUG_PASSWORD
177 NDR_PRINT_DEBUG(PAC_CREDENTIAL_NTLM_SECPKG
, &ntlm_secpkg
);
181 ndr_err
= ndr_push_struct_blob(&ntlm_blob
, mem_ctx
, &ntlm_secpkg
,
182 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_NTLM_SECPKG
);
183 ZERO_STRUCT(ntlm_secpkg
);
184 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
185 nt_status
= ndr_map_error2ntstatus(ndr_err
);
186 DEBUG(1, ("PAC_CREDENTIAL_NTLM_SECPKG (presig) push failed: %s\n",
187 nt_errstr(nt_status
)));
191 DEBUG(10, ("NTLM credential BLOB (len %zu) for user\n",
193 dump_data_pw("PAC_CREDENTIAL_NTLM_SECPKG",
194 ntlm_blob
.data
, ntlm_blob
.length
);
196 secpkgs
[0].package_name
.string
= discard_const_p(char, "NTLM");
197 secpkgs
[0].credential_size
= ntlm_blob
.length
;
198 secpkgs
[0].credential
= ntlm_blob
.data
;
200 cred_data
.credential_count
= ARRAY_SIZE(secpkgs
);
201 cred_data
.credentials
= secpkgs
;
203 #ifdef DEBUG_PASSWORD
205 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA
, &cred_data
);
209 cred_ndr
.ctr
.data
= &cred_data
;
211 #ifdef DEBUG_PASSWORD
213 NDR_PRINT_DEBUG(PAC_CREDENTIAL_DATA_NDR
, &cred_ndr
);
217 ndr_err
= ndr_push_struct_blob(cred_blob
, mem_ctx
, &cred_ndr
,
218 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_DATA_NDR
);
219 data_blob_clear(&ntlm_blob
);
220 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
221 nt_status
= ndr_map_error2ntstatus(ndr_err
);
222 DEBUG(1, ("PAC_CREDENTIAL_DATA_NDR (presig) push failed: %s\n",
223 nt_errstr(nt_status
)));
227 DEBUG(10, ("Created credential BLOB (len %zu) for user\n",
229 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
230 cred_blob
->data
, cred_blob
->length
);
235 #ifdef SAMBA4_USES_HEIMDAL
236 krb5_error_code
samba_kdc_encrypt_pac_credentials(krb5_context context
,
237 const krb5_keyblock
*pkreplykey
,
238 const DATA_BLOB
*cred_ndr_blob
,
240 DATA_BLOB
*cred_info_blob
)
242 krb5_crypto cred_crypto
;
243 krb5_enctype cred_enctype
;
244 krb5_data cred_ndr_crypt
;
245 struct PAC_CREDENTIAL_INFO pac_cred_info
= { .version
= 0, };
248 enum ndr_err_code ndr_err
;
251 *cred_info_blob
= data_blob_null
;
253 ret
= krb5_crypto_init(context
, pkreplykey
, ETYPE_NULL
,
256 krb5err
= krb5_get_error_message(context
, ret
);
257 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err
));
258 krb5_free_error_message(context
, krb5err
);
262 ret
= krb5_crypto_getenctype(context
, cred_crypto
, &cred_enctype
);
264 DEBUG(1, ("Failed getting crypto type for key\n"));
265 krb5_crypto_destroy(context
, cred_crypto
);
269 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
270 cred_ndr_blob
->length
));
271 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
272 cred_ndr_blob
->data
, cred_ndr_blob
->length
);
274 ret
= krb5_encrypt(context
, cred_crypto
,
275 KRB5_KU_OTHER_ENCRYPTED
,
276 cred_ndr_blob
->data
, cred_ndr_blob
->length
,
278 krb5_crypto_destroy(context
, cred_crypto
);
280 krb5err
= krb5_get_error_message(context
, ret
);
281 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err
));
282 krb5_free_error_message(context
, krb5err
);
286 pac_cred_info
.encryption_type
= cred_enctype
;
287 pac_cred_info
.encrypted_data
.length
= cred_ndr_crypt
.length
;
288 pac_cred_info
.encrypted_data
.data
= (uint8_t *)cred_ndr_crypt
.data
;
291 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO
, &pac_cred_info
);
294 ndr_err
= ndr_push_struct_blob(cred_info_blob
, mem_ctx
, &pac_cred_info
,
295 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_INFO
);
296 krb5_data_free(&cred_ndr_crypt
);
297 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
298 nt_status
= ndr_map_error2ntstatus(ndr_err
);
299 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
300 nt_errstr(nt_status
)));
301 return KRB5KDC_ERR_SVC_UNAVAILABLE
;
304 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
305 cred_info_blob
->length
, (int)pac_cred_info
.encryption_type
));
306 dump_data_pw("PAC_CREDENTIAL_INFO",
307 cred_info_blob
->data
, cred_info_blob
->length
);
311 #else /* SAMBA4_USES_HEIMDAL */
312 krb5_error_code
samba_kdc_encrypt_pac_credentials(krb5_context context
,
313 const krb5_keyblock
*pkreplykey
,
314 const DATA_BLOB
*cred_ndr_blob
,
316 DATA_BLOB
*cred_info_blob
)
319 krb5_enctype cred_enctype
;
320 struct PAC_CREDENTIAL_INFO pac_cred_info
= { .version
= 0, };
321 krb5_error_code code
;
323 enum ndr_err_code ndr_err
;
325 krb5_data cred_ndr_data
;
326 krb5_enc_data cred_ndr_crypt
;
329 *cred_info_blob
= data_blob_null
;
331 code
= krb5_k_create_key(context
,
335 krb5err
= krb5_get_error_message(context
, code
);
336 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err
));
337 krb5_free_error_message(context
, krb5err
);
341 cred_enctype
= krb5_k_key_enctype(context
, cred_key
);
343 DEBUG(10, ("Plain cred_ndr_blob (len %zu)\n",
344 cred_ndr_blob
->length
));
345 dump_data_pw("PAC_CREDENTIAL_DATA_NDR",
346 cred_ndr_blob
->data
, cred_ndr_blob
->length
);
348 pac_cred_info
.encryption_type
= cred_enctype
;
350 cred_ndr_data
.magic
= 0;
351 cred_ndr_data
.data
= (char *)cred_ndr_blob
->data
;
352 cred_ndr_data
.length
= cred_ndr_blob
->length
;
354 code
= krb5_c_encrypt_length(context
,
356 cred_ndr_data
.length
,
359 krb5err
= krb5_get_error_message(context
, code
);
360 DEBUG(1, ("Failed initializing cred data crypto: %s\n", krb5err
));
361 krb5_free_error_message(context
, krb5err
);
365 pac_cred_info
.encrypted_data
= data_blob_talloc_zero(mem_ctx
, enc_len
);
366 if (pac_cred_info
.encrypted_data
.data
== NULL
) {
367 DBG_ERR("Out of memory\n");
371 cred_ndr_crypt
.ciphertext
.length
= enc_len
;
372 cred_ndr_crypt
.ciphertext
.data
= (char *)pac_cred_info
.encrypted_data
.data
;
374 code
= krb5_k_encrypt(context
,
376 KRB5_KU_OTHER_ENCRYPTED
,
380 krb5_k_free_key(context
, cred_key
);
382 krb5err
= krb5_get_error_message(context
, code
);
383 DEBUG(1, ("Failed crypt of cred data: %s\n", krb5err
));
384 krb5_free_error_message(context
, krb5err
);
389 NDR_PRINT_DEBUG(PAC_CREDENTIAL_INFO
, &pac_cred_info
);
392 ndr_err
= ndr_push_struct_blob(cred_info_blob
, mem_ctx
, &pac_cred_info
,
393 (ndr_push_flags_fn_t
)ndr_push_PAC_CREDENTIAL_INFO
);
394 TALLOC_FREE(pac_cred_info
.encrypted_data
.data
);
395 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
396 nt_status
= ndr_map_error2ntstatus(ndr_err
);
397 DEBUG(1, ("PAC_CREDENTIAL_INFO (presig) push failed: %s\n",
398 nt_errstr(nt_status
)));
399 return KRB5KDC_ERR_SVC_UNAVAILABLE
;
402 DEBUG(10, ("Encrypted credential BLOB (len %zu) with alg %d\n",
403 cred_info_blob
->length
, (int)pac_cred_info
.encryption_type
));
404 dump_data_pw("PAC_CREDENTIAL_INFO",
405 cred_info_blob
->data
, cred_info_blob
->length
);
409 #endif /* SAMBA4_USES_HEIMDAL */
412 krb5_error_code
samba_make_krb5_pac(krb5_context context
,
413 const DATA_BLOB
*logon_blob
,
414 const DATA_BLOB
*cred_blob
,
415 const DATA_BLOB
*upn_blob
,
416 const DATA_BLOB
*deleg_blob
,
419 krb5_data logon_data
;
422 krb5_data deleg_data
;
424 #ifdef SAMBA4_USES_HEIMDAL
425 krb5_data null_data
= {
431 /* The user account may be set not to want the PAC */
432 if (logon_blob
== NULL
) {
436 ret
= smb_krb5_copy_data_contents(&logon_data
,
443 ZERO_STRUCT(cred_data
);
444 if (cred_blob
!= NULL
) {
445 ret
= smb_krb5_copy_data_contents(&cred_data
,
449 smb_krb5_free_data_contents(context
, &logon_data
);
454 ZERO_STRUCT(upn_data
);
455 if (upn_blob
!= NULL
) {
456 ret
= smb_krb5_copy_data_contents(&upn_data
,
460 smb_krb5_free_data_contents(context
, &logon_data
);
461 smb_krb5_free_data_contents(context
, &cred_data
);
466 ZERO_STRUCT(deleg_data
);
467 if (deleg_blob
!= NULL
) {
468 ret
= smb_krb5_copy_data_contents(&deleg_data
,
472 smb_krb5_free_data_contents(context
, &logon_data
);
473 smb_krb5_free_data_contents(context
, &cred_data
);
474 smb_krb5_free_data_contents(context
, &upn_data
);
479 ret
= krb5_pac_init(context
, pac
);
481 smb_krb5_free_data_contents(context
, &logon_data
);
482 smb_krb5_free_data_contents(context
, &cred_data
);
483 smb_krb5_free_data_contents(context
, &upn_data
);
484 smb_krb5_free_data_contents(context
, &deleg_data
);
488 ret
= krb5_pac_add_buffer(context
, *pac
, PAC_TYPE_LOGON_INFO
, &logon_data
);
489 smb_krb5_free_data_contents(context
, &logon_data
);
491 smb_krb5_free_data_contents(context
, &upn_data
);
492 smb_krb5_free_data_contents(context
, &cred_data
);
493 smb_krb5_free_data_contents(context
, &deleg_data
);
497 if (cred_blob
!= NULL
) {
498 ret
= krb5_pac_add_buffer(context
, *pac
,
499 PAC_TYPE_CREDENTIAL_INFO
,
501 smb_krb5_free_data_contents(context
, &cred_data
);
503 smb_krb5_free_data_contents(context
, &upn_data
);
504 smb_krb5_free_data_contents(context
, &deleg_data
);
509 #ifdef SAMBA4_USES_HEIMDAL
511 * null_data will be filled by the generic KDC code in the caller
512 * here we just add it in order to have it before
513 * PAC_TYPE_UPN_DNS_INFO
515 * Not needed with MIT Kerberos - asn
517 ret
= krb5_pac_add_buffer(context
, *pac
,
521 smb_krb5_free_data_contents(context
, &upn_data
);
522 smb_krb5_free_data_contents(context
, &deleg_data
);
527 if (upn_blob
!= NULL
) {
528 ret
= krb5_pac_add_buffer(context
, *pac
,
529 PAC_TYPE_UPN_DNS_INFO
,
531 smb_krb5_free_data_contents(context
, &upn_data
);
533 smb_krb5_free_data_contents(context
, &deleg_data
);
538 if (deleg_blob
!= NULL
) {
539 ret
= krb5_pac_add_buffer(context
, *pac
,
540 PAC_TYPE_CONSTRAINED_DELEGATION
,
542 smb_krb5_free_data_contents(context
, &deleg_data
);
551 bool samba_princ_needs_pac(struct samba_kdc_entry
*skdc_entry
)
554 uint32_t userAccountControl
;
556 /* The service account may be set not to want the PAC */
557 userAccountControl
= ldb_msg_find_attr_as_uint(skdc_entry
->msg
, "userAccountControl", 0);
558 if (userAccountControl
& UF_NO_AUTH_DATA_REQUIRED
) {
565 /* Was the krbtgt in this DB (ie, should we check the incoming signature) and was it an RODC */
566 int samba_krbtgt_is_in_db(struct samba_kdc_entry
*p
,
571 int rodc_krbtgt_number
, trust_direction
;
574 TALLOC_CTX
*mem_ctx
= talloc_new(NULL
);
579 trust_direction
= ldb_msg_find_attr_as_int(p
->msg
, "trustDirection", 0);
581 if (trust_direction
!= 0) {
582 /* Domain trust - we cannot check the sig, but we trust it for a correct PAC
584 This is exactly where we should flag for SID
585 validation when we do inter-foreest trusts
587 talloc_free(mem_ctx
);
588 *is_untrusted
= false;
593 /* The lack of password controls etc applies to krbtgt by
594 * virtue of being that particular RID */
595 status
= dom_sid_split_rid(NULL
, samdb_result_dom_sid(mem_ctx
, p
->msg
, "objectSid"), NULL
, &rid
);
597 if (!NT_STATUS_IS_OK(status
)) {
598 talloc_free(mem_ctx
);
602 rodc_krbtgt_number
= ldb_msg_find_attr_as_int(p
->msg
, "msDS-SecondaryKrbTgtNumber", -1);
604 if (p
->kdc_db_ctx
->my_krbtgt_number
== 0) {
605 if (rid
== DOMAIN_RID_KRBTGT
) {
606 *is_untrusted
= false;
608 talloc_free(mem_ctx
);
610 } else if (rodc_krbtgt_number
!= -1) {
612 *is_untrusted
= true;
613 talloc_free(mem_ctx
);
616 } else if ((rid
!= DOMAIN_RID_KRBTGT
) && (rodc_krbtgt_number
== p
->kdc_db_ctx
->my_krbtgt_number
)) {
617 talloc_free(mem_ctx
);
618 *is_untrusted
= false;
621 } else if (rid
== DOMAIN_RID_KRBTGT
) {
622 /* krbtgt viewed from an RODC */
623 talloc_free(mem_ctx
);
624 *is_untrusted
= false;
630 talloc_free(mem_ctx
);
631 *is_untrusted
= true;
636 NTSTATUS
samba_kdc_get_pac_blobs(TALLOC_CTX
*mem_ctx
,
637 struct samba_kdc_entry
*p
,
638 DATA_BLOB
**_logon_info_blob
,
639 DATA_BLOB
**_cred_ndr_blob
,
640 DATA_BLOB
**_upn_info_blob
)
642 struct auth_user_info_dc
*user_info_dc
;
643 DATA_BLOB
*logon_blob
= NULL
;
644 DATA_BLOB
*cred_blob
= NULL
;
645 DATA_BLOB
*upn_blob
= NULL
;
648 *_logon_info_blob
= NULL
;
649 if (_cred_ndr_blob
!= NULL
) {
650 *_cred_ndr_blob
= NULL
;
652 *_upn_info_blob
= NULL
;
654 /* The user account may be set not to want the PAC */
655 if ( ! samba_princ_needs_pac(p
)) {
659 logon_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
660 if (logon_blob
== NULL
) {
661 return NT_STATUS_NO_MEMORY
;
664 if (_cred_ndr_blob
!= NULL
) {
665 cred_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
666 if (cred_blob
== NULL
) {
667 return NT_STATUS_NO_MEMORY
;
671 upn_blob
= talloc_zero(mem_ctx
, DATA_BLOB
);
672 if (upn_blob
== NULL
) {
673 return NT_STATUS_NO_MEMORY
;
676 nt_status
= authsam_make_user_info_dc(mem_ctx
, p
->kdc_db_ctx
->samdb
,
677 lpcfg_netbios_name(p
->kdc_db_ctx
->lp_ctx
),
678 lpcfg_sam_name(p
->kdc_db_ctx
->lp_ctx
),
679 lpcfg_sam_dnsname(p
->kdc_db_ctx
->lp_ctx
),
685 if (!NT_STATUS_IS_OK(nt_status
)) {
686 DEBUG(0, ("Getting user info for PAC failed: %s\n",
687 nt_errstr(nt_status
)));
691 nt_status
= samba_get_logon_info_pac_blob(logon_blob
,
694 if (!NT_STATUS_IS_OK(nt_status
)) {
695 DEBUG(0, ("Building PAC LOGON INFO failed: %s\n",
696 nt_errstr(nt_status
)));
700 if (cred_blob
!= NULL
) {
701 nt_status
= samba_get_cred_info_ndr_blob(cred_blob
,
704 if (!NT_STATUS_IS_OK(nt_status
)) {
705 DEBUG(0, ("Building PAC CRED INFO failed: %s\n",
706 nt_errstr(nt_status
)));
711 nt_status
= samba_get_upn_info_pac_blob(upn_blob
,
714 if (!NT_STATUS_IS_OK(nt_status
)) {
715 DEBUG(0, ("Building PAC UPN INFO failed: %s\n",
716 nt_errstr(nt_status
)));
720 TALLOC_FREE(user_info_dc
);
721 *_logon_info_blob
= logon_blob
;
722 if (_cred_ndr_blob
!= NULL
) {
723 *_cred_ndr_blob
= cred_blob
;
725 *_upn_info_blob
= upn_blob
;
729 NTSTATUS
samba_kdc_get_pac_blob(TALLOC_CTX
*mem_ctx
,
730 struct samba_kdc_entry
*p
,
731 DATA_BLOB
**_logon_info_blob
)
734 DATA_BLOB
*upn_blob
= NULL
;
736 nt_status
= samba_kdc_get_pac_blobs(mem_ctx
, p
,
738 NULL
, /* cred_blob */
740 if (!NT_STATUS_IS_OK(nt_status
)) {
744 TALLOC_FREE(upn_blob
);
748 NTSTATUS
samba_kdc_update_pac_blob(TALLOC_CTX
*mem_ctx
,
749 krb5_context context
,
750 struct samba_kdc_entry
*krbtgt
,
751 struct samba_kdc_entry
*server
,
752 const krb5_pac pac
, DATA_BLOB
*pac_blob
,
753 struct PAC_SIGNATURE_DATA
*pac_srv_sig
,
754 struct PAC_SIGNATURE_DATA
*pac_kdc_sig
)
756 struct auth_user_info_dc
*user_info_dc
;
760 ret
= kerberos_pac_to_user_info_dc(mem_ctx
, pac
,
761 context
, &user_info_dc
, pac_srv_sig
, pac_kdc_sig
);
763 return NT_STATUS_UNSUCCESSFUL
;
766 nt_status
= samba_get_logon_info_pac_blob(mem_ctx
,
767 user_info_dc
, pac_blob
);
772 NTSTATUS
samba_kdc_update_delegation_info_blob(TALLOC_CTX
*mem_ctx
,
773 krb5_context context
,
775 const krb5_principal server_principal
,
776 const krb5_principal proxy_principal
,
783 enum ndr_err_code ndr_err
;
785 struct PAC_CONSTRAINED_DELEGATION _d
;
786 struct PAC_CONSTRAINED_DELEGATION
*d
= NULL
;
790 TALLOC_CTX
*tmp_ctx
= talloc_new(mem_ctx
);
792 if (tmp_ctx
== NULL
) {
793 return NT_STATUS_NO_MEMORY
;
796 ret
= krb5_pac_get_buffer(context
, pac
, PAC_TYPE_CONSTRAINED_DELEGATION
, &old_data
);
798 ZERO_STRUCT(old_data
);
800 talloc_free(tmp_ctx
);
801 return NT_STATUS_UNSUCCESSFUL
;
804 old_blob
.length
= old_data
.length
;
805 old_blob
.data
= (uint8_t *)old_data
.data
;
808 if (old_blob
.length
> 0) {
809 ndr_err
= ndr_pull_union_blob(&old_blob
, mem_ctx
,
810 &info
, PAC_TYPE_CONSTRAINED_DELEGATION
,
811 (ndr_pull_flags_fn_t
)ndr_pull_PAC_INFO
);
812 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
813 smb_krb5_free_data_contents(context
, &old_data
);
814 nt_status
= ndr_map_error2ntstatus(ndr_err
);
815 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status
)));
816 talloc_free(tmp_ctx
);
821 info
.constrained_delegation
.info
= &_d
;
823 smb_krb5_free_data_contents(context
, &old_data
);
825 ret
= krb5_unparse_name(context
, server_principal
, &server
);
827 talloc_free(tmp_ctx
);
828 return NT_STATUS_INTERNAL_ERROR
;
831 ret
= krb5_unparse_name_flags(context
, proxy_principal
,
832 KRB5_PRINCIPAL_UNPARSE_NO_REALM
, &proxy
);
835 talloc_free(tmp_ctx
);
836 return NT_STATUS_INTERNAL_ERROR
;
839 d
= info
.constrained_delegation
.info
;
840 i
= d
->num_transited_services
;
841 d
->proxy_target
.string
= server
;
842 d
->transited_services
= talloc_realloc(mem_ctx
, d
->transited_services
,
843 struct lsa_String
, i
+ 1);
844 d
->transited_services
[i
].string
= proxy
;
845 d
->num_transited_services
= i
+ 1;
847 ndr_err
= ndr_push_union_blob(new_blob
, mem_ctx
,
848 &info
, PAC_TYPE_CONSTRAINED_DELEGATION
,
849 (ndr_push_flags_fn_t
)ndr_push_PAC_INFO
);
852 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
853 smb_krb5_free_data_contents(context
, &old_data
);
854 nt_status
= ndr_map_error2ntstatus(ndr_err
);
855 DEBUG(0,("can't parse the PAC LOGON_INFO: %s\n", nt_errstr(nt_status
)));
856 talloc_free(tmp_ctx
);
860 talloc_free(tmp_ctx
);
864 /* function to map policy errors */
865 krb5_error_code
samba_kdc_map_policy_err(NTSTATUS nt_status
)
869 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_PASSWORD_MUST_CHANGE
))
870 ret
= KRB5KDC_ERR_KEY_EXP
;
871 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_PASSWORD_EXPIRED
))
872 ret
= KRB5KDC_ERR_KEY_EXP
;
873 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_EXPIRED
))
874 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
875 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_DISABLED
))
876 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
877 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_LOGON_HOURS
))
878 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
879 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_ACCOUNT_LOCKED_OUT
))
880 ret
= KRB5KDC_ERR_CLIENT_REVOKED
;
881 else if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_INVALID_WORKSTATION
))
882 ret
= KRB5KDC_ERR_POLICY
;
884 ret
= KRB5KDC_ERR_POLICY
;
889 /* Given a kdc entry, consult the account_ok routine in auth/auth_sam.c
891 NTSTATUS
samba_kdc_check_client_access(struct samba_kdc_entry
*kdc_entry
,
892 const char *client_name
,
893 const char *workstation
,
894 bool password_change
)
899 tmp_ctx
= talloc_named(NULL
, 0, "samba_kdc_check_client_access");
901 return NT_STATUS_NO_MEMORY
;
904 /* we allow all kinds of trusts here */
905 nt_status
= authsam_account_ok(tmp_ctx
,
906 kdc_entry
->kdc_db_ctx
->samdb
,
907 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT
|
908 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT
,
909 kdc_entry
->realm_dn
, kdc_entry
->msg
,
910 workstation
, client_name
,
911 true, password_change
);
913 talloc_free(tmp_ctx
);