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/kdc-glue.h"
26 #include "kdc/db-glue.h"
27 #include "kdc/pac-glue.h"
30 #include "librpc/gen_ndr/auth.h"
31 #include <krb5_locl.h>
34 * Given the right private pointer from hdb_samba4,
35 * get a PAC from the attached ldb messages.
37 * For PKINIT we also get pk_reply_key and can add PAC_CREDENTIAL_INFO.
39 static krb5_error_code
samba_wdc_get_pac(void *priv
,
43 const krb5_keyblock
*pk_reply_key
,
44 uint64_t pac_attributes
,
47 krb5_context context
= kdc_request_get_context((kdc_request_t
)r
);
49 DATA_BLOB
*logon_blob
= NULL
;
50 DATA_BLOB
*cred_ndr
= NULL
;
51 DATA_BLOB
**cred_ndr_ptr
= NULL
;
52 DATA_BLOB _cred_blob
= data_blob_null
;
53 DATA_BLOB
*cred_blob
= NULL
;
54 DATA_BLOB
*upn_blob
= NULL
;
55 DATA_BLOB
*pac_attrs_blob
= NULL
;
56 DATA_BLOB
*requester_sid_blob
= NULL
;
59 struct samba_kdc_entry
*skdc_entry
=
60 talloc_get_type_abort(client
->context
,
61 struct samba_kdc_entry
);
64 mem_ctx
= talloc_named(client
->context
, 0, "samba_get_pac context");
69 if (pk_reply_key
!= NULL
) {
70 cred_ndr_ptr
= &cred_ndr
;
73 is_krbtgt
= krb5_principal_is_krbtgt(context
, server
->principal
);
75 nt_status
= samba_kdc_get_pac_blobs(mem_ctx
, skdc_entry
,
79 is_krbtgt
? &pac_attrs_blob
: NULL
,
81 is_krbtgt
? &requester_sid_blob
: NULL
);
82 if (!NT_STATUS_IS_OK(nt_status
)) {
87 if (pk_reply_key
!= NULL
&& cred_ndr
!= NULL
) {
88 ret
= samba_kdc_encrypt_pac_credentials(context
,
97 cred_blob
= &_cred_blob
;
100 ret
= krb5_pac_init(context
, pac
);
102 talloc_free(mem_ctx
);
106 ret
= samba_make_krb5_pac(context
, logon_blob
, cred_blob
,
107 upn_blob
, pac_attrs_blob
,
108 requester_sid_blob
, NULL
, *pac
);
110 talloc_free(mem_ctx
);
114 static krb5_error_code
samba_wdc_reget_pac2(krb5_context context
,
115 const krb5_principal delegated_proxy_principal
,
120 krb5_cksumtype ctype
)
122 struct samba_kdc_entry
*client_skdc_entry
= NULL
;
123 struct samba_kdc_entry
*server_skdc_entry
=
124 talloc_get_type_abort(server
->context
, struct samba_kdc_entry
);
125 struct samba_kdc_entry
*krbtgt_skdc_entry
=
126 talloc_get_type_abort(krbtgt
->context
, struct samba_kdc_entry
);
127 TALLOC_CTX
*mem_ctx
= NULL
;
128 krb5_pac new_pac
= NULL
;
130 bool is_in_db
= false;
131 bool is_untrusted
= false;
134 mem_ctx
= talloc_named(NULL
, 0, "samba_kdc_reget_pac2 context");
135 if (mem_ctx
== NULL
) {
139 if (client
!= NULL
) {
140 client_skdc_entry
= talloc_get_type_abort(client
->context
,
141 struct samba_kdc_entry
);
145 * If the krbtgt was generated by an RODC, and we are not that
146 * RODC, then we need to regenerate the PAC - we can't trust
147 * it, and confirm that the RODC was permitted to print this ticket
149 * Becasue of the samba_kdc_validate_pac_blob() step we can be
150 * sure that the record in 'client' matches the SID in the
153 ret
= samba_krbtgt_is_in_db(krbtgt_skdc_entry
, &is_in_db
, &is_untrusted
);
158 if (delegated_proxy_principal
!= NULL
) {
164 * The RODC-issued PAC was signed by a KDC entry that we
165 * don't have a key for. The server signature is not
166 * trustworthy, since it could have been created by the
167 * server we got the ticket from. We must not proceed as
168 * otherwise the ticket signature is unchecked.
170 ret
= HDB_ERR_NOT_FOUND_HERE
;
174 /* Fetch the correct key depending on the checksum type. */
175 if (ctype
== CKSUMTYPE_HMAC_MD5
) {
176 etype
= ENCTYPE_ARCFOUR_HMAC
;
178 ret
= krb5_cksumtype_to_enctype(context
,
185 ret
= hdb_enctype2key(context
, krbtgt
, NULL
, etype
, &key
);
190 /* Check the KDC and ticket signatures. */
191 ret
= krb5_pac_verify(context
,
198 DEBUG(1, ("PAC KDC signature failed to verify\n"));
202 flags
|= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION
;
206 flags
|= SAMBA_KDC_FLAG_KRBTGT_IS_UNTRUSTED
;
210 flags
|= SAMBA_KDC_FLAG_KRBTGT_IN_DB
;
213 ret
= krb5_pac_init(context
, &new_pac
);
219 ret
= samba_kdc_update_pac(mem_ctx
,
221 krbtgt_skdc_entry
->kdc_db_ctx
->samdb
,
227 delegated_proxy_principal
,
231 krb5_pac_free(context
, new_pac
);
232 if (ret
== ENODATA
) {
233 krb5_pac_free(context
, *pac
);
240 /* Replace the pac */
241 krb5_pac_free(context
, *pac
);
245 talloc_free(mem_ctx
);
249 /* Resign (and reform, including possibly new groups) a PAC */
251 static krb5_error_code
samba_wdc_reget_pac(void *priv
, astgs_request_t r
,
252 const krb5_principal client_principal
,
253 const krb5_principal delegated_proxy_principal
,
259 krb5_context context
= kdc_request_get_context((kdc_request_t
)r
);
260 krb5_kdc_configuration
*config
= kdc_request_get_config((kdc_request_t
)r
);
261 struct samba_kdc_entry
*krbtgt_skdc_entry
=
262 talloc_get_type_abort(krbtgt
->context
,
263 struct samba_kdc_entry
);
265 krb5_cksumtype ctype
= CKSUMTYPE_NONE
;
266 hdb_entry signing_krbtgt_hdb
;
268 if (delegated_proxy_principal
) {
270 unsigned int my_krbtgt_number
;
273 * We're using delegated_proxy_principal for the moment to
274 * indicate cases where the ticket was encrypted with the server
275 * key, and not a krbtgt key. This cannot be trusted, so we need
276 * to find a krbtgt key that signs the PAC in order to trust the
279 * The krbtgt passed in to this function refers to the krbtgt
280 * used to decrypt the ticket of the server requesting
283 * When we implement service ticket renewal, we need to check
284 * the PAC, and this will need to be updated.
286 ret
= krb5_pac_get_kdc_checksum_info(context
,
291 DEBUG(1, ("Failed to get PAC checksum info\n"));
296 * We need to check the KDC and ticket signatures, fetching the
297 * correct key based on the enctype.
300 my_krbtgt_number
= krbtgt_skdc_entry
->kdc_db_ctx
->my_krbtgt_number
;
302 if (my_krbtgt_number
!= 0) {
304 * If we are an RODC, and we are not the KDC that signed
305 * the evidence ticket, then we need to proxy the
308 if (rodc_id
!= my_krbtgt_number
) {
309 return HDB_ERR_NOT_FOUND_HERE
;
313 * If we are a DC, the ticket may have been signed by a
314 * different KDC than the one that issued the header
317 if (rodc_id
!= krbtgt
->kvno
>> 16) {
318 struct sdb_entry_ex signing_krbtgt_sdb
;
321 * If we didn't sign the ticket, then return an
325 return KRB5KRB_AP_ERR_MODIFIED
;
329 * Fetch our key from the database. To support
330 * key rollover, we're going to need to try
331 * multiple keys by trial and error. For now,
332 * krbtgt keys aren't assumed to change.
334 ret
= samba_kdc_fetch(context
,
335 krbtgt_skdc_entry
->kdc_db_ctx
,
337 SDB_F_GET_KRBTGT
| SDB_F_CANON
,
339 &signing_krbtgt_sdb
.entry
);
344 ret
= sdb_entry_to_hdb_entry(context
,
345 &signing_krbtgt_sdb
.entry
,
346 &signing_krbtgt_hdb
);
347 sdb_free_entry(&signing_krbtgt_sdb
);
353 * Replace the krbtgt entry with our own entry
354 * for further processing.
356 krbtgt
= &signing_krbtgt_hdb
;
361 ret
= samba_wdc_reget_pac2(context
,
362 delegated_proxy_principal
,
369 if (krbtgt
== &signing_krbtgt_hdb
) {
370 hdb_free_entry(context
, config
->db
[0], &signing_krbtgt_hdb
);
376 static char *get_netbios_name(TALLOC_CTX
*mem_ctx
, HostAddresses
*addrs
)
378 char *nb_name
= NULL
;
382 for (i
= 0; addrs
&& i
< addrs
->len
; i
++) {
383 if (addrs
->val
[i
].addr_type
!= KRB5_ADDRESS_NETBIOS
) {
386 len
= MIN(addrs
->val
[i
].address
.length
, 15);
387 nb_name
= talloc_strndup(mem_ctx
,
388 addrs
->val
[i
].address
.data
, len
);
394 if ((nb_name
== NULL
) || (nb_name
[0] == '\0')) {
398 /* Strip space padding */
399 for (len
= strlen(nb_name
) - 1;
400 (len
> 0) && (nb_name
[len
] == ' ');
408 /* this function allocates 'data' using malloc.
409 * The caller is responsible for freeing it */
410 static void samba_kdc_build_edata_reply(NTSTATUS nt_status
, krb5_data
*e_data
)
412 e_data
->data
= malloc(12);
413 if (e_data
->data
== NULL
) {
420 SIVAL(e_data
->data
, 0, NT_STATUS_V(nt_status
));
421 SIVAL(e_data
->data
, 4, 0);
422 SIVAL(e_data
->data
, 8, 1);
427 static krb5_error_code
samba_wdc_check_client_access(void *priv
,
430 struct samba_kdc_entry
*kdc_entry
;
431 bool password_change
;
436 kdc_entry
= talloc_get_type(kdc_request_get_client(r
)->context
, struct samba_kdc_entry
);
437 password_change
= (kdc_request_get_server(r
) && kdc_request_get_server(r
)->flags
.change_pw
);
438 workstation
= get_netbios_name((TALLOC_CTX
*)kdc_request_get_client(r
)->context
,
439 kdc_request_get_req(r
)->req_body
.addresses
);
441 nt_status
= samba_kdc_check_client_access(kdc_entry
,
442 kdc_request_get_cname((kdc_request_t
)r
),
446 if (!NT_STATUS_IS_OK(nt_status
)) {
447 if (NT_STATUS_EQUAL(nt_status
, NT_STATUS_NO_MEMORY
)) {
451 if (kdc_request_get_rep(r
)->padata
) {
455 samba_kdc_build_edata_reply(nt_status
, &kd
);
456 ret
= krb5_padata_add(kdc_request_get_context((kdc_request_t
)r
), kdc_request_get_rep(r
)->padata
,
461 * So we do not leak the allocated
462 * memory on kd in the error case
468 return samba_kdc_map_policy_err(nt_status
);
471 /* Now do the standard Heimdal check */
472 return KRB5_PLUGIN_NO_HANDLE
;
475 /* this function allocates 'data' using malloc.
476 * The caller is responsible for freeing it */
477 static krb5_error_code
samba_kdc_build_supported_etypes(uint32_t supported_etypes
,
480 e_data
->data
= malloc(4);
481 if (e_data
->data
== NULL
) {
486 PUSH_LE_U32(e_data
->data
, 0, supported_etypes
);
491 static krb5_error_code
samba_wdc_finalize_reply(void *priv
,
494 struct samba_kdc_entry
*server_kdc_entry
;
495 uint32_t supported_enctypes
;
497 server_kdc_entry
= talloc_get_type(kdc_request_get_server(r
)->context
, struct samba_kdc_entry
);
500 * If the canonicalize flag is set, add PA-SUPPORTED-ENCTYPES padata
501 * type to indicate what encryption types the server supports.
503 supported_enctypes
= server_kdc_entry
->supported_enctypes
;
504 if (kdc_request_get_req(r
)->req_body
.kdc_options
.canonicalize
&& supported_enctypes
!= 0) {
509 ret
= samba_kdc_build_supported_etypes(supported_enctypes
, &md
.padata_value
);
514 md
.padata_type
= KRB5_PADATA_SUPPORTED_ETYPES
;
516 ret
= kdc_request_add_encrypted_padata(r
, &md
);
519 * So we do not leak the allocated
520 * memory on kd in the error case
522 krb5_data_free(&md
.padata_value
);
529 static krb5_error_code
samba_wdc_plugin_init(krb5_context context
, void **ptr
)
535 static void samba_wdc_plugin_fini(void *ptr
)
540 static krb5_error_code
samba_wdc_referral_policy(void *priv
,
543 return kdc_request_get_error_code((kdc_request_t
)r
);
546 struct krb5plugin_kdc_ftable kdc_plugin_table
= {
547 .minor_version
= KRB5_PLUGIN_KDC_VERSION_10
,
548 .init
= samba_wdc_plugin_init
,
549 .fini
= samba_wdc_plugin_fini
,
550 .pac_verify
= samba_wdc_reget_pac
,
551 .client_access
= samba_wdc_check_client_access
,
552 .finalize_reply
= samba_wdc_finalize_reply
,
553 .pac_generate
= samba_wdc_get_pac
,
554 .referral_policy
= samba_wdc_referral_policy
,