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 "kdc/authn_policy_util.h"
26 #include "kdc/kdc-glue.h"
27 #include "kdc/db-glue.h"
28 #include "kdc/pac-glue.h"
31 #include "librpc/gen_ndr/auth.h"
32 #include <krb5_locl.h>
33 #include "lib/replace/system/filesys.h"
36 #define DBGC_CLASS DBGC_KERBEROS
38 static bool samba_wdc_is_s4u2self_req(astgs_request_t r
)
40 const KDC_REQ
*req
= kdc_request_get_req(r
);
41 const PA_DATA
*pa_for_user
= NULL
;
43 if (req
->msg_type
!= krb_tgs_req
) {
47 if (req
->padata
!= NULL
) {
50 pa_for_user
= krb5_find_padata(req
->padata
->val
,
56 if (pa_for_user
!= NULL
) {
64 * Given the right private pointer from hdb_samba4,
65 * get a PAC from the attached ldb messages.
67 * For PKINIT we also get pk_reply_key and can add PAC_CREDENTIAL_INFO.
69 static krb5_error_code
samba_wdc_get_pac(void *priv
,
73 const krb5_keyblock
*pk_reply_key
,
74 uint64_t pac_attributes
,
77 krb5_context context
= kdc_request_get_context((kdc_request_t
)r
);
79 DATA_BLOB
*logon_blob
= NULL
;
80 DATA_BLOB
*cred_ndr
= NULL
;
81 DATA_BLOB
**cred_ndr_ptr
= NULL
;
82 DATA_BLOB _cred_blob
= data_blob_null
;
83 DATA_BLOB
*cred_blob
= NULL
;
84 DATA_BLOB
*upn_blob
= NULL
;
85 DATA_BLOB
*pac_attrs_blob
= NULL
;
86 DATA_BLOB
*requester_sid_blob
= NULL
;
87 DATA_BLOB client_claims_blob
= {};
90 struct samba_kdc_entry
*skdc_entry
=
91 talloc_get_type_abort(client
->context
,
92 struct samba_kdc_entry
);
93 const struct samba_kdc_entry
*server_entry
=
94 talloc_get_type_abort(server
->context
,
95 struct samba_kdc_entry
);
96 bool is_krbtgt
= krb5_principal_is_krbtgt(context
, server
->principal
);
97 enum auth_group_inclusion group_inclusion
;
98 bool is_s4u2self
= samba_wdc_is_s4u2self_req(r
);
99 enum samba_asserted_identity asserted_identity
=
101 SAMBA_ASSERTED_IDENTITY_SERVICE
:
102 SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY
;
103 struct authn_audit_info
*server_audit_info
= NULL
;
104 NTSTATUS reply_status
= NT_STATUS_OK
;
106 const struct auth_user_info_dc
*user_info_dc_const
= NULL
;
107 struct auth_user_info_dc
*user_info_dc_shallow_copy
= NULL
;
108 struct auth_claims auth_claims
= {};
110 /* Only include resource groups in a service ticket. */
112 group_inclusion
= AUTH_EXCLUDE_RESOURCE_GROUPS
;
113 } else if (server_entry
->supported_enctypes
& KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED
) {
114 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS
;
116 group_inclusion
= AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED
;
119 mem_ctx
= talloc_named(client
->context
, 0, "samba_wdc_get_pac context");
124 if (pk_reply_key
!= NULL
) {
125 cred_ndr_ptr
= &cred_ndr
;
128 ret
= samba_kdc_get_user_info_from_db(mem_ctx
,
129 server_entry
->kdc_db_ctx
->samdb
,
132 &user_info_dc_const
);
134 talloc_free(mem_ctx
);
138 /* Make a shallow copy of the user_info_dc structure. */
139 nt_status
= authsam_shallow_copy_user_info_dc(mem_ctx
,
141 &user_info_dc_shallow_copy
);
142 user_info_dc_const
= NULL
;
144 if (!NT_STATUS_IS_OK(nt_status
)) {
145 DBG_ERR("Failed to allocate user_info_dc SIDs: %s\n",
146 nt_errstr(nt_status
));
147 talloc_free(mem_ctx
);
148 return map_errno_from_nt_status(nt_status
);
151 nt_status
= samba_kdc_add_asserted_identity(asserted_identity
,
152 user_info_dc_shallow_copy
);
153 if (!NT_STATUS_IS_OK(nt_status
)) {
154 DBG_ERR("Failed to add asserted identity: %s\n",
155 nt_errstr(nt_status
));
156 talloc_free(mem_ctx
);
157 return map_errno_from_nt_status(nt_status
);
160 nt_status
= samba_kdc_add_claims_valid(user_info_dc_shallow_copy
);
161 if (!NT_STATUS_IS_OK(nt_status
)) {
162 DBG_ERR("Failed to add Claims Valid: %s\n",
163 nt_errstr(nt_status
));
164 talloc_free(mem_ctx
);
165 return map_errno_from_nt_status(nt_status
);
168 if (kdc_request_get_pkinit_freshness_used(r
)) {
169 nt_status
= samba_kdc_add_fresh_public_key_identity(user_info_dc_shallow_copy
);
170 if (!NT_STATUS_IS_OK(nt_status
)) {
171 DBG_ERR("Failed to add Fresh Public Key Identity: %s\n",
172 nt_errstr(nt_status
));
173 talloc_free(mem_ctx
);
174 return map_errno_from_nt_status(nt_status
);
178 ret
= samba_kdc_get_claims_data_from_db(server_entry
->kdc_db_ctx
->samdb
,
180 &auth_claims
.user_claims
);
182 talloc_free(mem_ctx
);
186 nt_status
= claims_data_encoded_claims_set(mem_ctx
,
187 auth_claims
.user_claims
,
188 &client_claims_blob
);
189 if (!NT_STATUS_IS_OK(nt_status
)) {
190 talloc_free(mem_ctx
);
191 return map_errno_from_nt_status(nt_status
);
195 * For an S4U2Self request, the authentication policy is not enforced.
197 if (!is_s4u2self
&& authn_policy_restrictions_present(server_entry
->server_policy
)) {
198 const hdb_entry
*device
= kdc_request_get_armor_client(r
);
199 const struct auth_user_info_dc
*device_info
= NULL
;
201 if (device
!= NULL
) {
202 const hdb_entry
*device_krbtgt
= NULL
;
203 struct samba_kdc_entry
*device_skdc_entry
= NULL
;
204 const struct samba_kdc_entry
*device_krbtgt_skdc_entry
= NULL
;
205 const krb5_const_pac device_pac
= kdc_request_get_armor_pac(r
);
206 struct samba_kdc_entry_pac device_pac_entry
= {};
208 device_skdc_entry
= talloc_get_type_abort(device
->context
,
209 struct samba_kdc_entry
);
211 device_krbtgt
= kdc_request_get_armor_server(r
);
212 if (device_krbtgt
!= NULL
) {
213 device_krbtgt_skdc_entry
= talloc_get_type_abort(device_krbtgt
->context
,
214 struct samba_kdc_entry
);
217 device_pac_entry
= samba_kdc_entry_pac(device_pac
,
219 samba_kdc_entry_is_trust(device_krbtgt_skdc_entry
));
221 ret
= samba_kdc_get_user_info_dc(mem_ctx
,
223 server_entry
->kdc_db_ctx
->samdb
,
226 NULL
/* resource_groups_out */);
228 talloc_free(mem_ctx
);
232 ret
= samba_kdc_get_claims_data(mem_ctx
,
234 server_entry
->kdc_db_ctx
->samdb
,
236 &auth_claims
.device_claims
);
238 talloc_free(mem_ctx
);
243 ret
= samba_kdc_allowed_to_authenticate_to(mem_ctx
,
244 server_entry
->kdc_db_ctx
->samdb
,
245 server_entry
->kdc_db_ctx
->lp_ctx
,
247 user_info_dc_shallow_copy
,
253 if (server_audit_info
!= NULL
) {
254 krb5_error_code ret2
;
256 ret2
= hdb_samba4_set_steal_server_audit_info(r
, server_audit_info
);
261 if (!NT_STATUS_IS_OK(reply_status
)) {
262 krb5_error_code ret2
;
264 ret2
= hdb_samba4_set_ntstatus(r
, reply_status
, ret
);
270 talloc_free(mem_ctx
);
275 nt_status
= samba_kdc_get_logon_info_blob(mem_ctx
,
276 user_info_dc_shallow_copy
,
279 if (!NT_STATUS_IS_OK(nt_status
)) {
280 talloc_free(mem_ctx
);
281 return map_errno_from_nt_status(nt_status
);
284 if (cred_ndr_ptr
!= NULL
) {
285 nt_status
= samba_kdc_get_cred_ndr_blob(mem_ctx
,
288 if (!NT_STATUS_IS_OK(nt_status
)) {
289 talloc_free(mem_ctx
);
290 return map_errno_from_nt_status(nt_status
);
294 nt_status
= samba_kdc_get_upn_info_blob(mem_ctx
,
295 user_info_dc_shallow_copy
,
297 if (!NT_STATUS_IS_OK(nt_status
)) {
298 talloc_free(mem_ctx
);
299 return map_errno_from_nt_status(nt_status
);
303 nt_status
= samba_kdc_get_pac_attrs_blob(mem_ctx
,
306 if (!NT_STATUS_IS_OK(nt_status
)) {
307 talloc_free(mem_ctx
);
308 return map_errno_from_nt_status(nt_status
);
311 nt_status
= samba_kdc_get_requester_sid_blob(mem_ctx
,
312 user_info_dc_shallow_copy
,
313 &requester_sid_blob
);
314 if (!NT_STATUS_IS_OK(nt_status
)) {
315 talloc_free(mem_ctx
);
316 return map_errno_from_nt_status(nt_status
);
320 if (pk_reply_key
!= NULL
&& cred_ndr
!= NULL
) {
321 ret
= samba_kdc_encrypt_pac_credentials(context
,
327 talloc_free(mem_ctx
);
330 cred_blob
= &_cred_blob
;
333 ret
= krb5_pac_init(context
, pac
);
335 talloc_free(mem_ctx
);
339 ret
= samba_make_krb5_pac(context
, logon_blob
, cred_blob
,
340 upn_blob
, pac_attrs_blob
,
341 requester_sid_blob
, NULL
,
342 &client_claims_blob
, NULL
, NULL
,
345 talloc_free(mem_ctx
);
349 static krb5_error_code
samba_wdc_verify_pac2(astgs_request_t r
,
350 const hdb_entry
*delegated_proxy
,
351 const hdb_entry
*client
,
352 const hdb_entry
*krbtgt
,
354 krb5_cksumtype ctype
)
356 krb5_context context
= kdc_request_get_context((kdc_request_t
)r
);
357 struct samba_kdc_entry
*client_skdc_entry
= NULL
;
358 struct samba_kdc_entry
*krbtgt_skdc_entry
=
359 talloc_get_type_abort(krbtgt
->context
, struct samba_kdc_entry
);
360 struct samba_kdc_entry_pac client_pac_entry
= {};
361 TALLOC_CTX
*mem_ctx
= NULL
;
363 bool is_s4u2self
= samba_wdc_is_s4u2self_req(r
);
364 bool is_in_db
= false;
365 bool is_trusted
= false;
372 mem_ctx
= talloc_named(NULL
, 0, "samba_wdc_verify_pac2 context");
373 if (mem_ctx
== NULL
) {
377 if (client
!= NULL
) {
378 client_skdc_entry
= talloc_get_type_abort(client
->context
,
379 struct samba_kdc_entry
);
383 * If the krbtgt was generated by an RODC, and we are not that
384 * RODC, then we need to regenerate the PAC - we can't trust
385 * it, and confirm that the RODC was permitted to print this ticket
387 * Because of the samba_kdc_validate_pac_blob() step we can be
388 * sure that the record in 'client' matches the SID in the
391 ret
= samba_krbtgt_is_in_db(krbtgt_skdc_entry
, &is_in_db
, &is_trusted
);
396 krb5_pac_set_trusted(pac
, is_trusted
);
397 client_pac_entry
= samba_kdc_entry_pac(pac
,
399 samba_kdc_entry_is_trust(krbtgt_skdc_entry
));
402 flags
|= SAMBA_KDC_FLAG_PROTOCOL_TRANSITION
;
405 if (delegated_proxy
!= NULL
) {
411 * The RODC-issued PAC was signed by a KDC entry that we
412 * don't have a key for. The server signature is not
413 * trustworthy, since it could have been created by the
414 * server we got the ticket from. We must not proceed as
415 * otherwise the ticket signature is unchecked.
417 ret
= HDB_ERR_NOT_FOUND_HERE
;
421 /* Fetch the correct key depending on the checksum type. */
422 if (ctype
== CKSUMTYPE_HMAC_MD5
) {
423 etype
= ENCTYPE_ARCFOUR_HMAC
;
425 ret
= krb5_cksumtype_to_enctype(context
,
432 ret
= hdb_enctype2key(context
, krbtgt
, NULL
, etype
, &key
);
437 /* Check the KDC, whole-PAC and ticket signatures. */
438 ret
= krb5_pac_verify(context
,
445 DBG_WARNING("PAC KDC signature failed to verify\n");
449 flags
|= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
;
452 ret
= samba_kdc_verify_pac(mem_ctx
,
454 krbtgt_skdc_entry
->kdc_db_ctx
->samdb
,
463 talloc_free(mem_ctx
);
467 /* Re-sign (and reform, including possibly new groups) a PAC */
469 static krb5_error_code
samba_wdc_reget_pac(void *priv
, astgs_request_t r
,
470 krb5_const_principal _client_principal
,
471 hdb_entry
*delegated_proxy
,
472 krb5_const_pac delegated_proxy_pac
,
478 krb5_context context
= kdc_request_get_context((kdc_request_t
)r
);
479 struct samba_kdc_entry
*delegated_proxy_skdc_entry
= NULL
;
480 krb5_const_principal delegated_proxy_principal
= NULL
;
481 struct samba_kdc_entry_pac delegated_proxy_pac_entry
= {};
482 struct samba_kdc_entry
*client_skdc_entry
= NULL
;
483 struct samba_kdc_entry_pac client_pac_entry
= {};
484 struct samba_kdc_entry_pac device
= {};
485 const struct samba_kdc_entry
*server_skdc_entry
=
486 talloc_get_type_abort(server
->context
, struct samba_kdc_entry
);
487 const struct samba_kdc_entry
*krbtgt_skdc_entry
=
488 talloc_get_type_abort(krbtgt
->context
, struct samba_kdc_entry
);
489 TALLOC_CTX
*mem_ctx
= NULL
;
490 krb5_pac new_pac
= NULL
;
491 struct authn_audit_info
*server_audit_info
= NULL
;
493 NTSTATUS reply_status
= NT_STATUS_OK
;
500 mem_ctx
= talloc_named(NULL
, 0, "samba_wdc_reget_pac context");
501 if (mem_ctx
== NULL
) {
505 if (delegated_proxy
!= NULL
) {
506 delegated_proxy_skdc_entry
= talloc_get_type_abort(delegated_proxy
->context
,
507 struct samba_kdc_entry
);
508 delegated_proxy_principal
= delegated_proxy
->principal
;
511 delegated_proxy_pac_entry
= samba_kdc_entry_pac(delegated_proxy_pac
,
512 delegated_proxy_skdc_entry
,
514 * evidence ticket could
515 * not have been signed
516 * or issued by a krbtgt
518 false /* is_from_trust */);
520 if (client
!= NULL
) {
521 client_skdc_entry
= talloc_get_type_abort(client
->context
,
522 struct samba_kdc_entry
);
525 device
= samba_kdc_get_device_pac(r
);
527 ret
= krb5_pac_init(context
, &new_pac
);
533 client_pac_entry
= samba_kdc_entry_pac(*pac
,
535 samba_kdc_entry_is_trust(krbtgt_skdc_entry
));
537 ret
= samba_kdc_update_pac(mem_ctx
,
539 krbtgt_skdc_entry
->kdc_db_ctx
->samdb
,
540 krbtgt_skdc_entry
->kdc_db_ctx
->lp_ctx
,
545 delegated_proxy_principal
,
546 delegated_proxy_pac_entry
,
551 if (server_audit_info
!= NULL
) {
552 krb5_error_code ret2
;
554 ret2
= hdb_samba4_set_steal_server_audit_info(r
, server_audit_info
);
559 if (!NT_STATUS_IS_OK(reply_status
)) {
560 krb5_error_code ret2
;
562 ret2
= hdb_samba4_set_ntstatus(r
, reply_status
, ret
);
568 krb5_pac_free(context
, new_pac
);
569 if (ret
== ENOATTR
) {
570 krb5_pac_free(context
, *pac
);
577 /* Replace the pac */
578 krb5_pac_free(context
, *pac
);
582 talloc_free(mem_ctx
);
586 /* Verify a PAC's SID and signatures */
588 static krb5_error_code
samba_wdc_verify_pac(void *priv
, astgs_request_t r
,
589 krb5_const_principal _client_principal
,
590 hdb_entry
*delegated_proxy
,
594 EncTicketPart
*ticket
,
597 krb5_context context
= kdc_request_get_context((kdc_request_t
)r
);
598 krb5_kdc_configuration
*config
= kdc_request_get_config((kdc_request_t
)r
);
599 struct samba_kdc_entry
*krbtgt_skdc_entry
=
600 talloc_get_type_abort(krbtgt
->context
,
601 struct samba_kdc_entry
);
603 krb5_cksumtype ctype
= CKSUMTYPE_NONE
;
604 hdb_entry signing_krbtgt_hdb
;
606 if (delegated_proxy
) {
607 uint16_t pac_kdc_signature_rodc_id
;
608 const unsigned int local_tgs_rodc_id
= krbtgt_skdc_entry
->kdc_db_ctx
->my_krbtgt_number
;
609 const uint16_t header_ticket_rodc_id
= krbtgt
->kvno
>> 16;
612 * We're using delegated_proxy for the moment to indicate cases
613 * where the ticket was encrypted with the server key, and not a
614 * krbtgt key. This cannot be trusted, so we need to find a
615 * krbtgt key that signs the PAC in order to trust the ticket.
617 * The krbtgt passed in to this function refers to the krbtgt
618 * used to decrypt the ticket of the server requesting
621 * When we implement service ticket renewal, we need to check
622 * the PAC, and this will need to be updated.
624 ret
= krb5_pac_get_kdc_checksum_info(context
,
627 &pac_kdc_signature_rodc_id
);
629 DBG_WARNING("Failed to get PAC checksum info\n");
634 * We need to check the KDC and ticket signatures, fetching the
635 * correct key based on the enctype.
637 if (local_tgs_rodc_id
!= 0) {
639 * If we are an RODC, and we are not the KDC that signed
640 * the evidence ticket, then we need to proxy the
643 if (local_tgs_rodc_id
!= pac_kdc_signature_rodc_id
) {
644 return HDB_ERR_NOT_FOUND_HERE
;
648 * If we are a DC, the ticket may have been signed by a
649 * different KDC than the one that issued the header
652 if (pac_kdc_signature_rodc_id
!= header_ticket_rodc_id
) {
653 struct sdb_entry signing_krbtgt_sdb
;
656 * Fetch our key from the database. To support
657 * key rollover, we're going to need to try
658 * multiple keys by trial and error. For now,
659 * krbtgt keys aren't assumed to change.
661 ret
= samba_kdc_fetch(context
,
662 krbtgt_skdc_entry
->kdc_db_ctx
,
664 SDB_F_GET_KRBTGT
| SDB_F_RODC_NUMBER_SPECIFIED
| SDB_F_CANON
,
665 ((uint32_t)pac_kdc_signature_rodc_id
) << 16,
666 &signing_krbtgt_sdb
);
671 ret
= sdb_entry_to_hdb_entry(context
,
673 &signing_krbtgt_hdb
);
674 sdb_entry_free(&signing_krbtgt_sdb
);
680 * Replace the krbtgt entry with our own entry
681 * for further processing.
683 krbtgt
= &signing_krbtgt_hdb
;
686 } else if (!krbtgt_skdc_entry
->is_trust
) {
688 * We expect to have received a TGT, so check that we haven't
689 * been given a kpasswd ticket instead. We don't need to do this
690 * check for an incoming trust, as they use a different secret
691 * and can't be confused with a normal TGT.
694 struct timeval now
= krb5_kdc_get_time();
697 * Check if the ticket is in the last two minutes of its
700 KerberosTime lifetime
= rk_time_sub(ticket
->endtime
, now
.tv_sec
);
701 if (lifetime
<= CHANGEPW_LIFETIME
) {
703 * This ticket has at most two minutes left to live. It
704 * may be a kpasswd ticket rather than a TGT, so don't
707 kdc_audit_addreason((kdc_request_t
)r
,
708 "Ticket is not a ticket-granting ticket");
709 return KRB5KRB_AP_ERR_TKT_EXPIRED
;
713 ret
= samba_wdc_verify_pac2(r
,
720 if (krbtgt
== &signing_krbtgt_hdb
) {
721 hdb_free_entry(context
, config
->db
[0], &signing_krbtgt_hdb
);
727 static char *get_netbios_name(TALLOC_CTX
*mem_ctx
, HostAddresses
*addrs
)
729 char *nb_name
= NULL
;
733 for (i
= 0; addrs
&& i
< addrs
->len
; i
++) {
734 if (addrs
->val
[i
].addr_type
!= KRB5_ADDRESS_NETBIOS
) {
737 len
= MIN(addrs
->val
[i
].address
.length
, 15);
738 nb_name
= talloc_strndup(mem_ctx
,
739 addrs
->val
[i
].address
.data
, len
);
745 if ((nb_name
== NULL
) || (nb_name
[0] == '\0')) {
749 /* Strip space padding */
750 for (len
= strlen(nb_name
) - 1;
751 (len
> 0) && (nb_name
[len
] == ' ');
759 static krb5_error_code
samba_wdc_check_client_access(void *priv
,
762 krb5_context context
= kdc_request_get_context((kdc_request_t
)r
);
763 TALLOC_CTX
*tmp_ctx
= NULL
;
764 const hdb_entry
*client
= NULL
;
765 struct samba_kdc_entry
*kdc_entry
;
766 struct samba_kdc_entry_pac device
= {};
767 struct authn_audit_info
*client_audit_info
= NULL
;
768 bool password_change
;
771 NTSTATUS check_device_status
= NT_STATUS_OK
;
772 krb5_error_code ret
= 0;
774 client
= kdc_request_get_client(r
);
776 tmp_ctx
= talloc_named(client
->context
, 0, "samba_wdc_check_client_access");
777 if (tmp_ctx
== NULL
) {
781 kdc_entry
= talloc_get_type_abort(client
->context
, struct samba_kdc_entry
);
783 device
= samba_kdc_get_device_pac(r
);
785 ret
= samba_kdc_check_device(tmp_ctx
,
787 kdc_entry
->kdc_db_ctx
->samdb
,
788 kdc_entry
->kdc_db_ctx
->lp_ctx
,
790 kdc_entry
->client_policy
,
792 &check_device_status
);
793 if (client_audit_info
!= NULL
) {
794 krb5_error_code ret2
;
796 ret2
= hdb_samba4_set_steal_client_audit_info(r
, client_audit_info
);
801 kdc_entry
->reject_status
= check_device_status
;
802 if (!NT_STATUS_IS_OK(check_device_status
)) {
803 krb5_error_code ret2
;
806 * Add the NTSTATUS to the request so we can return it in the
807 * ‘e-data’ field later.
809 ret2
= hdb_samba4_set_ntstatus(r
, check_device_status
, ret
);
817 * As we didn’t get far enough to check the server policy, only
818 * the client policy will be referenced in the authentication
822 talloc_free(tmp_ctx
);
826 workstation
= get_netbios_name(tmp_ctx
,
827 kdc_request_get_req(r
)->req_body
.addresses
);
828 password_change
= (kdc_request_get_server(r
) && kdc_request_get_server(r
)->flags
.change_pw
);
830 nt_status
= samba_kdc_check_client_access(kdc_entry
,
831 kdc_request_get_cname((kdc_request_t
)r
),
835 kdc_entry
->reject_status
= nt_status
;
836 if (!NT_STATUS_IS_OK(nt_status
)) {
837 krb5_error_code ret2
;
839 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_NO_MEMORY
)) {
840 talloc_free(tmp_ctx
);
844 ret
= samba_kdc_map_policy_err(nt_status
);
847 * Add the NTSTATUS to the request so we can return it in the
848 * ‘e-data’ field later.
850 ret2
= hdb_samba4_set_ntstatus(r
, nt_status
, ret
);
855 talloc_free(tmp_ctx
);
859 /* Now do the standard Heimdal check */
860 talloc_free(tmp_ctx
);
861 return KRB5_PLUGIN_NO_HANDLE
;
864 /* this function allocates 'data' using malloc.
865 * The caller is responsible for freeing it */
866 static krb5_error_code
samba_kdc_build_supported_etypes(uint32_t supported_etypes
,
869 e_data
->data
= malloc(4);
870 if (e_data
->data
== NULL
) {
875 PUSH_LE_U32(e_data
->data
, 0, supported_etypes
);
880 static krb5_error_code
samba_wdc_finalize_reply(void *priv
,
883 struct samba_kdc_entry
*server_kdc_entry
;
884 uint32_t supported_enctypes
;
886 server_kdc_entry
= talloc_get_type(kdc_request_get_server(r
)->context
, struct samba_kdc_entry
);
889 * If the canonicalize flag is set, add PA-SUPPORTED-ENCTYPES padata
890 * type to indicate what encryption types the server supports.
892 supported_enctypes
= server_kdc_entry
->supported_enctypes
;
893 if (kdc_request_get_req(r
)->req_body
.kdc_options
.canonicalize
&& supported_enctypes
!= 0) {
898 ret
= samba_kdc_build_supported_etypes(supported_enctypes
, &md
.padata_value
);
903 md
.padata_type
= KRB5_PADATA_SUPPORTED_ETYPES
;
905 ret
= kdc_request_add_encrypted_padata(r
, &md
);
908 * So we do not leak the allocated
909 * memory on md in the error case
911 krb5_data_free(&md
.padata_value
);
918 static krb5_error_code
samba_wdc_plugin_init(krb5_context context
, void **ptr
)
924 static void samba_wdc_plugin_fini(void *ptr
)
929 static krb5_error_code
samba_wdc_referral_policy(void *priv
,
932 return kdc_request_get_error_code((kdc_request_t
)r
);
935 static krb5_error_code
samba_wdc_hwauth_policy(void *priv
, astgs_request_t r
)
937 const hdb_entry
*client
= kdc_request_get_client(r
);
938 krb5_error_code ret
= 0;
940 if (client
!= NULL
&& client
->flags
.require_hwauth
) {
941 krb5_error_code ret2
;
943 ret
= KRB5KDC_ERR_POLICY
;
944 ret2
= hdb_samba4_set_ntstatus(
945 r
, NT_STATUS_SMARTCARD_LOGON_REQUIRED
, ret
);
954 struct krb5plugin_kdc_ftable kdc_plugin_table
= {
955 .minor_version
= KRB5_PLUGIN_KDC_VERSION_12
,
956 .init
= samba_wdc_plugin_init
,
957 .fini
= samba_wdc_plugin_fini
,
958 .pac_verify
= samba_wdc_verify_pac
,
959 .pac_update
= samba_wdc_reget_pac
,
960 .client_access
= samba_wdc_check_client_access
,
961 .finalize_reply
= samba_wdc_finalize_reply
,
962 .pac_generate
= samba_wdc_get_pac
,
963 .referral_policy
= samba_wdc_referral_policy
,
964 .hwauth_policy
= samba_wdc_hwauth_policy
,