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, krb5_context context,
40 krb5_kdc_configuration *config,
43 const krb5_keyblock *pk_reply_key,
44 uint64_t pac_attributes,
48 DATA_BLOB *logon_blob = NULL;
49 DATA_BLOB *cred_ndr = NULL;
50 DATA_BLOB **cred_ndr_ptr = NULL;
51 DATA_BLOB _cred_blob = data_blob_null;
52 DATA_BLOB *cred_blob = NULL;
53 DATA_BLOB *upn_blob = NULL;
54 DATA_BLOB *pac_attrs_blob = NULL;
55 DATA_BLOB *requester_sid_blob = NULL;
58 struct samba_kdc_entry *skdc_entry =
59 talloc_get_type_abort(client->context,
60 struct samba_kdc_entry);
63 mem_ctx = talloc_named(client->context, 0, "samba_get_pac context");
68 if (pk_reply_key != NULL) {
69 cred_ndr_ptr = &cred_ndr;
72 is_krbtgt = krb5_principal_is_krbtgt(context, server->principal);
74 nt_status = samba_kdc_get_pac_blobs(mem_ctx, skdc_entry,
78 is_krbtgt ? &pac_attrs_blob : NULL,
80 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 *server_skdc_entry =
123 talloc_get_type_abort(server->context,
124 struct samba_kdc_entry);
125 struct samba_kdc_entry *krbtgt_skdc_entry =
126 talloc_get_type_abort(krbtgt->context,
127 struct samba_kdc_entry);
128 TALLOC_CTX *mem_ctx = talloc_named(server_skdc_entry,
130 "samba_kdc_reget_pac2 context");
131 krb5_pac new_pac = NULL;
132 DATA_BLOB *pac_blob = NULL;
133 DATA_BLOB *upn_blob = NULL;
134 DATA_BLOB *requester_sid_blob = NULL;
135 DATA_BLOB *deleg_blob = NULL;
138 bool is_in_db, is_untrusted;
140 size_t num_types = 0;
141 uint32_t *types = NULL;
142 uint32_t forced_next_type = 0;
144 ssize_t logon_info_idx = -1;
145 ssize_t delegation_idx = -1;
146 ssize_t logon_name_idx = -1;
147 ssize_t upn_dns_info_idx = -1;
148 ssize_t srv_checksum_idx = -1;
149 ssize_t kdc_checksum_idx = -1;
150 ssize_t tkt_checksum_idx = -1;
151 ssize_t attrs_info_idx = -1;
152 ssize_t requester_sid_idx = -1;
158 if (client != NULL) {
159 struct samba_kdc_entry *client_skdc_entry = NULL;
161 client_skdc_entry = talloc_get_type_abort(client->context,
162 struct samba_kdc_entry);
165 * Check the objectSID of the client and pac data are the same.
166 * Does a parse and SID check, but no crypto.
168 ret = samba_kdc_validate_pac_blob(context, client_skdc_entry, *pac);
170 talloc_free(mem_ctx);
176 * If the krbtgt was generated by an RODC, and we are not that
177 * RODC, then we need to regenerate the PAC - we can't trust
178 * it, and confirm that the RODC was permitted to print this ticket
180 * Becasue of the samba_kdc_validate_pac_blob() step we can be
181 * sure that the record in 'client' matches the SID in the
184 ret = samba_krbtgt_is_in_db(krbtgt_skdc_entry, &is_in_db, &is_untrusted);
186 talloc_free(mem_ctx);
190 if (delegated_proxy_principal != NULL) {
196 * The RODC-issued PAC was signed by a KDC entry that we
197 * don't have a key for. The server signature is not
198 * trustworthy, since it could have been created by the
199 * server we got the ticket from. We must not proceed as
200 * otherwise the ticket signature is unchecked.
202 talloc_free(mem_ctx);
203 return HDB_ERR_NOT_FOUND_HERE;
206 /* Fetch the correct key depending on the checksum type. */
207 if (ctype == CKSUMTYPE_HMAC_MD5) {
208 etype = ENCTYPE_ARCFOUR_HMAC;
210 ret = krb5_cksumtype_to_enctype(context,
214 talloc_free(mem_ctx);
218 ret = hdb_enctype2key(context, krbtgt, NULL, etype, &key);
220 talloc_free(mem_ctx);
224 /* Check the KDC and ticket signatures. */
225 ret = krb5_pac_verify(context,
232 DEBUG(1, ("PAC KDC signature failed to verify\n"));
233 talloc_free(mem_ctx);
237 deleg_blob = talloc_zero(mem_ctx, DATA_BLOB);
239 talloc_free(mem_ctx);
243 nt_status = samba_kdc_update_delegation_info_blob(mem_ctx,
246 delegated_proxy_principal,
248 if (!NT_STATUS_IS_OK(nt_status)) {
249 DBG_ERR("samba_kdc_update_delegation_info_blob() failed: %s\n",
250 nt_errstr(nt_status));
251 talloc_free(mem_ctx);
257 struct samba_kdc_entry *client_skdc_entry = NULL;
258 struct auth_user_info_dc *user_info_dc = NULL;
261 if (client == NULL) {
262 return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
265 client_skdc_entry = talloc_get_type_abort(client->context,
266 struct samba_kdc_entry);
268 nt_status = samba_kdc_get_pac_blobs(mem_ctx, client_skdc_entry,
269 &pac_blob, NULL, &upn_blob,
270 NULL, PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY,
273 if (!NT_STATUS_IS_OK(nt_status)) {
274 talloc_free(mem_ctx);
275 DBG_ERR("samba_kdc_get_pac_blobs() failed: %s\n",
276 nt_errstr(nt_status));
277 return KRB5KDC_ERR_TGT_REVOKED;
281 * Now check if the SID list in the user_info_dc
282 * intersects correctly with the RODC allow/deny
286 werr = samba_rodc_confirm_user_is_allowed(user_info_dc->num_sids,
290 if (!W_ERROR_IS_OK(werr)) {
291 talloc_free(mem_ctx);
292 if (W_ERROR_EQUAL(werr, WERR_DOMAIN_CONTROLLER_NOT_FOUND)) {
293 return KRB5KDC_ERR_POLICY;
295 return KRB5KDC_ERR_TGT_REVOKED;
301 pac_blob = talloc_zero(mem_ctx, DATA_BLOB);
303 talloc_free(mem_ctx);
307 nt_status = samba_kdc_update_pac_blob(mem_ctx, context,
308 krbtgt_skdc_entry->kdc_db_ctx->samdb,
311 if (!NT_STATUS_IS_OK(nt_status)) {
312 DBG_ERR("samba_kdc_update_pac_blob() failed: %s\n",
313 nt_errstr(nt_status));
314 talloc_free(mem_ctx);
319 /* Check the types of the given PAC */
320 ret = krb5_pac_get_types(context, *pac, &num_types, &types);
322 talloc_free(mem_ctx);
326 for (i = 0; i < num_types; i++) {
328 case PAC_TYPE_LOGON_INFO:
329 if (logon_info_idx != -1) {
330 DEBUG(1, ("logon info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
335 talloc_free(mem_ctx);
340 case PAC_TYPE_CONSTRAINED_DELEGATION:
341 if (delegation_idx != -1) {
342 DEBUG(1, ("constrained delegation type[%"PRIu32"] twice [%zd] and [%zu]: \n",
347 talloc_free(mem_ctx);
352 case PAC_TYPE_LOGON_NAME:
353 if (logon_name_idx != -1) {
354 DEBUG(1, ("logon name type[%"PRIu32"] twice [%zd] and [%zu]: \n",
359 talloc_free(mem_ctx);
364 case PAC_TYPE_UPN_DNS_INFO:
365 if (upn_dns_info_idx != -1) {
366 DEBUG(1, ("upn dns info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
371 talloc_free(mem_ctx);
374 upn_dns_info_idx = i;
376 case PAC_TYPE_SRV_CHECKSUM:
377 if (srv_checksum_idx != -1) {
378 DEBUG(1, ("server checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
383 talloc_free(mem_ctx);
386 srv_checksum_idx = i;
388 case PAC_TYPE_KDC_CHECKSUM:
389 if (kdc_checksum_idx != -1) {
390 DEBUG(1, ("kdc checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
395 talloc_free(mem_ctx);
398 kdc_checksum_idx = i;
400 case PAC_TYPE_TICKET_CHECKSUM:
401 if (tkt_checksum_idx != -1) {
402 DEBUG(1, ("ticket checksum type[%"PRIu32"] twice [%zd] and [%zu]: \n",
407 talloc_free(mem_ctx);
410 tkt_checksum_idx = i;
412 case PAC_TYPE_ATTRIBUTES_INFO:
413 if (attrs_info_idx != -1) {
414 DEBUG(1, ("attributes info type[%"PRIu32"] twice [%zd] and [%zu]: \n",
419 talloc_free(mem_ctx);
424 case PAC_TYPE_REQUESTER_SID:
425 if (requester_sid_idx != -1) {
426 DEBUG(1, ("requester sid type[%"PRIu32"] twice [%zd] and [%zu]: \n",
431 talloc_free(mem_ctx);
434 requester_sid_idx = i;
441 if (logon_info_idx == -1) {
442 DEBUG(1, ("PAC_TYPE_LOGON_INFO missing\n"));
444 talloc_free(mem_ctx);
447 if (logon_name_idx == -1) {
448 DEBUG(1, ("PAC_TYPE_LOGON_NAME missing\n"));
450 talloc_free(mem_ctx);
453 if (srv_checksum_idx == -1) {
454 DEBUG(1, ("PAC_TYPE_SRV_CHECKSUM missing\n"));
456 talloc_free(mem_ctx);
459 if (kdc_checksum_idx == -1) {
460 DEBUG(1, ("PAC_TYPE_KDC_CHECKSUM missing\n"));
462 talloc_free(mem_ctx);
465 if (delegated_proxy_principal == NULL && requester_sid_idx == -1) {
466 DEBUG(1, ("PAC_TYPE_REQUESTER_SID missing\n"));
468 talloc_free(mem_ctx);
469 return KRB5KDC_ERR_TGT_REVOKED;
473 * The server account may be set not to want the PAC.
475 * While this is wasteful if the above cacluations were done
476 * and now thrown away, this is cleaner as we do any ticket
477 * signature checking etc always.
479 * UF_NO_AUTH_DATA_REQUIRED is the rare case and most of the
480 * time (eg not accepting a ticket from the RODC) we do not
481 * need to re-generate anything anyway.
483 if (!samba_princ_needs_pac(server_skdc_entry)) {
489 is_krbtgt = krb5_principal_is_krbtgt(context, server->principal);
491 if (!is_untrusted && !is_krbtgt) {
493 * The client may have requested no PAC when obtaining the
497 ret = samba_client_requested_pac(context, pac, mem_ctx,
499 if (ret != 0 || !requested_pac) {
505 /* Otherwise build an updated PAC */
506 ret = krb5_pac_init(context, &new_pac);
513 const uint8_t zero_byte = 0;
515 DATA_BLOB type_blob = data_blob_null;
518 if (forced_next_type != 0) {
520 * We need to inject possible missing types
522 type = forced_next_type;
523 forced_next_type = 0;
524 } else if (i < num_types) {
532 case PAC_TYPE_LOGON_INFO:
533 type_blob = *pac_blob;
535 if (delegation_idx == -1 && deleg_blob != NULL) {
536 /* inject CONSTRAINED_DELEGATION behind */
537 forced_next_type = PAC_TYPE_CONSTRAINED_DELEGATION;
540 case PAC_TYPE_CONSTRAINED_DELEGATION:
541 if (deleg_blob != NULL) {
542 type_blob = *deleg_blob;
545 case PAC_TYPE_CREDENTIAL_INFO:
547 * Note that we copy the credential blob,
548 * as it's only usable with the PKINIT based
549 * AS-REP reply key, it's only available on the
550 * host which did the AS-REQ/AS-REP exchange.
552 * This matches Windows 2008R2...
555 case PAC_TYPE_LOGON_NAME:
557 * this is generated in the main KDC code
558 * we just add a place holder here.
560 type_blob = data_blob_const(&zero_byte, 1);
562 if (upn_dns_info_idx == -1 && upn_blob != NULL) {
563 /* inject UPN_DNS_INFO behind */
564 forced_next_type = PAC_TYPE_UPN_DNS_INFO;
567 case PAC_TYPE_UPN_DNS_INFO:
569 * Replace in the RODC case, otherwise
570 * upn_blob is NULL and we just copy.
572 if (upn_blob != NULL) {
573 type_blob = *upn_blob;
576 case PAC_TYPE_SRV_CHECKSUM:
578 * this are generated in the main KDC code
579 * we just add a place holder here.
581 type_blob = data_blob_const(&zero_byte, 1);
583 if (requester_sid_idx == -1 && requester_sid_blob != NULL) {
584 /* inject REQUESTER_SID behind */
585 forced_next_type = PAC_TYPE_REQUESTER_SID;
588 case PAC_TYPE_KDC_CHECKSUM:
590 * this are generated in the main KDC code
591 * we just add a place holders here.
593 type_blob = data_blob_const(&zero_byte, 1);
595 case PAC_TYPE_ATTRIBUTES_INFO:
596 if (!is_untrusted && is_krbtgt) {
602 case PAC_TYPE_REQUESTER_SID:
605 * Replace in the RODC case, otherwise
606 * requester_sid_blob is NULL and we just copy.
608 if (requester_sid_blob != NULL) {
609 type_blob = *requester_sid_blob;
620 if (type_blob.length != 0) {
621 ret = smb_krb5_copy_data_contents(&type_data,
626 krb5_pac_free(context, new_pac);
627 talloc_free(mem_ctx);
631 ret = krb5_pac_get_buffer(context, *pac,
635 krb5_pac_free(context, new_pac);
636 talloc_free(mem_ctx);
641 ret = krb5_pac_add_buffer(context, new_pac,
643 smb_krb5_free_data_contents(context, &type_data);
646 krb5_pac_free(context, new_pac);
647 talloc_free(mem_ctx);
656 /* We now replace the pac */
657 krb5_pac_free(context, *pac);
660 talloc_free(mem_ctx);
664 /* Resign (and reform, including possibly new groups) a PAC */
666 static krb5_error_code samba_wdc_reget_pac(void *priv, krb5_context context,
667 krb5_kdc_configuration *config,
668 const krb5_principal client_principal,
669 const krb5_principal delegated_proxy_principal,
675 struct samba_kdc_entry *krbtgt_skdc_entry =
676 talloc_get_type_abort(krbtgt->context,
677 struct samba_kdc_entry);
679 krb5_cksumtype ctype = CKSUMTYPE_NONE;
680 hdb_entry signing_krbtgt_hdb;
682 if (delegated_proxy_principal) {
684 unsigned int my_krbtgt_number;
687 * We're using delegated_proxy_principal for the moment to
688 * indicate cases where the ticket was encrypted with the server
689 * key, and not a krbtgt key. This cannot be trusted, so we need
690 * to find a krbtgt key that signs the PAC in order to trust the
693 * The krbtgt passed in to this function refers to the krbtgt
694 * used to decrypt the ticket of the server requesting
697 * When we implement service ticket renewal, we need to check
698 * the PAC, and this will need to be updated.
700 ret = krb5_pac_get_kdc_checksum_info(context,
705 DEBUG(1, ("Failed to get PAC checksum info\n"));
710 * We need to check the KDC and ticket signatures, fetching the
711 * correct key based on the enctype.
714 my_krbtgt_number = krbtgt_skdc_entry->kdc_db_ctx->my_krbtgt_number;
716 if (my_krbtgt_number != 0) {
718 * If we are an RODC, and we are not the KDC that signed
719 * the evidence ticket, then we need to proxy the
722 if (rodc_id != my_krbtgt_number) {
723 return HDB_ERR_NOT_FOUND_HERE;
727 * If we are a DC, the ticket may have been signed by a
728 * different KDC than the one that issued the header
731 if (rodc_id != krbtgt->kvno >> 16) {
732 struct sdb_entry_ex signing_krbtgt_sdb;
735 * If we didn't sign the ticket, then return an
739 return KRB5KRB_AP_ERR_MODIFIED;
743 * Fetch our key from the database. To support
744 * key rollover, we're going to need to try
745 * multiple keys by trial and error. For now,
746 * krbtgt keys aren't assumed to change.
748 ret = samba_kdc_fetch(context,
749 krbtgt_skdc_entry->kdc_db_ctx,
751 SDB_F_GET_KRBTGT | SDB_F_CANON,
753 &signing_krbtgt_sdb);
758 ret = sdb_entry_ex_to_hdb_entry_ex(context,
760 &signing_krbtgt_hdb);
761 sdb_free_entry(&signing_krbtgt_sdb);
767 * Replace the krbtgt entry with our own entry
768 * for further processing.
770 krbtgt = &signing_krbtgt_hdb;
775 ret = samba_wdc_reget_pac2(context,
776 delegated_proxy_principal,
783 if (krbtgt == &signing_krbtgt_hdb) {
784 hdb_free_entry(context, config->db[0], &signing_krbtgt_hdb);
790 static char *get_netbios_name(TALLOC_CTX *mem_ctx, HostAddresses *addrs)
792 char *nb_name = NULL;
796 for (i = 0; addrs && i < addrs->len; i++) {
797 if (addrs->val[i].addr_type != KRB5_ADDRESS_NETBIOS) {
800 len = MIN(addrs->val[i].address.length, 15);
801 nb_name = talloc_strndup(mem_ctx,
802 addrs->val[i].address.data, len);
808 if ((nb_name == NULL) || (nb_name[0] == '\0')) {
812 /* Strip space padding */
813 for (len = strlen(nb_name) - 1;
814 (len > 0) && (nb_name[len] == ' ');
822 /* this function allocates 'data' using malloc.
823 * The caller is responsible for freeing it */
824 static void samba_kdc_build_edata_reply(NTSTATUS nt_status, krb5_data *e_data)
826 e_data->data = malloc(12);
827 if (e_data->data == NULL) {
834 SIVAL(e_data->data, 0, NT_STATUS_V(nt_status));
835 SIVAL(e_data->data, 4, 0);
836 SIVAL(e_data->data, 8, 1);
841 static krb5_error_code samba_wdc_check_client_access(void *priv,
844 struct samba_kdc_entry *kdc_entry;
845 bool password_change;
850 kdc_entry = talloc_get_type(kdc_request_get_client(r)->context, struct samba_kdc_entry);
851 password_change = (kdc_request_get_server(r) && kdc_request_get_server(r)->flags.change_pw);
852 workstation = get_netbios_name((TALLOC_CTX *)kdc_request_get_client(r)->context,
853 kdc_request_get_req(r)->req_body.addresses);
855 nt_status = samba_kdc_check_client_access(kdc_entry,
856 kdc_request_get_cname((kdc_request_t)r),
860 if (!NT_STATUS_IS_OK(nt_status)) {
861 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
865 if (kdc_request_get_rep(r)->padata) {
869 samba_kdc_build_edata_reply(nt_status, &kd);
870 ret = krb5_padata_add(kdc_request_get_context((kdc_request_t)r), kdc_request_get_rep(r)->padata,
875 * So we do not leak the allocated
876 * memory on kd in the error case
882 return samba_kdc_map_policy_err(nt_status);
885 /* Now do the standard Heimdal check */
886 return KRB5_PLUGIN_NO_HANDLE;
889 /* this function allocates 'data' using malloc.
890 * The caller is responsible for freeing it */
891 static krb5_error_code samba_kdc_build_supported_etypes(uint32_t supported_etypes,
894 e_data->data = malloc(4);
895 if (e_data->data == NULL) {
900 PUSH_LE_U32(e_data->data, 0, supported_etypes);
905 static krb5_error_code samba_wdc_finalize_reply(void *priv,
908 struct samba_kdc_entry *server_kdc_entry;
909 uint32_t supported_enctypes;
911 server_kdc_entry = talloc_get_type(kdc_request_get_server(r)->context, struct samba_kdc_entry);
914 * If the canonicalize flag is set, add PA-SUPPORTED-ENCTYPES padata
915 * type to indicate what encryption types the server supports.
917 supported_enctypes = server_kdc_entry->supported_enctypes;
918 if (kdc_request_get_req(r)->req_body.kdc_options.canonicalize && supported_enctypes != 0) {
923 ret = samba_kdc_build_supported_etypes(supported_enctypes, &md.padata_value);
928 md.padata_type = KRB5_PADATA_SUPPORTED_ETYPES;
930 ret = kdc_request_add_encrypted_padata(r, &md);
933 * So we do not leak the allocated
934 * memory on kd in the error case
936 krb5_data_free(&md.padata_value);
943 static krb5_error_code samba_wdc_plugin_init(krb5_context context, void **ptr)
949 static void samba_wdc_plugin_fini(void *ptr)
954 static krb5_error_code samba_wdc_referral_policy(void *priv,
957 return kdc_request_get_error_code((kdc_request_t)r);
960 struct krb5plugin_kdc_ftable kdc_plugin_table = {
961 .minor_version = KRB5_PLUGIN_KDC_VERSION_10,
962 .init = samba_wdc_plugin_init,
963 .fini = samba_wdc_plugin_fini,
964 .pac_verify = samba_wdc_reget_pac,
965 .client_access = samba_wdc_check_client_access,
966 .finalize_reply = samba_wdc_finalize_reply,
967 .pac_generate = samba_wdc_get_pac,
968 .referral_policy = samba_wdc_referral_policy,