krb5 commit: Replace AD-SIGNEDPATH with minimal PACs
Greg Hudson
ghudson at mit.edu
Wed Jan 12 14:38:40 EST 2022
https://github.com/krb5/krb5/commit/a441fbe329ebbd7775eb5d4ccc4a05eef370f08b
commit a441fbe329ebbd7775eb5d4ccc4a05eef370f08b
Author: Greg Hudson <ghudson at mit.edu>
Date: Fri Jan 7 22:41:30 2022 -0500
Replace AD-SIGNEDPATH with minimal PACs
Remove all of the AD-SIGNEDPATH code. Instead, issue a signed minimal
PAC in all tickets and require a valid PAC to be present in all
tickets presented for S4U operations. Remove the get_authdata_info()
and sign_authdata() DAL methods, and add an issue_pac() method to
allow the KDB to add or copy buffers to the PAC. Add a disable_pac
realm flag.
Microsoft revised the S4U2Proxy rules for forwardable tickets. All
S4U2Proxy operations require forwardable evidence tickets, but
S4U2Self should issue a forwardable ticket if the requesting service
has no ok-to-auth-as-delegate bit but also no constrained delegation
privileges for traditional S4U2Proxy. Implement these rules,
extending the check_allowed_to_delegate() DAL method so that the KDC
can ask if a principal has any delegation privileges.
Combine the KRB5_KDB_FLAG_ISSUE_PAC and
KRB5_FLAG_CLIENT_REFERRALS_ONLY flags into KRB5_KDB_FLAG_CLIENT.
Rename the KRB5_KDB_FLAG_CANONICALIZE flag to
KRB5_KDB_FLAG_REFERRAL_OK, and only pass it to get_principal() for
lookup operations that can use a realm referral.
For consistency with Active Directory, honor the no-auth-data-required
server principal flag for S4U2Proxy but not for S4U2Self. Previously
we did the reverse.
ticket: 9044 (new)
doc/admin/conf_files/kdc_conf.rst | 6 +
src/include/k5-int.h | 26 +-
src/include/kdb.h | 330 ++++++---------
src/kdc/do_as_req.c | 33 +-
src/kdc/do_tgs_req.c | 131 +++---
src/kdc/kdc_authdata.c | 651 ++++++++-------------------
src/kdc/kdc_util.c | 221 +++++++---
src/kdc/kdc_util.h | 64 ++-
src/kdc/main.c | 5 +
src/kdc/realm_data.h | 1 +
src/kdc/tgs_policy.c | 222 ++++++++--
src/lib/kdb/kdb5.c | 99 +----
src/lib/kdb/libkdb5.exports | 4 +-
src/lib/krb5/asn.1/asn1_k_encode.c | 30 --
src/lib/krb5/krb/Makefile.in | 5 +-
src/lib/krb5/krb/authdata.c | 1 -
src/lib/krb5/krb/deps | 12 -
src/lib/krb5/krb/kfree.c | 18 -
src/lib/krb5/krb/s4u_authdata.c | 598 ------------------------
src/lib/krb5/libkrb5.exports | 4 -
src/plugins/kdb/db2/db2_exp.c | 13 +-
src/plugins/kdb/ldap/ldap_exp.c | 1 -
src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c | 4 +-
src/plugins/kdb/test/kdb_test.c | 530 ++++------------------
src/tests/asn.1/krb5_decode_leak.c | 10 -
src/tests/asn.1/krb5_decode_test.c | 8 -
src/tests/asn.1/krb5_encode_test.c | 17 -
src/tests/asn.1/ktest.c | 55 ---
src/tests/asn.1/ktest.h | 4 -
src/tests/asn.1/ktest_equal.c | 28 --
src/tests/asn.1/ktest_equal.h | 4 -
src/tests/asn.1/reference_encode.out | 2 -
src/tests/asn.1/trval_reference.out | 49 --
src/tests/gssapi/t_s4u.py | 20 +-
src/tests/t_authdata.py | 76 +---
35 files changed, 957 insertions(+), 2325 deletions(-)
diff --git a/doc/admin/conf_files/kdc_conf.rst b/doc/admin/conf_files/kdc_conf.rst
index 1dc958d..74a0a2a 100644
--- a/doc/admin/conf_files/kdc_conf.rst
+++ b/doc/admin/conf_files/kdc_conf.rst
@@ -208,6 +208,12 @@ The following tags may be specified in a [realms] subsection:
if there is no policy assigned to the principal, no dictionary
checks of passwords will be performed.
+**disable_pac**
+ (Boolean value.) If true, the KDC will not issue PACs for this
+ realm, and S4U2Self and S4U2Proxy operations will be disabled.
+ The default is false, which will permit the KDC to issue PACs.
+ New in release 1.20.
+
**encrypted_challenge_indicator**
(String.) Specifies the authentication indicator value that the KDC
asserts into tickets obtained using FAST encrypted challenge
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 12aeb1e..44dc1ee 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -205,6 +205,7 @@ typedef unsigned char u_char;
#define KRB5_CONF_DISABLE_ENCRYPTED_TIMESTAMP "disable_encrypted_timestamp"
#define KRB5_CONF_DISABLE_LAST_SUCCESS "disable_last_success"
#define KRB5_CONF_DISABLE_LOCKOUT "disable_lockout"
+#define KRB5_CONF_DISABLE_PAC "disable_pac"
#define KRB5_CONF_DNS_CANONICALIZE_HOSTNAME "dns_canonicalize_hostname"
#define KRB5_CONF_DNS_FALLBACK "dns_fallback"
#define KRB5_CONF_DNS_LOOKUP_KDC "dns_lookup_kdc"
@@ -816,21 +817,6 @@ typedef struct _krb5_ad_kdcissued {
krb5_authdata **elements;
} krb5_ad_kdcissued;
-typedef struct _krb5_ad_signedpath_data {
- krb5_principal client;
- krb5_timestamp authtime;
- krb5_principal *delegated;
- krb5_pa_data **method_data;
- krb5_authdata **authorization_data;
-} krb5_ad_signedpath_data;
-
-typedef struct _krb5_ad_signedpath {
- krb5_enctype enctype;
- krb5_checksum checksum;
- krb5_principal *delegated;
- krb5_pa_data **method_data;
-} krb5_ad_signedpath;
-
typedef struct _krb5_iakerb_header {
krb5_data target_realm;
krb5_data *cookie;
@@ -949,7 +935,6 @@ void KRB5_CALLCONV krb5_free_fast_req(krb5_context, krb5_fast_req *);
void KRB5_CALLCONV krb5_free_fast_finished(krb5_context, krb5_fast_finished *);
void KRB5_CALLCONV krb5_free_fast_response(krb5_context, krb5_fast_response *);
void KRB5_CALLCONV krb5_free_ad_kdcissued(krb5_context, krb5_ad_kdcissued *);
-void KRB5_CALLCONV krb5_free_ad_signedpath(krb5_context, krb5_ad_signedpath *);
void KRB5_CALLCONV krb5_free_iakerb_header(krb5_context, krb5_iakerb_header *);
void KRB5_CALLCONV krb5_free_iakerb_finished(krb5_context,
krb5_iakerb_finished *);
@@ -1514,12 +1499,6 @@ krb5_error_code
encode_krb5_ad_kdcissued(const krb5_ad_kdcissued *, krb5_data **);
krb5_error_code
-encode_krb5_ad_signedpath(const krb5_ad_signedpath *, krb5_data **);
-
-krb5_error_code
-encode_krb5_ad_signedpath_data(const krb5_ad_signedpath_data *, krb5_data **);
-
-krb5_error_code
encode_krb5_otp_tokeninfo(const krb5_otp_tokeninfo *, krb5_data **);
krb5_error_code
@@ -1696,9 +1675,6 @@ krb5_error_code
decode_krb5_ad_kdcissued(const krb5_data *, krb5_ad_kdcissued **);
krb5_error_code
-decode_krb5_ad_signedpath(const krb5_data *, krb5_ad_signedpath **);
-
-krb5_error_code
decode_krb5_iakerb_header(const krb5_data *, krb5_iakerb_header **);
krb5_error_code
diff --git a/src/include/kdb.h b/src/include/kdb.h
index f6cbb47..1fa7bc5 100644
--- a/src/include/kdb.h
+++ b/src/include/kdb.h
@@ -105,12 +105,10 @@
#define KRB5_KDB_CREATE_HASH 0x00000002
/* Entry get flags */
-/* Name canonicalization requested */
-#define KRB5_KDB_FLAG_CANONICALIZE 0x00000010
-/* Include authorization data generated by backend */
-#define KRB5_KDB_FLAG_INCLUDE_PAC 0x00000020
-/* Is AS-REQ (client referrals only) */
-#define KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY 0x00000040
+/* Okay to generate a referral on lookup */
+#define KRB5_KDB_FLAG_REFERRAL_OK 0x00000010
+/* Client principal lookup (client referrals only) */
+#define KRB5_KDB_FLAG_CLIENT 0x00000040
/* Map cross-realm principals */
#define KRB5_KDB_FLAG_MAP_PRINCIPALS 0x00000080
/* Protocol transition */
@@ -656,25 +654,6 @@ krb5_db_get_key_data_kvno( krb5_context context,
int count,
krb5_key_data * data);
-krb5_error_code krb5_db_sign_authdata(krb5_context kcontext,
- unsigned int flags,
- krb5_const_principal client_princ,
- krb5_const_principal server_princ,
- krb5_db_entry *client,
- krb5_db_entry *server,
- krb5_db_entry *header_server,
- krb5_db_entry *local_tgt,
- krb5_keyblock *client_key,
- krb5_keyblock *server_key,
- krb5_keyblock *header_key,
- krb5_keyblock *local_tgt_key,
- krb5_keyblock *session_key,
- krb5_timestamp authtime,
- krb5_authdata **tgt_auth_data,
- void *ad_info,
- krb5_data ***auth_indicators,
- krb5_authdata ***signed_auth_data);
-
krb5_error_code krb5_db_check_transited_realms(krb5_context kcontext,
const krb5_data *tr_contents,
const krb5_data *client_realm,
@@ -717,23 +696,9 @@ krb5_error_code krb5_db_get_s4u_x509_principal(krb5_context kcontext,
krb5_error_code krb5_db_allowed_to_delegate_from(krb5_context context,
krb5_const_principal client,
krb5_const_principal server,
- void *server_ad_info,
+ krb5_pac server_pac,
const krb5_db_entry *proxy);
-krb5_error_code krb5_db_get_authdata_info(krb5_context context,
- unsigned int flags,
- krb5_authdata **in_authdata,
- krb5_const_principal client_princ,
- krb5_const_principal server_princ,
- krb5_keyblock *server_key,
- krb5_keyblock *krbtgt_key,
- krb5_db_entry *krbtgt,
- krb5_timestamp authtime,
- void **ad_info_out,
- krb5_principal *client_out);
-
-void krb5_db_free_authdata_info(krb5_context context, void *ad_info);
-
/**
* Sort an array of @a krb5_key_data keys in descending order by their kvno.
* Key data order within a kvno is preserved.
@@ -747,6 +712,13 @@ void krb5_db_free_authdata_info(krb5_context context, void *ad_info);
void
krb5_dbe_sort_key_data(krb5_key_data *key_data, size_t key_data_length);
+krb5_error_code
+krb5_db_issue_pac(krb5_context context, unsigned int flags,
+ krb5_db_entry *client, krb5_keyblock *replaced_reply_key,
+ krb5_db_entry *server, krb5_db_entry *krbtgt,
+ krb5_timestamp authtime, krb5_pac old_pac, krb5_pac new_pac,
+ krb5_data ***auth_indicators);
+
/* default functions. Should not be directly called */
/*
* Default functions prototype
@@ -894,7 +866,35 @@ krb5_error_code krb5_db_register_keytab(krb5_context context);
* This number indicates the date of the last incompatible change to the DAL.
* The maj_ver field of the module's vtable structure must match this version.
*/
-#define KRB5_KDB_DAL_MAJOR_VERSION 8
+#define KRB5_KDB_DAL_MAJOR_VERSION 9
+
+/*
+ * Note the following when converting a module to DAL version 9:
+ *
+ * - get_authdata_info() and sign_authdata() have been removed, and issue_pac()
+ * has been added.
+ *
+ * - check_allowed_to_delegate() must handle a null proxy argument, returning
+ * success if server has any authorized delegation targets in the traditional
+ * scheme.
+ *
+ * - allowed_to_delegate_from() accepts a krb5_pac parameter (in place
+ * server_ad_info) for the impersonator's PAC.
+ *
+ * - check_allowed_to_delegate() and allowed_to_delegate_from() must return
+ * KRB5KDC_ERR_BADOPTION on authorization failure.
+ *
+ * - the KRB5_KDB_FLAG_ISSUE_PAC and KRB5_FLAG_CLIENT_REFERRALS_ONLY flags have
+ * been combined into KRB5_KDB_FLAG_CLIENT.
+ *
+ * - the KRB5_KDB_FLAG_CANONICALIZE flag has been renamed to
+ * KRB5_KDB_FLAG_REFERRAL_OK, and is only passed to get_principal() when a
+ * realm referral is allowed (AS client and TGS server lookups, when the
+ * CANONICALIZE option is requested or, for AS requests, when the client is
+ * an enterprise principal). As of DAL version 8 the KDB module should
+ * always canonicalize aliases within a realm; the KDC will decide whether to
+ * use the original or canonical principal.
+ */
/*
* A krb5_context can hold one database object. Modules should use
@@ -1008,17 +1008,14 @@ typedef struct _kdb_vftabl {
*
* The meaning of flags are as follows:
*
- * KRB5_KDB_FLAG_CANONICALIZE: Set by the KDC when looking up entries for
- * an AS or TGS request with canonicalization requested. Determines
- * whether the module should return out-of-realm referrals.
- *
- * KRB5_KDB_FLAG_INCLUDE_PAC: Set by the KDC during an AS request when the
- * client requested PAC information during padata, and during most TGS
- * requests. Indicates that the module should include PAC information
- * when its sign_authdata method is invoked.
+ * KRB5_KDB_FLAG_REFERRAL_OK: Set by the KDC when looking up entries for an
+ * AS client with canonicalization requested or for an enterprise
+ * principal, or for a TGS request server with canonicalization
+ * requested. Determines whether the module should return out-of-realm
+ * referrals.
*
- * KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY: Set by the KDC when looking up the
- * client entry in an AS request. Affects how the module should return
+ * KRB5_KDB_FLAG_CLIENT: Set by the KDC when looking up a client principal
+ * during an AS or TGS request. Affects how the module should return
* out-of-realm referrals.
*
* KRB5_KDB_FLAG_MAP_PRINCIPALS: Set by the KDC when looking up the client
@@ -1049,18 +1046,12 @@ typedef struct _kdb_vftabl {
* canonical name. The KDC will decide based on the request whether to use
* the requested name or the canonical name in the issued ticket.
*
- * A module can return a referral to another realm if
- * KRB5_KDB_FLAG_CANONICALIZE is set, or if
- * KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY is set and search_for->type is
- * KRB5_NT_ENTERPRISE_PRINCIPAL. If KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY is
- * set, the module should return a referral by simply filling in an
- * out-of-realm name in (*entry)->princ and setting all other fields to
- * NULL. Otherwise, the module should return the entry for the cross-realm
- * TGS of the referred-to realm. For TGS referals, the module can also
- * include tl-data of type KRB5_TL_SERVER_REFERRAL containing ASN.1-encoded
- * Windows referral data as documented in
- * draft-ietf-krb-wg-kerberos-referrals-11 appendix A; this will be
- * returned to the client as encrypted padata.
+ * A module can return a referral to another realm if flags contains
+ * KRB5_KDB_FLAG_REFERRAL_OK. If KRB5_KDB_FLAG_CLIENT is also set, the
+ * module should return a referral by simply filling in an out-of-realm
+ * name in (*entry)->princ and setting all other fields to NULL.
+ * Otherwise, the module should return the entry for the cross-realm TGS of
+ * the referred-to realm.
*/
krb5_error_code (*get_principal)(krb5_context kcontext,
krb5_const_principal search_for,
@@ -1275,91 +1266,6 @@ typedef struct _kdb_vftabl {
int keyver, krb5_key_data *key_data);
/*
- * Optional: Generate signed authorization data, such as a Windows PAC, for
- * the ticket to be returned to the client. Place the signed authorization
- * data, if any, in *signed_auth_data. This function will be invoked for
- * an AS request if the client included padata requesting a PAC. This
- * function will be invoked for a TGS request if there is authorization
- * data in the TGT, if the client is from another realm, or if the TGS
- * request is an S4U2Self or S4U2Proxy request. This function will not be
- * invoked during TGS requests if the server principal has the
- * no_auth_data_required attribute set. Input parameters are:
- *
- * flags: The flags used to look up the client principal.
- *
- * client_princ: For S4U2Self and S4U2Proxy TGS requests, the client
- * principal requested by the service; for regular TGS requests, the
- * possibly-canonicalized client principal.
- *
- * server_princ: The server principal in the request.
- *
- * client: The DB entry of the client if it is in the local realm, NULL
- * if not. For S4U2Self and S4U2Proxy TGS requests, this is the DB
- * entry for the client principal requested by the service.
- *
- * server: The DB entry of the service principal, or of a cross-realm
- * krbtgt principal in case of referral.
- *
- * header_server: For S4U2Proxy requests, the DB entry of the second
- * ticket server. For other TGS requests, the DB entry of the header
- * ticket server. For AS requests, NULL.
- *
- * local_tgt: the DB entry of the local krbtgt principal.
- *
- * client_key: The reply key for the KDC request, before any FAST armor
- * is applied. For AS requests, this may be the client's long-term key
- * or a key chosen by a preauth mechanism. For TGS requests, this may
- * be the subkey found in the AP-REQ or the session key of the TGT.
- *
- * server_key: The server key used to encrypt the returned ticket.
- *
- * header_key: For S4U2Proxy requests, the key used to decrypt the second
- * ticket. For TGS requests, the key used to decrypt the header
- * ticket. For AS requests, NULL.
- *
- * local_tgt_key: The decrypted first key of local_tgt.
- *
- * session_key: The session key of the ticket being granted to the
- * requestor.
- *
- * authtime: The timestamp of the original client authentication time.
- * For AS requests, this is the current time. For TGS requests, this
- * is the authtime of the subject ticket (TGT or S4U2Proxy evidence
- * ticket).
- *
- * tgt_auth_data: For TGS requests, the authorization data present in the
- * subject ticket. For AS requests, NULL.
- *
- * ad_info: For TGS requests, the parsed authorization data if obtained
- * by get_authdata_info method from the authorization data present in
- * the subject ticket. Otherwise NULL.
- *
- * auth_indicators: Points to NULL or a null-terminated list of krb5_data
- * pointers, each containing an authentication indicator (RFC 8129).
- * The method may modify this list, or free it and replace
- * *auth_indicators with NULL, to change which auth indicators will be
- * included in the ticket.
- */
- krb5_error_code (*sign_authdata)(krb5_context kcontext,
- unsigned int flags,
- krb5_const_principal client_princ,
- krb5_const_principal server_princ,
- krb5_db_entry *client,
- krb5_db_entry *server,
- krb5_db_entry *header_server,
- krb5_db_entry *local_tgt,
- krb5_keyblock *client_key,
- krb5_keyblock *server_key,
- krb5_keyblock *header_key,
- krb5_keyblock *local_tgt_key,
- krb5_keyblock *session_key,
- krb5_timestamp authtime,
- krb5_authdata **tgt_auth_data,
- void *ad_info,
- krb5_data ***auth_indicators,
- krb5_authdata ***signed_auth_data);
-
- /*
* Optional: Perform a policy check on a cross-realm ticket's transited
* field. Return 0 if the check authoritatively succeeds,
* KRB5_PLUGIN_NO_HANDLE to use the core transited-checking mechanisms, or
@@ -1424,13 +1330,15 @@ typedef struct _kdb_vftabl {
/*
* Optional: Perform a policy check on server being allowed to obtain
- * tickets from client to proxy. (Note that proxy is the target of the
- * delegation, not the delegating service; the term "proxy" is from the
- * viewpoint of the delegating service asking another service to perform
- * some of its work in the authentication context of the client. This
- * terminology comes from the Microsoft S4U protocol documentation.)
- * Return 0 if policy allows it, or an appropriate error (such as
- * KRB5KDC_ERR_POLICY) if not. If this method is not implemented, all
+ * tickets from client to proxy. If proxy is NULL, check if server has any
+ * authorized delegation targets (client will also be NULL in this case).
+ * (Note that proxy is the target of the delegation, not the delegating
+ * service; the term "proxy" is from the viewpoint of the delegating
+ * service asking another service to perform some of its work in the
+ * authentication context of the client. This terminology comes from the
+ * Microsoft S4U protocol documentation.) Return 0 if policy allows
+ * delegation to the specified target (or to any target if proxy is NULL),
+ * or KRB5KDC_ERR_BADOPTION if not. If this method is not implemented, all
* S4U2Proxy delegation requests will be rejected.
*/
krb5_error_code (*check_allowed_to_delegate)(krb5_context context,
@@ -1446,17 +1354,17 @@ typedef struct _kdb_vftabl {
void (*free_principal_e_data)(krb5_context kcontext, krb5_octet *e_data);
/*
- * Optional: get a principal entry for S4U2Self based on X509 certificate.
+ * Optional: get a client principal entry based on an X.509 certificate.
*
- * If flags include KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY, princ->realm
- * indicates the request realm, but the data components should be ignored.
- * The module can return an out-of-realm client referral as it would for
- * get_principal().
+ * If flags include KRB5_KDB_FLAG_REFERRAL_OK, the certificate was
+ * presented in an AS request. princ->realm indicates the request realm,
+ * but the data components should be ignored. The module can return an
+ * out-of-realm client referral as it would for get_principal().
*
- * If flags does not include KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY, princ is
- * from PA-S4U-X509-USER. If it contains data components (and not just a
- * realm), the module should verify that it is the same as the lookup
- * result for client_cert. The module should not return a referral.
+ * Otherwise, princ is from a TGS request. If it contains data components
+ * (and not just a realm), the module should verify that it is the same as
+ * the lookup result for client_cert. The module should not return a
+ * referral.
*/
krb5_error_code (*get_s4u_x509_principal)(krb5_context kcontext,
const krb5_data *client_cert,
@@ -1469,11 +1377,9 @@ typedef struct _kdb_vftabl {
* tickets from client to proxy. This method is similar to
* check_allowed_to_delegate, but it operates on the target server DB entry
* (called "proxy" here as in Microsoft's protocol documentation) rather
- * than the intermediate server entry. server_ad_info represents the
- * authdata of the intermediate server, as returned by the
- * get_authdata_info method on the header ticket. Return 0 if policy
- * allows the delegation, or an appropriate error (such as
- * KRB5KDC_ERR_POLICY) if not.
+ * than the intermediate server entry. server_pac is the verified PAC from
+ * the authdata of the intermediate server. Return 0 if policy allows the
+ * delegation, or KRB5KDC_ERR_BADOPTION if not.
*
* This method is called for S4U2Proxy requests and implements the
* resource-based constrained delegation variant, which can support
@@ -1485,46 +1391,64 @@ typedef struct _kdb_vftabl {
krb5_error_code (*allowed_to_delegate_from)(krb5_context context,
krb5_const_principal client,
krb5_const_principal server,
- void *server_ad_info,
+ krb5_pac server_pac,
const krb5_db_entry *proxy);
/*
- * Optional: Perform verification and policy checks on authorization data,
- * such as a Windows PAC, based on the request client lookup flags. Return
- * 0 if all checks have passed. Optionally return a representation of the
- * authdata in *ad_info_out, to be consumed by allowed_to_delegate_from and
- * sign_authdata. Returning *ad_info_out is required to support
- * resource-based constrained delegation.
+ * Optional: Add buffers to new_pac using krb5_pac_add_buffer() before it
+ * is signed.
+ *
+ * The caller will handle the following buffer types, so do not copy or add
+ * them:
+ *
+ * KRB5_PAC_SERVER_CHECKSUM
+ * KRB5_PAC_PRIVSVR_CHECKSUM
+ * KRB5_PAC_TICKET_CHECKSUM
+ * KRB5_PAC_CLIENT_INFO
+ * KRB5_PAC_DELEGATION_INFO
+ *
+ * For TGS requests, old_pac is the PAC of the header ticket, except when
+ * KRB5_KDB_FLAG_CONTRAINED_DELEGATION is present in flags, in which case
+ * it is the PAC of the second ticket. If
+ * KRB5_KDB_FLAG_PROTOCOL_TRANSITION is present in flags and client is not
+ * NULL, old_pac is the PAC of the requesting service, not the subject of
+ * the S4U2Self request, and its buffers should not be copied into new_pac.
+ * The signatures and PAC_CLIENT_INFO of old_pac have been verified by the
+ * caller.
+ *
+ * If replaced_reply_key is not null, the request is an AS request and the
+ * reply key was replaced by a preauth mechanism such as PKINIT, meaning
+ * the Kerberos password or long-term key was not used. The module may use
+ * this key to encrypt a PAC_CREDENTIALS_INFO buffer containing credentials
+ * (such as an NTLM hash) that the client would ordinarily derive from the
+ * Kerberos password or long-term key. (Note: this feature is not yet
+ * implemented and the caller will always pass NULL until it is.)
+ *
+ * server is the database entry of the server the ticket will be issued to,
+ * which may be a referral TGS.
*
- * If the KRB5_KDB_FLAG_CONSTRAINED_DELEGATION bit is set, a PAC must be
- * provided and verified, and an error should be returned if the client is
- * not allowed to delegate. If the KRB5_KDB_FLAG_CROSS_REALM bit is also
- * set, set *client_out to the client name in the PAC; this indicates the
- * requested client principal for a cross-realm S4U2Proxy request.
+ * signing_krbtgt is the database entry of the krbtgt principal used to
+ * verify old_pac (or null if old_pac is null). If
+ * KRB5_KDB_FLAG_CROSS_REALM is present in flags, this entry will be an
+ * incoming cross-realm TGS, and the PAC fields should undergo appropriate
+ * filtering based on the trust level of the cross-realm relationship.
*
- * This method is called for TGS requests on the authorization data from
- * the header ticket. For S4U2Proxy requests it is also called on the
- * authorization data from the evidence ticket. If the
- * KRB5_KDB_FLAG_PROTOCOL_TRANSITION bit is set in flags, the authdata is
- * from the header ticket of an S4U2Self referral request, and the supplied
- * client_princ is the requested client.
+ * auth_indicators points to NULL or a null-terminated list of krb5_data
+ * pointers, each containing an authentication indicator (RFC 8129). The
+ * method may modify this list, or free it and replace *auth_indicators
+ * with NULL, to change which auth indicators will be included in the
+ * ticket.
*/
- krb5_error_code (*get_authdata_info)(krb5_context context,
- unsigned int flags,
- krb5_authdata **in_authdata,
- krb5_const_principal client_princ,
- krb5_const_principal server_princ,
- krb5_keyblock *server_key,
- krb5_keyblock *krbtgt_key,
- krb5_db_entry *krbtgt,
- krb5_timestamp authtime,
- void **ad_info_out,
- krb5_principal *client_out);
-
- void (*free_authdata_info)(krb5_context context,
- void *ad_info);
-
- /* End of minor version 0 for major version 8. */
+ krb5_error_code (*issue_pac)(krb5_context context, unsigned int flags,
+ krb5_db_entry *client,
+ krb5_keyblock *replaced_reply_key,
+ krb5_db_entry *server,
+ krb5_db_entry *signing_krbtgt,
+ krb5_timestamp authtime, krb5_pac old_pac,
+ krb5_pac new_pac,
+ krb5_data ***auth_indicators);
+
+ /* End of minor version 0 for major version 9. */
} kdb_vftabl;
#endif /* !defined(_WIN32) */
diff --git a/src/kdc/do_as_req.c b/src/kdc/do_as_req.c
index 0144884..5e966de 100644
--- a/src/kdc/do_as_req.c
+++ b/src/kdc/do_as_req.c
@@ -142,6 +142,7 @@ lookup_client(krb5_context context, krb5_kdc_req *req, unsigned int flags,
if (pa != NULL && pa->length != 0 &&
req->client->type == KRB5_NT_X500_PRINCIPAL) {
cert = make_data(pa->contents, pa->length);
+ flags |= KRB5_KDB_FLAG_REFERRAL_OK;
return krb5_db_get_s4u_x509_principal(context, &cert, req->client,
flags, entry_out);
} else {
@@ -261,7 +262,7 @@ finish_process_as_req(struct as_req_state *state, krb5_error_code errcode)
goto egress;
}
- errcode = handle_authdata(kdc_context, state->c_flags, state->client,
+ errcode = handle_authdata(kdc_active_realm, state->c_flags, state->client,
state->server, NULL, state->local_tgt,
&state->local_tgt_key, &state->client_keyblock,
&state->server_keyblock, NULL, state->req_pkt,
@@ -473,7 +474,6 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
verto_ctx *vctx, loop_respond_fn respond, void *arg)
{
krb5_error_code errcode;
- unsigned int s_flags = 0;
krb5_data encoded_req_body;
krb5_enctype useenctype;
struct as_req_state *state;
@@ -570,19 +570,10 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
goto errout;
limit_string(state->sname);
- /*
- * We set KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY as a hint
- * to the backend to return naming information in lieu
- * of cross realm TGS entries.
- */
- setflag(state->c_flags, KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY);
-
- if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) {
- setflag(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE);
- }
- if (include_pac_p(kdc_context, state->request)) {
- setflag(state->c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
- }
+ setflag(state->c_flags, KRB5_KDB_FLAG_CLIENT);
+ if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) ||
+ state->request->client->type == KRB5_NT_ENTERPRISE_PRINCIPAL)
+ setflag(state->c_flags, KRB5_KDB_FLAG_REFERRAL_OK);
errcode = lookup_client(kdc_context, state->request, state->c_flags,
&state->client);
if (errcode == KRB5_KDB_CANTLOCK_DB)
@@ -602,12 +593,8 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
au_state->stage = SRVC_PRINC;
- s_flags = 0;
- if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) {
- setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
- }
- errcode = krb5_db_get_principal(kdc_context, state->request->server,
- s_flags, &state->server);
+ errcode = krb5_db_get_principal(kdc_context, state->request->server, 0,
+ &state->server);
if (errcode == KRB5_KDB_CANTLOCK_DB)
errcode = KRB5KDC_ERR_SVC_UNAVAILABLE;
if (errcode == KRB5_KDB_NOENTRY) {
@@ -671,7 +658,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
* (the intention is to allow support for Windows "short" realm
* aliases, nothing more).
*/
- if (isflagset(s_flags, KRB5_KDB_FLAG_CANONICALIZE) &&
+ if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE) &&
krb5_is_tgs_principal(state->request->server) &&
krb5_is_tgs_principal(state->server->princ)) {
state->ticket_reply.server = state->server->princ;
@@ -692,7 +679,7 @@ process_as_req(krb5_kdc_req *request, krb5_data *req_pkt,
*/
state->enc_tkt_reply.session = &state->session_key;
- if (isflagset(state->c_flags, KRB5_KDB_FLAG_CANONICALIZE)) {
+ if (isflagset(state->request->kdc_options, KDC_OPT_CANONICALIZE)) {
state->client_princ = *(state->client->princ);
} else {
state->client_princ = *(state->request->client);
diff --git a/src/kdc/do_tgs_req.c b/src/kdc/do_tgs_req.c
index 45837fb..b1a190f 100644
--- a/src/kdc/do_tgs_req.c
+++ b/src/kdc/do_tgs_req.c
@@ -78,7 +78,8 @@ prepare_error_tgs(struct kdc_request_state *, krb5_kdc_req *,krb5_ticket *,int,
krb5_principal,krb5_data **,const char *, krb5_pa_data **);
static krb5_error_code
-decrypt_2ndtkt(kdc_realm_t *, krb5_kdc_req *, krb5_flags, const krb5_ticket **,
+decrypt_2ndtkt(kdc_realm_t *, krb5_kdc_req *, krb5_flags, krb5_db_entry *,
+ krb5_keyblock *, const krb5_ticket **, krb5_pac *,
krb5_db_entry **, krb5_keyblock **, const char **);
static krb5_error_code
@@ -121,7 +122,6 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
krb5_keyblock session_key, local_tgt_key;
krb5_keyblock *reply_key = NULL;
krb5_principal cprinc = NULL, sprinc = NULL, altcprinc = NULL;
- krb5_const_principal authdata_client;
krb5_principal stkt_authdata_client = NULL;
krb5_last_req_entry *nolrarray[2], nolrentry;
int errcode;
@@ -142,7 +142,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
krb5_pa_data **e_data = NULL;
krb5_audit_state *au_state = NULL;
krb5_data **auth_indicators = NULL;
- void *ad_info = NULL, *stkt_ad_info = NULL;
+ krb5_pac header_pac = NULL, stkt_pac = NULL, subject_pac;
memset(&reply, 0, sizeof(reply));
memset(&reply_encpart, 0, sizeof(reply_encpart));
@@ -217,6 +217,14 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
goto cleanup;
}
+ errcode = get_verified_pac(kdc_context, header_ticket->enc_part2,
+ header_server->princ, header_key, local_tgt,
+ &local_tgt_key, &header_pac);
+ if (errcode) {
+ status = "HEADER_PAC";
+ goto cleanup;
+ }
+
/* Ignore (for now) the request modification due to FAST processing. */
au_state->request = request;
@@ -239,10 +247,8 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
/* XXX make sure server here has the proper realm...taken from AP_REQ
header? */
- if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE)) {
- setflag(c_flags, KRB5_KDB_FLAG_CANONICALIZE);
- setflag(s_flags, KRB5_KDB_FLAG_CANONICALIZE);
- }
+ if (isflagset(request->kdc_options, KDC_OPT_CANONICALIZE))
+ setflag(s_flags, KRB5_KDB_FLAG_REFERRAL_OK);
errcode = search_sprinc(kdc_active_realm, request, s_flags, &server,
&status);
@@ -279,17 +285,21 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
if (errcode)
goto cleanup;
}
+ if (s4u_x509_user != NULL)
+ setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);
/* For user-to-user and S4U2Proxy requests, decrypt the second ticket. */
- errcode = decrypt_2ndtkt(kdc_active_realm, request, c_flags,
- &stkt, &stkt_server, &stkt_server_key, &status);
+ errcode = decrypt_2ndtkt(kdc_active_realm, request, c_flags, local_tgt,
+ &local_tgt_key, &stkt, &stkt_pac, &stkt_server,
+ &stkt_server_key, &status);
if (errcode)
goto cleanup;
retval = validate_tgs_request(kdc_active_realm, request, server,
- header_ticket, stkt, stkt_server, kdc_time,
- s4u_x509_user, client, is_crossrealm,
- is_referral, &status, &e_data);
+ header_ticket, header_pac, stkt, stkt_pac,
+ stkt_server, kdc_time, s4u_x509_user,
+ client, is_crossrealm, is_referral,
+ &status, &e_data);
if (retval) {
if (retval == KDC_ERR_POLICY || retval == KDC_ERR_BADOPTION)
au_state->violation = PROT_CONSTRAINT;
@@ -297,44 +307,16 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
goto cleanup;
}
- if (s4u_x509_user != NULL && client == NULL) {
- /*
- * For an S4U2Self referral request (the requesting service is
- * following a referral back to its own realm), the authdata in the
- * header ticket should be for the requested client.
- */
- setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);
- authdata_client = s4u_x509_user->user_id.user;
- } else {
- /* Otherwise (including for initial S4U2Self requests), the authdata
- * should be for the header ticket client. */
- authdata_client = header_enc_tkt->client;
- }
- errcode = krb5_db_get_authdata_info(kdc_context, c_flags,
- header_enc_tkt->authorization_data,
- authdata_client, request->server,
- header_key, &local_tgt_key, local_tgt,
- header_enc_tkt->times.authtime,
- &ad_info, NULL);
- if (errcode && errcode != KRB5_PLUGIN_OP_NOTSUPP)
- goto cleanup;
-
- /* Flag all S4U2Self requests now that we have checked the authdata. */
- if (s4u_x509_user != NULL)
- setflag(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION);
-
if (isflagset(request->kdc_options, KDC_OPT_CNAME_IN_ADDL_TKT)) {
/* Do constrained delegation protocol and authorization checks. */
setflag(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION);
- errcode = kdc_process_s4u2proxy_req(kdc_active_realm, c_flags, request,
- stkt->enc_part2, local_tgt,
- &local_tgt_key, stkt_server,
- stkt_server_key,
+ errcode = kdc_process_s4u2proxy_req(kdc_active_realm, c_flags,
+ request, header_pac,
+ stkt->enc_part2, stkt_pac,
+ stkt_server, stkt_server_key,
header_ticket->enc_part2->client,
- server, request->server, ad_info,
- &stkt_ad_info,
- &stkt_authdata_client,
+ server, &stkt_authdata_client,
&status);
if (errcode == KDC_ERR_POLICY || errcode == KDC_ERR_BADOPTION)
au_state->violation = PROT_CONSTRAINT;
@@ -351,12 +333,6 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
goto cleanup;
assert(krb5_is_tgs_principal(header_ticket->server));
-
- /* Use the parsed authdata from the second ticket during authdata
- * handling. */
- krb5_db_free_authdata_info(kdc_context, ad_info);
- ad_info = stkt_ad_info;
- stkt_ad_info = NULL;
}
au_state->stage = ISSUE_TKT;
@@ -375,10 +351,12 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
subject_tkt = stkt->enc_part2;
+ subject_pac = stkt_pac;
subject_server = stkt_server;
subject_key = stkt_server_key;
} else {
subject_tkt = header_enc_tkt;
+ subject_pac = header_pac;
subject_server = header_server;
subject_key = header_key;
}
@@ -410,12 +388,12 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
server, header_enc_tkt);
enc_tkt_reply.times.starttime = 0;
- /* OK_TO_AUTH_AS_DELEGATE must be set on the service requesting S4U2Self
- * for forwardable tickets to be issued. */
- if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION) &&
- !is_referral &&
- !isflagset(server->attributes, KRB5_KDB_OK_TO_AUTH_AS_DELEGATE))
- clear(enc_tkt_reply.flags, TKT_FLG_FORWARDABLE);
+ if (s4u_x509_user != NULL && !is_referral) {
+ /* Check if we need to suppress the forwardable ticket flag. */
+ errcode = s4u2self_forwardable(kdc_context, server, &enc_tkt_reply);
+ if (errcode)
+ goto cleanup;
+ }
/* don't use new addresses unless forwarded, see below */
@@ -521,11 +499,12 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
encrypting_key = &server_keyblock;
}
- if (isflagset(c_flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION)) {
+ if (isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
/*
- * Don't allow authorization data to be disabled if constrained
- * delegation is requested. We don't want to deny the server
- * the ability to validate that delegation was used.
+ * For consistency with Active Directory, don't allow authorization
+ * data to be disabled if S4U2Self is requested. The server likely
+ * needs a PAC to inspect or for an S4U2Proxy operation, even if it
+ * doesn't need authorization data in tickets received from clients.
*/
clear(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED);
}
@@ -533,8 +512,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
/* If we are not doing protocol transition, try to look up the subject
* principal so that KDB modules can add additional authdata. */
if (!isflagset(c_flags, KRB5_KDB_FLAG_PROTOCOL_TRANSITION)) {
- /* Generate authorization data so we can include it in ticket */
- setflag(c_flags, KRB5_KDB_FLAG_INCLUDE_PAC);
+ setflag(c_flags, KRB5_KDB_FLAG_CLIENT);
/* Map principals from foreign (possibly non-AD) realms */
setflag(c_flags, KRB5_KDB_FLAG_MAP_PRINCIPALS);
@@ -609,12 +587,12 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
goto cleanup;
}
- errcode = handle_authdata(kdc_context, c_flags, client, server,
+ errcode = handle_authdata(kdc_active_realm, c_flags, client, server,
subject_server, local_tgt, &local_tgt_key,
subkey != NULL ? subkey :
header_ticket->enc_part2->session,
encrypting_key, subject_key, pkt, request,
- altcprinc, ad_info, subject_tkt,
+ altcprinc, subject_pac, subject_tkt,
&auth_indicators, &enc_tkt_reply);
if (errcode) {
krb5_klog_syslog(LOG_INFO, _("TGS_REQ : handle_authdata (%d)"),
@@ -694,8 +672,7 @@ process_tgs_req(krb5_kdc_req *request, krb5_data *pkt,
errcode = return_enc_padata(kdc_context, pkt, request,
reply_key, server, &reply_encpart,
is_referral &&
- isflagset(s_flags,
- KRB5_KDB_FLAG_CANONICALIZE));
+ isflagset(s_flags, KRB5_KDB_FLAG_REFERRAL_OK));
if (errcode) {
status = "KDC_RETURN_ENC_PADATA";
goto cleanup;
@@ -802,8 +779,8 @@ cleanup:
krb5_free_authdata(kdc_context, enc_tkt_reply.authorization_data);
krb5_free_pa_data(kdc_context, e_data);
k5_free_data_ptr_list(auth_indicators);
- krb5_db_free_authdata_info(kdc_context, ad_info);
- krb5_db_free_authdata_info(kdc_context, stkt_ad_info);
+ krb5_pac_free(kdc_context, header_pac);
+ krb5_pac_free(kdc_context, stkt_pac);
krb5_free_principal(kdc_context, stkt_authdata_client);
return retval;
@@ -888,9 +865,10 @@ prepare_error_tgs (struct kdc_request_state *state,
*/
static krb5_error_code
decrypt_2ndtkt(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
- krb5_flags flags, const krb5_ticket **stkt_out,
- krb5_db_entry **server_out, krb5_keyblock **key_out,
- const char **status)
+ krb5_flags flags, krb5_db_entry *local_tgt,
+ krb5_keyblock *local_tgt_key, const krb5_ticket **stkt_out,
+ krb5_pac *pac_out, krb5_db_entry **server_out,
+ krb5_keyblock **key_out, const char **status)
{
krb5_error_code retval;
krb5_db_entry *server = NULL;
@@ -899,6 +877,7 @@ decrypt_2ndtkt(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
krb5_ticket *stkt;
*stkt_out = NULL;
+ *pac_out = NULL;
*server_out = NULL;
*key_out = NULL;
@@ -918,6 +897,12 @@ decrypt_2ndtkt(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
*status = "2ND_TKT_DECRYPT";
goto cleanup;
}
+ retval = get_verified_pac(kdc_context, stkt->enc_part2, server->princ,
+ key, local_tgt, local_tgt_key, pac_out);
+ if (retval != 0) {
+ *status = "2ND_TKT_PAC";
+ goto cleanup;
+ }
*stkt_out = stkt;
*server_out = server;
*key_out = key;
@@ -1181,7 +1166,7 @@ search_sprinc(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
* the server is supposed to match an already-issued ticket. */
allow_referral = !(req->kdc_options & NO_REFERRAL_OPTION);
if (!allow_referral)
- flags &= ~KRB5_KDB_FLAG_CANONICALIZE;
+ flags &= ~KRB5_KDB_FLAG_REFERRAL_OK;
ret = db_get_svc_princ(kdc_context, princ, flags, server, status);
if (ret == 0 || ret != KRB5_KDB_NOENTRY || !allow_referral)
diff --git a/src/kdc/kdc_authdata.c b/src/kdc/kdc_authdata.c
index 010922c..3909daf 100644
--- a/src/kdc/kdc_authdata.c
+++ b/src/kdc/kdc_authdata.c
@@ -149,23 +149,6 @@ cleanup:
return result;
}
-/* Return true if authdata contains any elements which should only come from
- * the KDC. If desired_type is non-zero, look only for that type. */
-static krb5_boolean
-has_kdc_issued_authdata(krb5_authdata **authdata,
- krb5_authdatatype desired_type)
-{
- int i;
-
- if (authdata == NULL)
- return FALSE;
- for (i = 0; authdata[i] != NULL; i++) {
- if (is_kdc_issued_authdatum(authdata[i], desired_type))
- return TRUE;
- }
- return FALSE;
-}
-
/* Return true if authdata contains any mandatory-for-KDC elements. */
static krb5_boolean
has_mandatory_for_kdc_authdata(krb5_context context, krb5_authdata **authdata)
@@ -312,405 +295,6 @@ copy_tgt_authdata(krb5_context context, krb5_kdc_req *request,
return add_filtered_authdata(tkt_authdata, tgt_authdata);
}
-/* Fetch authorization data from KDB module. */
-static krb5_error_code
-fetch_kdb_authdata(krb5_context context, unsigned int flags,
- krb5_db_entry *client, krb5_db_entry *server,
- krb5_db_entry *header_server, krb5_db_entry *local_tgt,
- krb5_keyblock *client_key, krb5_keyblock *server_key,
- krb5_keyblock *header_key, krb5_keyblock *local_tgt_key,
- krb5_kdc_req *req, krb5_const_principal altcprinc,
- void *ad_info, krb5_enc_tkt_part *enc_tkt_req,
- krb5_enc_tkt_part *enc_tkt_reply,
- krb5_data ***auth_indicators)
-{
- krb5_error_code ret;
- krb5_authdata **tgt_authdata, **db_authdata = NULL;
- krb5_boolean tgs_req = (req->msg_type == KRB5_TGS_REQ);
- krb5_const_principal actual_client;
-
- /*
- * Check whether KDC issued authorization data should be included.
- * A server can explicitly disable the inclusion of authorization
- * data by setting the KRB5_KDB_NO_AUTH_DATA_REQUIRED flag on its
- * principal entry. Otherwise authorization data will be included
- * if it was present in the TGT, the client is from another realm
- * or protocol transition/constrained delegation was used, or, in
- * the AS-REQ case, if the pre-auth data indicated the PAC should
- * be present.
- */
- if (tgs_req) {
- assert(enc_tkt_req != NULL);
-
- if (isflagset(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED))
- return 0;
-
- if (enc_tkt_req->authorization_data == NULL &&
- !isflagset(flags, KRB5_KDB_FLAG_CROSS_REALM | KRB5_KDB_FLAGS_S4U))
- return 0;
-
- assert(enc_tkt_reply->times.authtime == enc_tkt_req->times.authtime);
- } else {
- if (!isflagset(flags, KRB5_KDB_FLAG_INCLUDE_PAC))
- return 0;
- }
-
- /* S4U referral replies should contain authdata for the requested client,
- * even though they use the requesting service as the ticket client. */
- if (isflagset(flags, KRB5_KDB_FLAGS_S4U))
- actual_client = altcprinc;
- else
- actual_client = enc_tkt_reply->client;
-
- tgt_authdata = tgs_req ? enc_tkt_req->authorization_data : NULL;
- ret = krb5_db_sign_authdata(context, flags, actual_client, req->server,
- client, server, header_server, local_tgt,
- client_key, server_key, header_key,
- local_tgt_key, enc_tkt_reply->session,
- enc_tkt_reply->times.authtime, tgt_authdata,
- ad_info, auth_indicators, &db_authdata);
- if (ret)
- return (ret == KRB5_PLUGIN_OP_NOTSUPP) ? 0 : ret;
-
- /* Put the KDB authdata first in the ticket. A successful merge places the
- * combined list in db_authdata and releases the old ticket authdata. */
- ret = merge_authdata(&db_authdata, &enc_tkt_reply->authorization_data);
- if (ret)
- krb5_free_authdata(context, db_authdata);
- else
- enc_tkt_reply->authorization_data = db_authdata;
- return ret;
-}
-
-static krb5_error_code
-make_signedpath_data(krb5_context context, krb5_const_principal client,
- krb5_timestamp authtime, krb5_principal *deleg_path,
- krb5_pa_data **method_data, krb5_authdata **authdata,
- krb5_data **data)
-{
- krb5_error_code ret;
- krb5_ad_signedpath_data sp_data;
- krb5_authdata **sign_authdata = NULL;
- size_t i, j, count;
-
- memset(&sp_data, 0, sizeof(sp_data));
-
- for (count = 0; authdata != NULL && authdata[count] != NULL; count++);
- if (count != 0) {
- /* Make a shallow copy with AD-SIGNTICKET filtered out. */
- sign_authdata = k5calloc(count + 1, sizeof(krb5_authdata *), &ret);
- if (sign_authdata == NULL)
- return ret;
-
- for (i = 0, j = 0; authdata[i] != NULL; i++) {
- if (is_kdc_issued_authdatum(authdata[i], KRB5_AUTHDATA_SIGNTICKET))
- continue;
-
- sign_authdata[j++] = authdata[i];
- }
-
- sign_authdata[j] = NULL;
- }
-
- sp_data.client = (krb5_principal)client;
- sp_data.authtime = authtime;
- sp_data.delegated = deleg_path;
- sp_data.method_data = method_data;
- sp_data.authorization_data = sign_authdata;
-
- ret = encode_krb5_ad_signedpath_data(&sp_data, data);
-
- if (sign_authdata != NULL)
- free(sign_authdata);
-
- return ret;
-}
-
-static krb5_error_code
-verify_signedpath_checksum(krb5_context context, krb5_db_entry *local_tgt,
- krb5_keyblock *local_tgt_key,
- krb5_enc_tkt_part *enc_tkt_part,
- krb5_principal *deleg_path,
- krb5_pa_data **method_data, krb5_checksum *cksum,
- krb5_boolean *valid_out)
-{
- krb5_error_code ret;
- krb5_data *data;
- krb5_key_data *kd;
- krb5_keyblock tgtkey;
- krb5_kvno kvno;
- krb5_boolean valid = FALSE;
- int tries;
-
- *valid_out = FALSE;
- memset(&tgtkey, 0, sizeof(tgtkey));
-
- if (!krb5_c_is_keyed_cksum(cksum->checksum_type))
- return KRB5KRB_AP_ERR_INAPP_CKSUM;
-
- ret = make_signedpath_data(context, enc_tkt_part->client,
- enc_tkt_part->times.authtime, deleg_path,
- method_data, enc_tkt_part->authorization_data,
- &data);
- if (ret)
- return ret;
-
- ret = krb5_c_verify_checksum(context, local_tgt_key,
- KRB5_KEYUSAGE_AD_SIGNEDPATH, data, cksum,
- &valid);
- if (ret || !valid) {
- /* There is no kvno in AD-SIGNTICKET, so try two previous versions. */
- kvno = local_tgt->key_data[0].key_data_kvno - 1;
- for (tries = 2; tries > 0 && kvno > 0; tries--, kvno--) {
- /* Get the first local tgt key of this kvno. */
- ret = krb5_dbe_find_enctype(context, local_tgt, -1, -1, kvno, &kd);
- if (ret) {
- ret = 0;
- break;
- }
- ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &tgtkey, NULL);
- if (ret)
- break;
-
- ret = krb5_c_verify_checksum(context, &tgtkey,
- KRB5_KEYUSAGE_AD_SIGNEDPATH, data,
- cksum, &valid);
- krb5_free_keyblock_contents(context, &tgtkey);
- if (!ret && valid)
- break;
- }
- }
-
- *valid_out = valid;
- krb5_free_data(context, data);
- return ret;
-}
-
-
-static krb5_error_code
-verify_signedpath(krb5_context context, krb5_db_entry *local_tgt,
- krb5_keyblock *local_tgt_key,
- krb5_enc_tkt_part *enc_tkt_part,
- krb5_principal **delegated_out, krb5_boolean *pathsigned_out)
-{
- krb5_error_code ret;
- krb5_ad_signedpath *sp = NULL;
- krb5_authdata **sp_authdata = NULL;
- krb5_data enc_sp;
-
- *delegated_out = NULL;
- *pathsigned_out = FALSE;
-
- ret = krb5_find_authdata(context, enc_tkt_part->authorization_data, NULL,
- KRB5_AUTHDATA_SIGNTICKET, &sp_authdata);
- if (ret)
- goto cleanup;
-
- if (sp_authdata == NULL ||
- sp_authdata[0]->ad_type != KRB5_AUTHDATA_SIGNTICKET ||
- sp_authdata[1] != NULL)
- goto cleanup;
-
- enc_sp.data = (char *)sp_authdata[0]->contents;
- enc_sp.length = sp_authdata[0]->length;
-
- ret = decode_krb5_ad_signedpath(&enc_sp, &sp);
- if (ret) {
- /* Treat an invalid signedpath authdata element as a missing one, since
- * we believe MS is using the same number for something else. */
- ret = 0;
- goto cleanup;
- }
-
- ret = verify_signedpath_checksum(context, local_tgt, local_tgt_key,
- enc_tkt_part, sp->delegated,
- sp->method_data, &sp->checksum,
- pathsigned_out);
- if (ret)
- goto cleanup;
-
- if (*pathsigned_out) {
- *delegated_out = sp->delegated;
- sp->delegated = NULL;
- }
-
-cleanup:
- krb5_free_ad_signedpath(context, sp);
- krb5_free_authdata(context, sp_authdata);
- return ret;
-}
-
-static krb5_error_code
-make_signedpath_checksum(krb5_context context,
- krb5_const_principal for_user_princ,
- krb5_keyblock *local_tgt_key,
- krb5_enc_tkt_part *enc_tkt_part,
- krb5_principal *deleg_path,
- krb5_pa_data **method_data, krb5_checksum *cksum_out,
- krb5_enctype *enctype_out)
-{
- krb5_error_code ret;
- krb5_data *data = NULL;
- krb5_const_principal client;
-
- memset(cksum_out, 0, sizeof(*cksum_out));
- *enctype_out = ENCTYPE_NULL;
-
- client = (for_user_princ != NULL) ? for_user_princ : enc_tkt_part->client;
-
- ret = make_signedpath_data(context, client, enc_tkt_part->times.authtime,
- deleg_path, method_data,
- enc_tkt_part->authorization_data, &data);
- if (ret)
- return ret;
-
- ret = krb5_c_make_checksum(context, 0, local_tgt_key,
- KRB5_KEYUSAGE_AD_SIGNEDPATH, data, cksum_out);
- krb5_free_data(context, data);
- if (ret)
- return ret;
-
- *enctype_out = local_tgt_key->enctype;
- return 0;
-}
-
-static krb5_error_code
-make_signedpath(krb5_context context, krb5_const_principal for_user_princ,
- krb5_principal server, krb5_keyblock *local_tgt_key,
- krb5_principal *deleg_path, krb5_enc_tkt_part *enc_tkt_reply)
-{
- krb5_error_code ret;
- krb5_ad_signedpath sp;
- krb5_data *data = NULL;
- krb5_authdata ad_datum, *ad_data[2];
- krb5_authdata **if_relevant = NULL;
- size_t count;
-
- memset(&sp, 0, sizeof(sp));
-
- for (count = 0; deleg_path != NULL && deleg_path[count] != NULL; count++);
-
- sp.delegated = k5calloc(count + 2, sizeof(krb5_principal), &ret);
- if (sp.delegated == NULL)
- goto cleanup;
-
- /* Combine existing and new transited services, if any */
- if (deleg_path != NULL)
- memcpy(sp.delegated, deleg_path, count * sizeof(krb5_principal));
- if (server != NULL)
- sp.delegated[count++] = server;
- sp.delegated[count] = NULL;
- sp.method_data = NULL;
-
- ret = make_signedpath_checksum(context, for_user_princ, local_tgt_key,
- enc_tkt_reply, sp.delegated, sp.method_data,
- &sp.checksum, &sp.enctype);
- if (ret) {
- if (ret == KRB5KRB_AP_ERR_INAPP_CKSUM) {
- /*
- * In the hopefully unlikely case the TGS key enctype has an
- * unkeyed mandatory checksum type, do not fail so we do not
- * prevent the KDC from servicing requests.
- */
- ret = 0;
- }
- goto cleanup;
- }
-
- ret = encode_krb5_ad_signedpath(&sp, &data);
- if (ret)
- goto cleanup;
-
- ad_datum.ad_type = KRB5_AUTHDATA_SIGNTICKET;
- ad_datum.contents = (krb5_octet *)data->data;
- ad_datum.length = data->length;
-
- ad_data[0] = &ad_datum;
- ad_data[1] = NULL;
-
- ret = krb5_encode_authdata_container(context, KRB5_AUTHDATA_IF_RELEVANT,
- ad_data, &if_relevant);
- if (ret)
- goto cleanup;
-
- /* Add the signedpath authdata to the ticket. */
- ret = merge_authdata(&enc_tkt_reply->authorization_data, &if_relevant);
-
-cleanup:
- free(sp.delegated);
- krb5_free_authdata(context, if_relevant);
- krb5_free_data(context, data);
- krb5_free_checksum_contents(context, &sp.checksum);
- krb5_free_pa_data(context, sp.method_data);
- return ret;
-}
-
-static void
-free_deleg_path(krb5_context context, krb5_principal *deleg_path)
-{
- int i;
-
- for (i = 0; deleg_path != NULL && deleg_path[i] != NULL; i++)
- krb5_free_principal(context, deleg_path[i]);
- free(deleg_path);
-}
-
-/* Return true if the Windows PAC is present in authorization data. */
-static krb5_boolean
-has_pac(krb5_context context, krb5_authdata **authdata)
-{
- return has_kdc_issued_authdata(authdata, KRB5_AUTHDATA_WIN2K_PAC);
-}
-
-/* Verify AD-SIGNTICKET authdata if we need to, and insert an AD-SIGNEDPATH
- * element if we should. */
-static krb5_error_code
-handle_signticket(krb5_context context, unsigned int flags,
- krb5_db_entry *subject_server, krb5_db_entry *server,
- krb5_db_entry *local_tgt, krb5_keyblock *local_tgt_key,
- krb5_kdc_req *req, krb5_const_principal for_user_princ,
- krb5_enc_tkt_part *enc_tkt_req,
- krb5_enc_tkt_part *enc_tkt_reply)
-{
- krb5_error_code ret = 0;
- krb5_principal *deleg_path = NULL;
- krb5_boolean signed_path = FALSE;
- krb5_boolean s4u2proxy;
-
- s4u2proxy = isflagset(flags, KRB5_KDB_FLAG_CONSTRAINED_DELEGATION);
-
- /* For cross-realm the Windows PAC must have been verified, and it
- * fulfills the same role as the signed path. */
- if (req->msg_type == KRB5_TGS_REQ &&
- (!isflagset(flags, KRB5_KDB_FLAG_CROSS_REALM) ||
- !has_pac(context, enc_tkt_req->authorization_data))) {
- ret = verify_signedpath(context, local_tgt, local_tgt_key, enc_tkt_req,
- &deleg_path, &signed_path);
- if (ret)
- goto cleanup;
-
- if (s4u2proxy && signed_path == FALSE) {
- ret = KRB5KDC_ERR_BADOPTION;
- goto cleanup;
- }
- }
-
- /* No point in including signedpath authdata for a cross-realm TGT, since
- * it will be presented to a different KDC. */
- if (!isflagset(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED) &&
- !is_cross_tgs_principal(server->princ)) {
- ret = make_signedpath(context, for_user_princ,
- s4u2proxy ? subject_server->princ : NULL,
- local_tgt_key, deleg_path, enc_tkt_reply);
- if (ret)
- goto cleanup;
- }
-
-cleanup:
- free_deleg_path(context, deleg_path);
- return ret;
-}
-
/* Add authentication indicator authdata to enc_tkt_reply, wrapped in a CAMMAC
* and an IF-RELEVANT container. */
static krb5_error_code
@@ -723,6 +307,9 @@ add_auth_indicators(krb5_context context, krb5_data *const *auth_indicators,
krb5_data *der_indicators = NULL;
krb5_authdata ad, *list[2], **cammac = NULL;
+ if (auth_indicators == NULL || *auth_indicators == NULL)
+ return 0;
+
/* Format the authentication indicators into an authdata list. */
ret = encode_utf8_strings(auth_indicators, &der_indicators);
if (ret)
@@ -792,21 +379,209 @@ cleanup:
return ret;
}
+static krb5_error_code
+update_delegation_info(krb5_context context, krb5_kdc_req *req,
+ krb5_pac old_pac, krb5_pac new_pac)
+{
+ krb5_error_code ret;
+ krb5_data ndr_di_in = empty_data(), ndr_di_out = empty_data();
+ struct pac_s4u_delegation_info *di = NULL;
+ char *namestr = NULL;
+
+ ret = krb5_pac_get_buffer(context, old_pac, KRB5_PAC_DELEGATION_INFO,
+ &ndr_di_in);
+ if (ret && ret != ENOENT)
+ goto cleanup;
+ if (ret) {
+ /* Create new delegation info. */
+ di = k5alloc(sizeof(*di), &ret);
+ if (di == NULL)
+ goto cleanup;
+ di->transited_services = k5calloc(1, sizeof(char *), &ret);
+ if (di->transited_services == NULL)
+ goto cleanup;
+ } else {
+ /* Decode and modify old delegation info. */
+ ret = ndr_dec_delegation_info(&ndr_di_in, &di);
+ if (ret)
+ goto cleanup;
+ }
+
+ /* Set proxy_target to the requested server, without realm. */
+ ret = krb5_unparse_name_flags(context, req->server,
+ KRB5_PRINCIPAL_UNPARSE_DISPLAY |
+ KRB5_PRINCIPAL_UNPARSE_NO_REALM,
+ &namestr);
+ if (ret)
+ goto cleanup;
+ free(di->proxy_target);
+ di->proxy_target = namestr;
+
+ /* Add a transited entry for the requesting service, with realm. */
+ assert(req->second_ticket != NULL && req->second_ticket[0] != NULL);
+ ret = krb5_unparse_name(context, req->second_ticket[0]->server, &namestr);
+ if (ret)
+ goto cleanup;
+ di->transited_services[di->transited_services_length++] = namestr;
+
+ ret = ndr_enc_delegation_info(di, &ndr_di_out);
+ if (ret)
+ goto cleanup;
+
+ ret = krb5_pac_add_buffer(context, new_pac, KRB5_PAC_DELEGATION_INFO,
+ &ndr_di_out);
+
+cleanup:
+ krb5_free_data_contents(context, &ndr_di_in);
+ krb5_free_data_contents(context, &ndr_di_out);
+ ndr_free_delegation_info(di);
+ return ret;
+}
+
+static krb5_error_code
+copy_pac_buffer(krb5_context context, uint32_t buffer_type, krb5_pac old_pac,
+ krb5_pac new_pac)
+{
+ krb5_error_code ret;
+ krb5_data data;
+
+ ret = krb5_pac_get_buffer(context, old_pac, buffer_type, &data);
+ if (ret)
+ return ret;
+ ret = krb5_pac_add_buffer(context, new_pac, buffer_type, &data);
+ krb5_free_data_contents(context, &data);
+ return ret;
+}
+
+/*
+ * Possibly add a signed PAC to enc_tkt_reply. Also possibly add auth
+ * indicators; these are handled here so that the KDB module's issue_pac()
+ * method can alter the auth indicator list.
+ */
+static krb5_error_code
+handle_pac(kdc_realm_t *kdc_active_realm, unsigned int flags,
+ krb5_db_entry *client, krb5_db_entry *server,
+ krb5_db_entry *subject_server, krb5_db_entry *local_tgt,
+ krb5_keyblock *local_tgt_key, krb5_keyblock *server_key,
+ krb5_keyblock *subject_key, krb5_enc_tkt_part *subject_tkt,
+ krb5_pac subject_pac, krb5_kdc_req *req,
+ krb5_const_principal altcprinc, krb5_timestamp authtime,
+ krb5_enc_tkt_part *enc_tkt_reply, krb5_data ***auth_indicators)
+{
+ krb5_error_code ret;
+ krb5_context context = kdc_context;
+ krb5_pac new_pac = NULL;
+ krb5_const_principal pac_client = NULL;
+ krb5_boolean with_realm, is_as_req = (req->msg_type == KRB5_AS_REQ);
+ krb5_db_entry *signing_tgt;
+
+ /* Don't add a PAC or auth indicators if the server disables authdata. */
+ if (server->attributes & KRB5_KDB_NO_AUTH_DATA_REQUIRED)
+ return 0;
+
+ /*
+ * Don't add a PAC if the realm disables them, or to an anonymous ticket,
+ * or for an AS-REQ if the client requested not to get one, or for a
+ * TGS-REQ if the subject ticket didn't contain one.
+ */
+ if (kdc_active_realm->realm_disable_pac ||
+ (enc_tkt_reply->flags & TKT_FLG_ANONYMOUS) ||
+ (is_as_req && !include_pac_p(context, req)) ||
+ (!is_as_req && subject_pac == NULL)) {
+ return add_auth_indicators(context, *auth_indicators, server_key,
+ local_tgt, local_tgt_key, enc_tkt_reply);
+ }
+
+ ret = krb5_pac_init(context, &new_pac);
+ if (ret)
+ goto cleanup;
+
+ if (subject_pac == NULL)
+ signing_tgt = NULL;
+ else if (krb5_is_tgs_principal(subject_server->princ))
+ signing_tgt = subject_server;
+ else
+ signing_tgt = local_tgt;
+
+ ret = krb5_db_issue_pac(context, flags, client, NULL, server, signing_tgt,
+ authtime, subject_pac, new_pac, auth_indicators);
+ if (ret) {
+ if (ret == KRB5_PLUGIN_OP_NOTSUPP)
+ ret = 0;
+ if (ret)
+ goto cleanup;
+ }
+
+ ret = add_auth_indicators(context, *auth_indicators, server_key,
+ local_tgt, local_tgt_key, enc_tkt_reply);
+
+ if ((flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) &&
+ !(flags & KRB5_KDB_FLAG_CROSS_REALM)) {
+ /* Add delegation info for the first S4U2Proxy request. */
+ ret = update_delegation_info(context, req, subject_pac, new_pac);
+ if (ret)
+ goto cleanup;
+ } else if (subject_pac != NULL) {
+ /* Copy delegation info if it was present in the subject PAC. */
+ ret = copy_pac_buffer(context, KRB5_PAC_DELEGATION_INFO, subject_pac,
+ new_pac);
+ if (ret && ret != ENOENT)
+ goto cleanup;
+ }
+
+ if ((flags & KRB5_KDB_FLAGS_S4U) &&
+ (flags & KRB5_KDB_FLAG_ISSUING_REFERRAL)) {
+ /* When issuing a referral for either kind of S4U request, add client
+ * info for the subject with realm. */
+ pac_client = altcprinc;
+ with_realm = TRUE;
+ } else if (subject_pac == NULL || (flags & KRB5_KDB_FLAGS_S4U)) {
+ /* For a new PAC or when issuing a final ticket for either kind of S4U
+ * request, add client info for the ticket client without the realm. */
+ pac_client = enc_tkt_reply->client;
+ with_realm = FALSE;
+ } else {
+ /*
+ * For regular TGS and transitive RBCD requests, copy the client info
+ * from the incoming PAC, and don't add client info during signing. We
+ * validated the incoming client info in validate_tgs_request().
+ */
+ ret = copy_pac_buffer(context, KRB5_PAC_CLIENT_INFO, subject_pac,
+ new_pac);
+ if (ret)
+ goto cleanup;
+ pac_client = NULL;
+ with_realm = FALSE;
+ }
+
+ ret = krb5_kdc_sign_ticket(context, enc_tkt_reply, new_pac, server->princ,
+ pac_client, server_key, local_tgt_key,
+ with_realm);
+ if (ret)
+ goto cleanup;
+
+ ret = 0;
+
+cleanup:
+ krb5_pac_free(context, new_pac);
+ return ret;
+}
+
krb5_error_code
-handle_authdata(krb5_context context, unsigned int flags,
+handle_authdata(kdc_realm_t *kdc_active_realm, unsigned int flags,
krb5_db_entry *client, krb5_db_entry *server,
krb5_db_entry *subject_server, krb5_db_entry *local_tgt,
krb5_keyblock *local_tgt_key, krb5_keyblock *client_key,
krb5_keyblock *server_key, krb5_keyblock *subject_key,
krb5_data *req_pkt, krb5_kdc_req *req,
- krb5_const_principal altcprinc, void *ad_info,
- krb5_enc_tkt_part *enc_tkt_req,
- krb5_data ***auth_indicators,
+ krb5_const_principal altcprinc, krb5_pac subject_pac,
+ krb5_enc_tkt_part *enc_tkt_req, krb5_data ***auth_indicators,
krb5_enc_tkt_part *enc_tkt_reply)
{
kdcauthdata_handle *h;
krb5_error_code ret = 0;
size_t i;
+ krb5_context context = kdc_active_realm->realm_context;
if (req->msg_type == KRB5_TGS_REQ &&
req->authorization_data.ciphertext.data != NULL) {
@@ -839,35 +614,9 @@ handle_authdata(krb5_context context, unsigned int flags,
return ret;
}
- if (!isflagset(enc_tkt_reply->flags, TKT_FLG_ANONYMOUS)) {
- /* Fetch authdata from the KDB if appropriate. */
- ret = fetch_kdb_authdata(context, flags, client, server,
- subject_server, local_tgt, client_key,
- server_key, subject_key, local_tgt_key,
- req, altcprinc, ad_info, enc_tkt_req,
- enc_tkt_reply, auth_indicators);
- if (ret)
- return ret;
- }
-
- /* Add auth indicators if any were given. */
- if (auth_indicators != NULL && *auth_indicators != NULL &&
- !isflagset(server->attributes, KRB5_KDB_NO_AUTH_DATA_REQUIRED)) {
- ret = add_auth_indicators(context, *auth_indicators, server_key,
- local_tgt, local_tgt_key, enc_tkt_reply);
- if (ret)
- return ret;
- }
-
- if (!isflagset(enc_tkt_reply->flags, TKT_FLG_ANONYMOUS)) {
- /* Validate and insert AD-SIGNTICKET authdata. This must happen last
- * since it contains a signature over the other authdata. */
- ret = handle_signticket(context, flags, subject_server, server,
- local_tgt, local_tgt_key, req, altcprinc,
- enc_tkt_req, enc_tkt_reply);
- if (ret)
- return ret;
- }
-
- return 0;
+ return handle_pac(kdc_active_realm, flags, client, server, subject_server,
+ local_tgt, local_tgt_key, server_key, subject_key,
+ enc_tkt_req, subject_pac, req, altcprinc,
+ enc_tkt_reply->times.authtime, enc_tkt_reply,
+ auth_indicators);
}
diff --git a/src/kdc/kdc_util.c b/src/kdc/kdc_util.c
index 60f30c4..9f2a67d 100644
--- a/src/kdc/kdc_util.c
+++ b/src/kdc/kdc_util.c
@@ -520,6 +520,100 @@ cleanup:
return ret;
}
+/*
+ * If a PAC is present in enc_tkt, verify it and place it in *pac_out. sprinc
+ * is the canonical name of the server principal entry used to decrypt enc_tkt.
+ * server_key is the ticket decryption key. tgt is the local krbtgt entry for
+ * the ticket server realm, and tgt_key is its first key.
+ */
+krb5_error_code
+get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
+ krb5_const_principal sprinc, krb5_keyblock *server_key,
+ krb5_db_entry *tgt, krb5_keyblock *tgt_key, krb5_pac *pac_out)
+{
+ krb5_error_code ret;
+ krb5_key_data *kd;
+ krb5_keyblock old_key;
+ krb5_kvno kvno;
+ int tries;
+
+ *pac_out = NULL;
+
+ /* For local or cross-realm TGTs we only check the server signature. */
+ if (krb5_is_tgs_principal(sprinc)) {
+ return krb5_kdc_verify_ticket(context, enc_tkt, sprinc, server_key,
+ NULL, pac_out);
+ }
+
+ ret = krb5_kdc_verify_ticket(context, enc_tkt, sprinc, server_key,
+ tgt_key, pac_out);
+ if (ret != KRB5KRB_AP_ERR_MODIFIED && ret != KRB5_BAD_ENCTYPE)
+ return ret;
+
+ /* There is no kvno in PAC signatures, so try two previous versions. */
+ kvno = tgt->key_data[0].key_data_kvno - 1;
+ for (tries = 2; tries > 0 && kvno > 0; tries--, kvno--) {
+ ret = krb5_dbe_find_enctype(context, tgt, -1, -1, kvno, &kd);
+ if (ret)
+ return KRB5KRB_AP_ERR_MODIFIED;
+ ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &old_key, NULL);
+ if (ret)
+ return ret;
+ ret = krb5_kdc_verify_ticket(context, enc_tkt, sprinc, server_key,
+ &old_key, pac_out);
+ krb5_free_keyblock_contents(context, &old_key);
+ if (!ret)
+ return 0;
+ }
+
+ return KRB5KRB_AP_ERR_MODIFIED;
+}
+
+/*
+ * Fetch the client info from pac and parse it into a principal name, expecting
+ * a realm in the string. Set *authtime_out to the client info authtime if it
+ * is not null.
+ */
+krb5_error_code
+get_pac_princ_with_realm(krb5_context context, krb5_pac pac,
+ krb5_principal *princ_out,
+ krb5_timestamp *authtime_out)
+{
+ krb5_error_code ret;
+ int n_atsigns, flags = KRB5_PRINCIPAL_PARSE_REQUIRE_REALM;
+ char *client_str = NULL;
+ const char *p;
+
+ *princ_out = NULL;
+
+ ret = krb5_pac_get_client_info(context, pac, authtime_out, &client_str);
+ if (ret)
+ return ret;
+
+ n_atsigns = 0;
+ for (p = client_str; *p != '\0'; p++) {
+ if (*p == '@')
+ n_atsigns++;
+ }
+
+ if (n_atsigns == 2) {
+ flags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;
+ } else if (n_atsigns != 1) {
+ ret = KRB5_PARSE_MALFORMED;
+ goto cleanup;
+ }
+
+ ret = krb5_parse_name_flags(context, client_str, flags, princ_out);
+ if (ret)
+ return ret;
+
+ (*princ_out)->type = KRB5_NT_MS_PRINCIPAL;
+
+cleanup:
+ free(client_str);
+ return 0;
+}
+
/* This probably wants to be updated if you support last_req stuff */
static krb5_last_req_entry nolrentry = { KV5M_LAST_REQ_ENTRY, KRB5_LRQ_NONE, 0 };
@@ -1387,8 +1481,7 @@ is_client_db_alias(krb5_context context, const krb5_db_entry *entry,
krb5_db_entry *self;
krb5_boolean is_self = FALSE;
- ret = krb5_db_get_principal(context, princ,
- KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY, &self);
+ ret = krb5_db_get_principal(context, princ, KRB5_KDB_FLAG_CLIENT, &self);
if (!ret) {
is_self = krb5_principal_compare(context, entry->princ, self->princ);
krb5_db_free_principal(context, self);
@@ -1451,7 +1544,7 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
if (id->subject_cert.length != 0) {
code = krb5_db_get_s4u_x509_principal(kdc_context,
&id->subject_cert, id->user,
- KRB5_KDB_FLAG_INCLUDE_PAC,
+ KRB5_KDB_FLAG_CLIENT,
&princ);
if (code == 0 && id->user->length == 0) {
krb5_free_principal(kdc_context, id->user);
@@ -1460,7 +1553,7 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
}
} else {
code = krb5_db_get_principal(kdc_context, id->user,
- KRB5_KDB_FLAG_INCLUDE_PAC, &princ);
+ KRB5_KDB_FLAG_CLIENT, &princ);
}
if (code == KRB5_KDB_NOENTRY) {
*status = "UNKNOWN_S4U2SELF_PRINCIPAL";
@@ -1481,6 +1574,29 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
return 0;
}
+/* Clear the forwardable flag in tkt if server cannot obtain forwardable
+ * S4U2Self tickets according to [MS-SFU] 3.2.5.1.2. */
+krb5_error_code
+s4u2self_forwardable(krb5_context context, krb5_db_entry *server,
+ krb5_enc_tkt_part *tkt)
+{
+ krb5_error_code ret;
+
+ /* Allow the forwardable flag if server has ok-to-auth-as-delegate set. */
+ if (server->attributes & KRB5_KDB_OK_TO_AUTH_AS_DELEGATE)
+ return 0;
+
+ /* Deny the forwardable flag if server has any authorized delegation
+ * targets for traditional S4U2Proxy. */
+ ret = krb5_db_check_allowed_to_delegate(context, NULL, server, NULL);
+ if (!ret)
+ tkt->flags &= ~TKT_FLG_FORWARDABLE;
+
+ if (ret == KRB5KDC_ERR_BADOPTION || ret == KRB5_PLUGIN_OP_NOTSUPP)
+ return 0;
+ return ret;
+}
+
/*
* Determine if an S4U2Proxy request is authorized. Set **stkt_ad_info to the
* KDB authdata handle for the second ticket if the KDB module supplied one.
@@ -1489,97 +1605,80 @@ kdc_process_s4u2self_req(kdc_realm_t *kdc_active_realm,
*/
krb5_error_code
kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, unsigned int flags,
- krb5_kdc_req *request,
- const krb5_enc_tkt_part *t2enc,
- krb5_db_entry *krbtgt, krb5_keyblock *krbtgt_key,
+ krb5_kdc_req *request, krb5_pac header_pac,
+ const krb5_enc_tkt_part *t2enc, krb5_pac t2_pac,
const krb5_db_entry *server,
krb5_keyblock *server_key,
krb5_const_principal server_princ,
const krb5_db_entry *proxy,
- krb5_const_principal proxy_princ,
- void *ad_info, void **stkt_ad_info,
- krb5_principal *stkt_authdata_client,
+ krb5_principal *stkt_pac_client,
const char **status)
{
krb5_error_code errcode;
krb5_boolean support_rbcd;
- krb5_principal client_princ = t2enc->client;
+ krb5_principal client_princ = t2enc->client, t2_pac_princ = NULL;
+
+ *stkt_pac_client = NULL;
/* Check if the client supports resource-based constrained delegation. */
errcode = kdc_get_pa_pac_rbcd(kdc_context, request->padata, &support_rbcd);
if (errcode)
return errcode;
- errcode = krb5_db_get_authdata_info(kdc_context, flags,
- t2enc->authorization_data,
- t2enc->client, proxy_princ, server_key,
- krbtgt_key, krbtgt,
- t2enc->times.authtime, stkt_ad_info,
- stkt_authdata_client);
- if (errcode != 0 && errcode != KRB5_PLUGIN_OP_NOTSUPP) {
- *status = "NOT_ALLOWED_TO_DELEGATE";
- return errcode;
- }
-
- /* For RBCD we require that both client and impersonator's authdata have
- * been verified. */
- if (errcode != 0 || ad_info == NULL)
- support_rbcd = FALSE;
-
- /* For an RBCD final request, the KDB module must be able to recover the
- * reply ticket client name from the evidence ticket authorization data. */
- if (isflagset(flags, KRB5_KDB_FLAG_CROSS_REALM)) {
- if (*stkt_authdata_client == NULL ||
- (*stkt_authdata_client)->realm.length == 0) {
- *status = "UNSUPPORTED_S4U2PROXY_REQUEST";
- return KRB5KDC_ERR_BADOPTION;
+ /* For an RBCD final request, recover the reply ticket client name from
+ * the evidence ticket PAC. */
+ if (flags & KRB5_KDB_FLAG_CROSS_REALM) {
+ if (get_pac_princ_with_realm(kdc_context, t2_pac, &t2_pac_princ,
+ NULL) != 0) {
+ *status = "RBCD_PAC_PRINC";
+ errcode = KRB5KDC_ERR_BADOPTION;
+ goto done;
}
-
- client_princ = *stkt_authdata_client;
+ client_princ = t2_pac_princ;
}
/* If both are in the same realm, try allowed_to_delegate first. */
- if (krb5_realm_compare(kdc_context, server->princ, proxy_princ)) {
+ if (krb5_realm_compare(kdc_context, server->princ, request->server)) {
errcode = krb5_db_check_allowed_to_delegate(kdc_context, client_princ,
- server, proxy_princ);
- if (errcode != 0 && errcode != KRB5KDC_ERR_POLICY &&
+ server, request->server);
+ if (errcode != KRB5KDC_ERR_BADOPTION &&
errcode != KRB5_PLUGIN_OP_NOTSUPP)
- return errcode;
-
- if (errcode == 0) {
-
- /*
- * In legacy constrained-delegation, the evidence ticket must be
- * forwardable. This check deliberately causes an error response
- * even if the delegation is also authorized by resource-based
- * constrained delegation (which does not require a forwardable
- * evidence ticket). Windows KDCs behave the same way.
- */
- if (!isflagset(t2enc->flags, TKT_FLG_FORWARDABLE)) {
- *status = "EVIDENCE_TKT_NOT_FORWARDABLE";
- return KRB5KDC_ERR_BADOPTION;
- }
+ goto done;
- return 0;
- }
/* Fall back to resource-based constrained-delegation. */
}
if (!support_rbcd) {
*status = "UNSUPPORTED_S4U2PROXY_REQUEST";
- return KRB5KDC_ERR_BADOPTION;
+ errcode = KRB5KDC_ERR_BADOPTION;
+ goto done;
}
/* If we are issuing a referral, the KDC in the resource realm will check
* if delegation is allowed. */
- if (isflagset(flags, KRB5_KDB_FLAG_ISSUING_REFERRAL))
- return 0;
+ if (isflagset(flags, KRB5_KDB_FLAG_ISSUING_REFERRAL)) {
+ errcode = 0;
+ goto done;
+ }
errcode = krb5_db_allowed_to_delegate_from(kdc_context, client_princ,
- server_princ, ad_info, proxy);
- if (errcode)
+ server_princ, header_pac,
+ proxy);
+ if (errcode == KRB5_PLUGIN_OP_NOTSUPP) {
+ *status = "UNSUPPORTED_S4U2PROXY_REQUEST";
+ errcode = KRB5KDC_ERR_BADOPTION;
+ goto done;
+ } else if (errcode) {
*status = "NOT_ALLOWED_TO_DELEGATE";
+ goto done;
+ }
+
+ *stkt_pac_client = t2_pac_princ;
+ t2_pac_princ = NULL;
+
+done:
+ krb5_free_principal(kdc_context, t2_pac_princ);
return errcode;
}
diff --git a/src/kdc/kdc_util.h b/src/kdc/kdc_util.h
index f2d179c..45683ec 100644
--- a/src/kdc/kdc_util.h
+++ b/src/kdc/kdc_util.h
@@ -86,7 +86,8 @@ validate_as_request (kdc_realm_t *, krb5_kdc_req *, krb5_db_entry *,
int
validate_tgs_request(kdc_realm_t *kdc_active_realm,
krb5_kdc_req *request, krb5_db_entry *server,
- krb5_ticket *ticket, const krb5_ticket *stkt,
+ krb5_ticket *ticket, krb5_pac pac,
+ const krb5_ticket *stkt, krb5_pac stkt_pac,
krb5_db_entry *stkt_server, krb5_timestamp kdc_time,
krb5_pa_s4u_x509_user *s4u_x509_user,
krb5_db_entry *s4u2self_client,
@@ -225,7 +226,7 @@ get_auth_indicators(krb5_context context, krb5_enc_tkt_part *enc_tkt,
krb5_data ***indicators_out);
krb5_error_code
-handle_authdata (krb5_context context,
+handle_authdata (kdc_realm_t *kdc_active_realm,
unsigned int flags,
krb5_db_entry *client,
krb5_db_entry *server,
@@ -238,7 +239,7 @@ handle_authdata (krb5_context context,
krb5_data *req_pkt,
krb5_kdc_req *request,
krb5_const_principal altcprinc,
- void *ad_info,
+ krb5_pac subject_pac,
krb5_enc_tkt_part *enc_tkt_request,
krb5_data ***auth_indicators,
krb5_enc_tkt_part *enc_tkt_reply);
@@ -253,6 +254,17 @@ void kdc_free_lookaside(krb5_context);
/* kdc_util.c */
void reset_for_hangup(void *);
+krb5_error_code
+get_verified_pac(krb5_context context, const krb5_enc_tkt_part *enc_tkt,
+ krb5_const_principal sprinc, krb5_keyblock *server_key,
+ krb5_db_entry *tgt, krb5_keyblock *tgt_key,
+ krb5_pac *pac_out);
+
+krb5_error_code
+get_pac_princ_with_realm(krb5_context context, krb5_pac pac,
+ krb5_principal *princ_out,
+ krb5_timestamp *authtime_out);
+
krb5_boolean
include_pac_p(krb5_context context, krb5_kdc_req *request);
@@ -275,6 +287,10 @@ kdc_process_s4u2self_req (kdc_realm_t *kdc_active_realm,
const char **status);
krb5_error_code
+s4u2self_forwardable(krb5_context context, krb5_db_entry *server,
+ krb5_enc_tkt_part *enc_tkt);
+
+krb5_error_code
kdc_make_s4u2self_rep (krb5_context context,
krb5_keyblock *tgs_subkey,
krb5_keyblock *tgs_session,
@@ -283,21 +299,15 @@ kdc_make_s4u2self_rep (krb5_context context,
krb5_enc_kdc_rep_part *reply_encpart);
krb5_error_code
-kdc_process_s4u2proxy_req (kdc_realm_t *kdc_active_realm,
- unsigned int flags,
- krb5_kdc_req *request,
- const krb5_enc_tkt_part *t2enc,
- krb5_db_entry *krbtgt,
- krb5_keyblock *krbtgt_key,
- const krb5_db_entry *server,
- krb5_keyblock *server_key,
- krb5_const_principal server_princ,
- const krb5_db_entry *proxy,
- krb5_const_principal proxy_princ,
- void *ad_info,
- void **stkt_ad_info,
- krb5_principal *stkt_ad_client,
- const char **status);
+kdc_process_s4u2proxy_req(kdc_realm_t *kdc_active_realm, unsigned int flags,
+ krb5_kdc_req *request, krb5_pac header_pac,
+ const krb5_enc_tkt_part *t2enc, krb5_pac t2_pac,
+ const krb5_db_entry *server,
+ krb5_keyblock *server_key,
+ krb5_const_principal server_princ,
+ const krb5_db_entry *proxy,
+ krb5_principal *stkt_ad_client,
+ const char **status);
krb5_error_code
kdc_check_transited_list (kdc_realm_t *kdc_active_realm,
@@ -546,4 +556,22 @@ current_kvno(krb5_db_entry *entry)
return (entry->n_key_data == 0) ? 0 : entry->key_data[0].key_data_kvno;
}
+/* MS-PAC section 2.9 */
+struct pac_s4u_delegation_info {
+ char *proxy_target;
+ uint32_t transited_services_length;
+ char **transited_services;
+};
+
+/* Leaves room for one additional service. */
+krb5_error_code
+ndr_dec_delegation_info(krb5_data *data,
+ struct pac_s4u_delegation_info **res);
+
+krb5_error_code
+ndr_enc_delegation_info(struct pac_s4u_delegation_info *in,
+ krb5_data *out);
+
+void ndr_free_delegation_info(struct pac_s4u_delegation_info *in);
+
#endif /* __KRB5_KDC_UTIL__ */
diff --git a/src/kdc/main.c b/src/kdc/main.c
index 7917ffb..074680d 100644
--- a/src/kdc/main.c
+++ b/src/kdc/main.c
@@ -333,6 +333,11 @@ init_realm(kdc_realm_t * rdp, krb5_pointer aprof, char *realm,
free(svalue);
svalue = NULL;
+ hierarchy[2] = KRB5_CONF_DISABLE_PAC;
+ if (krb5_aprof_get_boolean(aprof, hierarchy, TRUE,
+ &rdp->realm_disable_pac))
+ rdp->realm_disable_pac = FALSE;
+
/*
* We've got our parameters, now go and setup our realm context.
*/
diff --git a/src/kdc/realm_data.h b/src/kdc/realm_data.h
index 8d698dc..2d66915 100644
--- a/src/kdc/realm_data.h
+++ b/src/kdc/realm_data.h
@@ -73,6 +73,7 @@ typedef struct __kdc_realm_data {
krb5_deltat realm_maxrlife; /* Maximum renewable life for realm */
krb5_boolean realm_reject_bad_transit; /* Accept unverifiable transited_realm ? */
krb5_boolean realm_restrict_anon; /* Anon to local TGT only */
+ krb5_boolean realm_disable_pac; /* Prevent issuance of PACs. */
} kdc_realm_t;
struct server_handle {
diff --git a/src/kdc/tgs_policy.c b/src/kdc/tgs_policy.c
index ae6c763..f33ad50 100644
--- a/src/kdc/tgs_policy.c
+++ b/src/kdc/tgs_policy.c
@@ -260,7 +260,7 @@ check_tgs_lineage(krb5_db_entry *server, krb5_ticket *tkt,
static int
check_tgs_s4u2self(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
- krb5_db_entry *server, krb5_ticket *tkt,
+ krb5_db_entry *server, krb5_ticket *tkt, krb5_pac pac,
krb5_timestamp kdc_time,
krb5_pa_s4u_x509_user *s4u_x509_user, krb5_db_entry *client,
krb5_boolean is_crossrealm, krb5_boolean is_referral,
@@ -272,7 +272,7 @@ check_tgs_s4u2self(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
if (!is_referral &&
!is_client_db_alias(kdc_context, server, tkt->enc_part2->client)) {
*status = "INVALID_S4U2SELF_REQUEST_SERVER_MISMATCH";
- return KDC_ERR_C_PRINCIPAL_UNKNOWN; /* match Windows error */
+ return KRB_AP_ERR_BADMATCH;
}
/* S4U2Self requests must use options valid for AS requests. */
@@ -325,28 +325,117 @@ check_tgs_s4u2self(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
return KDC_ERR_POLICY; /* match Windows error */
}
+ /* The header ticket PAC must be present. */
+ if (pac == NULL) {
+ *status = "S4U2SELF_NO_PAC";
+ return KDC_ERR_TGT_REVOKED;
+ }
+
if (client != NULL) {
+ /* The header ticket PAC must be for the impersonator. */
+ if (krb5_pac_verify(kdc_context, pac, tkt->enc_part2->times.authtime,
+ tkt->enc_part2->client, NULL, NULL) != 0) {
+ *status = "S4U2SELF_LOCAL_PAC_CLIENT";
+ return KDC_ERR_BADOPTION;
+ }
+
/* Validate the client policy. Use an empty server principal to bypass
* server policy checks. */
return validate_as_request(kdc_active_realm, req, client,
&empty_server, kdc_time, status, e_data);
+ } else {
+ /* The header ticket PAC must be for the subject, with realm. */
+ if (krb5_pac_verify_ext(kdc_context, pac,
+ tkt->enc_part2->times.authtime,
+ s4u_x509_user->user_id.user, NULL, NULL,
+ TRUE) != 0) {
+ *status = "S4U2SELF_FOREIGN_PAC_CLIENT";
+ return KDC_ERR_BADOPTION;
+ }
}
return 0;
}
+/*
+ * Validate pac as an S4U2Proxy subject PAC contained within a cross-realm TGT.
+ * If target_server is non-null, verify that it matches the PAC proxy target.
+ * Return 0 on success, non-zero on failure.
+ */
+static int
+verify_deleg_pac(krb5_context context, krb5_pac pac,
+ krb5_enc_tkt_part *enc_tkt,
+ krb5_const_principal target_server)
+{
+ krb5_timestamp pac_authtime;
+ krb5_data deleg_buf = empty_data();
+ krb5_principal princ = NULL;
+ struct pac_s4u_delegation_info *di = NULL;
+ char *client_str = NULL, *target_str = NULL;
+ const char *last_transited;
+ int result = -1;
+
+ /* Make sure the PAC client string can be parsed as a principal with
+ * realm. */
+ if (get_pac_princ_with_realm(context, pac, &princ, &pac_authtime) != 0)
+ goto cleanup;
+ if (pac_authtime != enc_tkt->times.authtime)
+ goto cleanup;
+
+ if (krb5_pac_get_buffer(context, pac, KRB5_PAC_DELEGATION_INFO,
+ &deleg_buf) != 0)
+ goto cleanup;
+
+ if (ndr_dec_delegation_info(&deleg_buf, &di) != 0)
+ goto cleanup;
+
+ if (target_server != NULL) {
+ if (krb5_unparse_name_flags(context, target_server,
+ KRB5_PRINCIPAL_UNPARSE_DISPLAY |
+ KRB5_PRINCIPAL_UNPARSE_NO_REALM,
+ &target_str) != 0)
+ goto cleanup;
+ if (strcmp(target_str, di->proxy_target) != 0)
+ goto cleanup;
+ }
+
+ /* Check that the most recently added PAC transited service matches the
+ * requesting impersonator. */
+ if (di->transited_services_length == 0)
+ goto cleanup;
+ if (krb5_unparse_name(context, enc_tkt->client, &client_str) != 0)
+ goto cleanup;
+ last_transited = di->transited_services[di->transited_services_length - 1];
+ if (strcmp(last_transited, client_str) != 0)
+ goto cleanup;
+
+ result = 0;
+
+cleanup:
+ free(target_str);
+ free(client_str);
+ ndr_free_delegation_info(di);
+ krb5_free_principal(context, princ);
+ krb5_free_data_contents(context, &deleg_buf);
+ return result;
+}
+
static int
check_tgs_s4u2proxy(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
- krb5_db_entry *server, krb5_ticket *tkt,
- const krb5_ticket *stkt, krb5_db_entry *stkt_server,
- krb5_boolean is_crossrealm, krb5_boolean is_referral,
- const char **status)
+ krb5_db_entry *server, krb5_ticket *tkt, krb5_pac pac,
+ const krb5_ticket *stkt, krb5_pac stkt_pac,
+ krb5_db_entry *stkt_server, krb5_boolean is_crossrealm,
+ krb5_boolean is_referral, const char **status)
{
- /* A second ticket must be present in the request. */
+ /* A forwardable second ticket must be present in the request. */
if (stkt == NULL) {
*status = "NO_2ND_TKT";
return KDC_ERR_BADOPTION;
}
+ if (!(stkt->enc_part2->flags & TKT_FLG_FORWARDABLE)) {
+ *status = "EVIDENCE_TKT_NOT_FORWARDABLE";
+ return KDC_ERR_BADOPTION;
+ }
/* Constrained delegation is mutually exclusive with renew/forward/etc.
* (and therefore requires the header ticket to be a TGT). */
@@ -361,6 +450,17 @@ check_tgs_s4u2proxy(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
return KDC_ERR_POLICY;
}
+ /* The header ticket PAC must be present and for the impersonator. */
+ if (pac == NULL) {
+ *status = "S4U2PROXY_NO_HEADER_PAC";
+ return KDC_ERR_TGT_REVOKED;
+ }
+ if (krb5_pac_verify(kdc_context, pac, tkt->enc_part2->times.authtime,
+ tkt->enc_part2->client, NULL, NULL) != 0) {
+ *status = "S4U2PROXY_HEADER_PAC";
+ return KDC_ERR_BADOPTION;
+ }
+
/*
* An S4U2Proxy request must be an initial request to the impersonator's
* realm (possibly for a target resource in the same realm), or a final
@@ -368,27 +468,51 @@ check_tgs_s4u2proxy(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
* referral-chasing requests do not use the CNAME-IN-ADDL-TKT flag.
*/
- /* For an initial or same-realm request, the second ticket server and
- * header ticket client must be the same principal. */
- if (!is_crossrealm && !is_client_db_alias(kdc_context, stkt_server,
- tkt->enc_part2->client)) {
- *status = "EVIDENCE_TICKET_MISMATCH";
- return KDC_ERR_SERVER_NOMATCH;
- }
+ if (stkt_pac == NULL) {
+ *status = "S4U2PROXY_NO_STKT_PAC";
+ return KRB_AP_ERR_MODIFIED;
+ }
+ if (!is_crossrealm) {
+ /* For an initial or same-realm request, the second ticket server and
+ * header ticket client must be the same principal. */
+ if (!is_client_db_alias(kdc_context, stkt_server,
+ tkt->enc_part2->client)) {
+ *status = "EVIDENCE_TICKET_MISMATCH";
+ return KDC_ERR_SERVER_NOMATCH;
+ }
- /*
- * For a cross-realm request, the second ticket must be a referral TGT to
- * our realm with the impersonator as client. (Unlike the header ticket,
- * the second ticket contains authdata for the subject client.) The target
- * server must also be local, so we must not be issuing a referral.
- */
- if (is_crossrealm &&
- (is_referral || !is_cross_tgs_principal(stkt_server->princ) ||
- !data_eq(stkt_server->princ->data[1], server->princ->realm) ||
- !krb5_principal_compare(kdc_context, stkt->enc_part2->client,
- tkt->enc_part2->client))) {
- *status = "XREALM_EVIDENCE_TICKET_MISMATCH";
- return KDC_ERR_BADOPTION;
+ /* The second ticket client and PAC client are the subject, and must
+ * match. */
+ if (krb5_pac_verify(kdc_context, stkt_pac,
+ stkt->enc_part2->times.authtime,
+ stkt->enc_part2->client, NULL, NULL) != 0) {
+ *status = "S4U2PROXY_LOCAL_STKT_PAC";
+ return KDC_ERR_BADOPTION;
+ }
+
+ } else {
+
+ /*
+ * For a cross-realm request, the second ticket must be a referral TGT
+ * to our realm with the impersonator as client. The target server
+ * must also be local, so we must not be issuing a referral.
+ */
+ if (is_referral || !is_cross_tgs_principal(stkt_server->princ) ||
+ !data_eq(stkt_server->princ->data[1], server->princ->realm) ||
+ !krb5_principal_compare(kdc_context, stkt->enc_part2->client,
+ tkt->enc_part2->client)) {
+ *status = "XREALM_EVIDENCE_TICKET_MISMATCH";
+ return KDC_ERR_BADOPTION;
+ }
+
+ /* The second ticket PAC must be present and for the impersonated
+ * client, with delegation info. */
+ if (stkt_pac == NULL ||
+ verify_deleg_pac(kdc_context, stkt_pac, stkt->enc_part2,
+ req->server) != 0) {
+ *status = "S4U2PROXY_CROSS_STKT_PAC";
+ return KDC_ERR_BADOPTION;
+ }
}
return 0;
@@ -421,6 +545,32 @@ check_tgs_u2u(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
return 0;
}
+/* Validate the PAC of a non-S4U TGS request, if one is present. */
+static int
+check_normal_tgs_pac(krb5_context context, krb5_enc_tkt_part *enc_tkt,
+ krb5_pac pac, krb5_db_entry *server,
+ krb5_boolean is_crossrealm, const char **status)
+{
+ /* We don't require a PAC for regular TGS requests. */
+ if (pac == NULL)
+ return 0;
+
+ /* For most requests the header ticket PAC will be for the ticket
+ * client. */
+ if (krb5_pac_verify(context, pac, enc_tkt->times.authtime, enc_tkt->client,
+ NULL, NULL) == 0)
+ return 0;
+
+ /* For intermediate RBCD requests the header ticket PAC will be for the
+ * impersonated client. */
+ if (is_crossrealm && is_cross_tgs_principal(server->princ) &&
+ verify_deleg_pac(context, pac, enc_tkt, NULL) == 0)
+ return 0;
+
+ *status = "HEADER_PAC";
+ return KDC_ERR_BADOPTION;
+}
+
/*
* Some TGS-REQ options allow for a non-TGS principal in the ticket. Do some
* checks that are peculiar to these cases. (e.g., ticket service principal
@@ -468,7 +618,8 @@ check_tgs_tgt(kdc_realm_t *kdc_active_realm, krb5_kdc_req *req,
int
validate_tgs_request(kdc_realm_t *kdc_active_realm,
krb5_kdc_req *request, krb5_db_entry *server,
- krb5_ticket *ticket, const krb5_ticket *stkt,
+ krb5_ticket *ticket, krb5_pac pac,
+ const krb5_ticket *stkt, krb5_pac stkt_pac,
krb5_db_entry *stkt_server, krb5_timestamp kdc_time,
krb5_pa_s4u_x509_user *s4u_x509_user,
krb5_db_entry *s4u2self_client,
@@ -508,9 +659,9 @@ validate_tgs_request(kdc_realm_t *kdc_active_realm,
if (s4u_x509_user != NULL) {
errcode = check_tgs_s4u2self(kdc_active_realm, request, server, ticket,
- kdc_time, s4u_x509_user, s4u2self_client,
- is_crossrealm, is_referral,
- status, e_data);
+ pac, kdc_time, s4u_x509_user,
+ s4u2self_client, is_crossrealm,
+ is_referral, status, e_data);
} else {
errcode = check_tgs_lineage(server, ticket, is_crossrealm, status);
}
@@ -526,8 +677,13 @@ validate_tgs_request(kdc_realm_t *kdc_active_realm,
if (request->kdc_options & KDC_OPT_CNAME_IN_ADDL_TKT) {
errcode = check_tgs_s4u2proxy(kdc_active_realm, request, server,
- ticket, stkt, stkt_server, is_crossrealm,
- is_referral, status);
+ ticket, pac, stkt, stkt_pac, stkt_server,
+ is_crossrealm, is_referral, status);
+ if (errcode != 0)
+ return errcode;
+ } else if (s4u_x509_user == NULL) {
+ errcode = check_normal_tgs_pac(kdc_context, ticket->enc_part2, pac,
+ server, is_crossrealm, status);
if (errcode != 0)
return errcode;
}
diff --git a/src/lib/kdb/kdb5.c b/src/lib/kdb/kdb5.c
index c497218..415ae64 100644
--- a/src/lib/kdb/kdb5.c
+++ b/src/lib/kdb/kdb5.c
@@ -315,7 +315,6 @@ copy_vtable(const kdb_vftabl *in, kdb_vftabl *out)
out->promote_db = in->promote_db;
out->decrypt_key_data = in->decrypt_key_data;
out->encrypt_key_data = in->encrypt_key_data;
- out->sign_authdata = in->sign_authdata;
out->check_transited_realms = in->check_transited_realms;
out->check_policy_as = in->check_policy_as;
out->check_policy_tgs = in->check_policy_tgs;
@@ -325,8 +324,7 @@ copy_vtable(const kdb_vftabl *in, kdb_vftabl *out)
out->free_principal_e_data = in->free_principal_e_data;
out->get_s4u_x509_principal = in->get_s4u_x509_principal;
out->allowed_to_delegate_from = in->allowed_to_delegate_from;
- out->get_authdata_info = in->get_authdata_info;
- out->free_authdata_info = in->free_authdata_info;
+ out->issue_pac = in->issue_pac;
/* Set defaults for optional fields. */
if (out->fetch_master_key == NULL)
@@ -2597,34 +2595,6 @@ krb5_db_set_context(krb5_context context, void *db_context)
}
krb5_error_code
-krb5_db_sign_authdata(krb5_context kcontext, unsigned int flags,
- krb5_const_principal client_princ,
- krb5_const_principal server_princ, krb5_db_entry *client,
- krb5_db_entry *server, krb5_db_entry *header_server,
- krb5_db_entry *local_tgt, krb5_keyblock *client_key,
- krb5_keyblock *server_key, krb5_keyblock *header_key,
- krb5_keyblock *local_tgt_key, krb5_keyblock *session_key,
- krb5_timestamp authtime, krb5_authdata **tgt_auth_data,
- void *ad_info, krb5_data ***auth_indicators,
- krb5_authdata ***signed_auth_data)
-{
- krb5_error_code status = 0;
- kdb_vftabl *v;
-
- *signed_auth_data = NULL;
- status = get_vftabl(kcontext, &v);
- if (status)
- return status;
- if (v->sign_authdata == NULL)
- return KRB5_PLUGIN_OP_NOTSUPP;
- return v->sign_authdata(kcontext, flags, client_princ, server_princ,
- client, server, header_server, local_tgt,
- client_key, server_key, header_key, local_tgt_key,
- session_key, authtime, tgt_auth_data, ad_info,
- auth_indicators, signed_auth_data);
-}
-
-krb5_error_code
krb5_db_check_transited_realms(krb5_context kcontext,
const krb5_data *tr_contents,
const krb5_data *client_realm,
@@ -2757,7 +2727,7 @@ krb5_error_code
krb5_db_allowed_to_delegate_from(krb5_context kcontext,
krb5_const_principal client,
krb5_const_principal server,
- void *server_ad_info,
+ krb5_pac server_pac,
const krb5_db_entry *proxy)
{
krb5_error_code ret;
@@ -2768,50 +2738,8 @@ krb5_db_allowed_to_delegate_from(krb5_context kcontext,
return ret;
if (v->allowed_to_delegate_from == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->allowed_to_delegate_from(kcontext, client, server,
- server_ad_info, proxy);
-}
-
-krb5_error_code
-krb5_db_get_authdata_info(krb5_context kcontext, unsigned int flags,
- krb5_authdata **in_authdata,
- krb5_const_principal client_princ,
- krb5_const_principal server_princ,
- krb5_keyblock *server_key, krb5_keyblock *krbtgt_key,
- krb5_db_entry *krbtgt, krb5_timestamp authtime,
- void **ad_info_out, krb5_principal *client_out)
-{
- krb5_error_code ret;
- kdb_vftabl *v;
-
- *ad_info_out = NULL;
- if (client_out != NULL)
- *client_out = NULL;
-
- ret = get_vftabl(kcontext, &v);
- if (ret)
- return ret;
- if (v->get_authdata_info == NULL)
- return KRB5_PLUGIN_OP_NOTSUPP;
- return v->get_authdata_info(kcontext, flags, in_authdata, client_princ,
- server_princ, server_key, krbtgt_key, krbtgt,
- authtime, ad_info_out, client_out);
-}
-
-void
-krb5_db_free_authdata_info(krb5_context kcontext, void *ad_info)
-{
- krb5_error_code ret;
- kdb_vftabl *v;
-
- if (ad_info == NULL)
- return;
- ret = get_vftabl(kcontext, &v);
- if (ret)
- return;
- if (v->free_authdata_info == NULL)
- return;
- v->free_authdata_info(kcontext, ad_info);
+ return v->allowed_to_delegate_from(kcontext, client, server, server_pac,
+ proxy);
}
void
@@ -2832,3 +2760,22 @@ krb5_dbe_sort_key_data(krb5_key_data *key_data, size_t key_data_length)
}
}
}
+
+krb5_error_code
+krb5_db_issue_pac(krb5_context context, unsigned int flags,
+ krb5_db_entry *client, krb5_keyblock *replaced_reply_key,
+ krb5_db_entry *server, krb5_db_entry *krbtgt,
+ krb5_timestamp authtime, krb5_pac old_pac, krb5_pac new_pac,
+ krb5_data ***auth_indicators)
+{
+ krb5_error_code ret;
+ kdb_vftabl *v;
+
+ ret = get_vftabl(context, &v);
+ if (ret)
+ return ret;
+ if (v->issue_pac == NULL)
+ return KRB5_PLUGIN_OP_NOTSUPP;
+ return v->issue_pac(context, flags, client, replaced_reply_key, server,
+ krbtgt, authtime, old_pac, new_pac, auth_indicators);
+}
diff --git a/src/lib/kdb/libkdb5.exports b/src/lib/kdb/libkdb5.exports
index b71984d..97dc5c0 100644
--- a/src/lib/kdb/libkdb5.exports
+++ b/src/lib/kdb/libkdb5.exports
@@ -16,13 +16,12 @@ krb5_db_destroy
krb5_db_fetch_mkey
krb5_db_fetch_mkey_list
krb5_db_fini
-krb5_db_free_authdata_info
krb5_db_free_principal
krb5_db_get_age
-krb5_db_get_authdata_info
krb5_db_get_key_data_kvno
krb5_db_get_context
krb5_db_get_principal
+krb5_db_issue_pac
krb5_db_iterate
krb5_db_lock
krb5_db_mkey_list_alias
@@ -31,7 +30,6 @@ krb5_db_refresh_config
krb5_db_rename_principal
krb5_db_set_context
krb5_db_setup_mkey_name
-krb5_db_sign_authdata
krb5_db_unlock
krb5_db_store_master_key
krb5_db_store_master_key_list
diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c
index d91964e..5378b5c 100644
--- a/src/lib/krb5/asn.1/asn1_k_encode.c
+++ b/src/lib/krb5/asn.1/asn1_k_encode.c
@@ -1091,33 +1091,6 @@ DEFPTRTYPE(ptr_seqof_princ_plus_realm, seqof_princ_plus_realm);
DEFOPTIONALEMPTYTYPE(opt_ptr_seqof_princ_plus_realm,
ptr_seqof_princ_plus_realm);
-DEFFIELD(spdata_0, krb5_ad_signedpath_data, client, 0, princ_plus_realm);
-DEFFIELD(spdata_1, krb5_ad_signedpath_data, authtime, 1, kerberos_time);
-DEFFIELD(spdata_2, krb5_ad_signedpath_data, delegated, 2,
- opt_ptr_seqof_princ_plus_realm);
-DEFFIELD(spdata_3, krb5_ad_signedpath_data, method_data, 3,
- opt_ptr_seqof_pa_data);
-DEFFIELD(spdata_4, krb5_ad_signedpath_data, authorization_data, 4,
- opt_auth_data_ptr);
-static const struct atype_info *ad_signedpath_data_fields[] = {
- &k5_atype_spdata_0, &k5_atype_spdata_1, &k5_atype_spdata_2,
- &k5_atype_spdata_3, &k5_atype_spdata_4
-};
-DEFSEQTYPE(ad_signedpath_data, krb5_ad_signedpath_data,
- ad_signedpath_data_fields);
-
-DEFFIELD(signedpath_0, krb5_ad_signedpath, enctype, 0, int32);
-DEFFIELD(signedpath_1, krb5_ad_signedpath, checksum, 1, checksum);
-DEFFIELD(signedpath_2, krb5_ad_signedpath, delegated, 2,
- opt_ptr_seqof_princ_plus_realm);
-DEFFIELD(signedpath_3, krb5_ad_signedpath, method_data, 3,
- opt_ptr_seqof_pa_data);
-static const struct atype_info *ad_signedpath_fields[] = {
- &k5_atype_signedpath_0, &k5_atype_signedpath_1, &k5_atype_signedpath_2,
- &k5_atype_signedpath_3
-};
-DEFSEQTYPE(ad_signedpath, krb5_ad_signedpath, ad_signedpath_fields);
-
/* First context tag is 1, not 0. */
DEFFIELD(iakerb_header_1, krb5_iakerb_header, target_realm, 1, ostring_data);
DEFFIELD(iakerb_header_2, krb5_iakerb_header, cookie, 2, opt_ostring_data_ptr);
@@ -1323,9 +1296,6 @@ MAKE_DECODER(decode_krb5_fast_response, fast_response);
MAKE_ENCODER(encode_krb5_ad_kdcissued, ad_kdc_issued);
MAKE_DECODER(decode_krb5_ad_kdcissued, ad_kdc_issued);
-MAKE_ENCODER(encode_krb5_ad_signedpath_data, ad_signedpath_data);
-MAKE_ENCODER(encode_krb5_ad_signedpath, ad_signedpath);
-MAKE_DECODER(decode_krb5_ad_signedpath, ad_signedpath);
MAKE_ENCODER(encode_krb5_iakerb_header, iakerb_header);
MAKE_DECODER(decode_krb5_iakerb_header, iakerb_header);
MAKE_ENCODER(encode_krb5_iakerb_finished, iakerb_finished);
diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in
index 5a163ab..e4b560f 100644
--- a/src/lib/krb5/krb/Makefile.in
+++ b/src/lib/krb5/krb/Makefile.in
@@ -100,7 +100,6 @@ STLIBOBJS= \
rd_safe.o \
recvauth.o \
response_items.o \
- s4u_authdata.o \
s4u_creds.o \
sendauth.o \
send_tgs.o \
@@ -214,7 +213,6 @@ OBJS= $(OUTPRE)addr_comp.$(OBJEXT) \
$(OUTPRE)rd_safe.$(OBJEXT) \
$(OUTPRE)recvauth.$(OBJEXT) \
$(OUTPRE)response_items.$(OBJEXT) \
- $(OUTPRE)s4u_authdata.$(OBJEXT) \
$(OUTPRE)s4u_creds.$(OBJEXT) \
$(OUTPRE)sendauth.$(OBJEXT) \
$(OUTPRE)send_tgs.$(OBJEXT) \
@@ -328,7 +326,6 @@ SRCS= $(srcdir)/addr_comp.c \
$(srcdir)/rd_safe.c \
$(srcdir)/recvauth.c \
$(srcdir)/response_items.c \
- $(srcdir)/s4u_authdata.c\
$(srcdir)/s4u_creds.c \
$(srcdir)/sendauth.c \
$(srcdir)/send_tgs.c \
@@ -396,7 +393,7 @@ T_KERB_OBJS= t_kerb.o conv_princ.o unparse.o set_realm.o str_conv.o
T_SER_OBJS= t_ser.o ser_actx.o ser_adata.o ser_addr.o ser_auth.o ser_cksum.o \
ser_ctx.o ser_key.o ser_princ.o serialize.o authdata.o pac.o \
- pac_sign.o ai_authdata.o authdata_exp.o s4u_authdata.o copy_data.o etype_list.o
+ pac_sign.o ai_authdata.o authdata_exp.o copy_data.o etype_list.o
T_DELTAT_OBJS= t_deltat.o deltat.o
diff --git a/src/lib/krb5/krb/authdata.c b/src/lib/krb5/krb/authdata.c
index 7f28883..a9023b0 100644
--- a/src/lib/krb5/krb/authdata.c
+++ b/src/lib/krb5/krb/authdata.c
@@ -44,7 +44,6 @@ static const char *objdirs[] = {
/* Internal authdata systems */
static krb5plugin_authdata_client_ftable_v0 *authdata_systems[] = {
&k5_mspac_ad_client_ftable,
- &k5_s4u2proxy_ad_client_ftable,
&k5_authind_ad_client_ftable,
NULL
};
diff --git a/src/lib/krb5/krb/deps b/src/lib/krb5/krb/deps
index ca6ab25..dd1fbf8 100644
--- a/src/lib/krb5/krb/deps
+++ b/src/lib/krb5/krb/deps
@@ -985,18 +985,6 @@ response_items.so response_items.po $(OUTPRE)response_items.$(OBJEXT): \
$(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
$(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
int-proto.h response_items.c
-s4u_authdata.so s4u_authdata.po $(OUTPRE)s4u_authdata.$(OBJEXT): \
- $(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
- $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
- $(COM_ERR_DEPS) $(srcdir)/../rcache/memrcache.h $(top_srcdir)/include/k5-buf.h \
- $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
- $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
- $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
- $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
- $(top_srcdir)/include/k5-utf8.h $(top_srcdir)/include/krb5.h \
- $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
- $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
- auth_con.h authdata.h int-proto.h s4u_authdata.c
s4u_creds.so s4u_creds.po $(OUTPRE)s4u_creds.$(OBJEXT): \
$(BUILDTOP)/include/autoconf.h $(BUILDTOP)/include/krb5/krb5.h \
$(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
diff --git a/src/lib/krb5/krb/kfree.c b/src/lib/krb5/krb/kfree.c
index 6e38044..b4503d2 100644
--- a/src/lib/krb5/krb/kfree.c
+++ b/src/lib/krb5/krb/kfree.c
@@ -744,24 +744,6 @@ krb5_free_ad_kdcissued(krb5_context context, krb5_ad_kdcissued *val)
}
void KRB5_CALLCONV
-krb5_free_ad_signedpath(krb5_context context, krb5_ad_signedpath *val)
-{
- int i;
-
- if (val == NULL)
- return;
-
- krb5_free_checksum_contents(context, &val->checksum);
- if (val->delegated != NULL) {
- for (i = 0; val->delegated[i] != NULL; i++)
- krb5_free_principal(context, val->delegated[i]);
- free(val->delegated);
- }
- krb5_free_pa_data(context, val->method_data);
- free(val);
-}
-
-void KRB5_CALLCONV
krb5_free_iakerb_header(krb5_context context, krb5_iakerb_header *val)
{
if (val == NULL)
diff --git a/src/lib/krb5/krb/s4u_authdata.c b/src/lib/krb5/krb/s4u_authdata.c
deleted file mode 100644
index c33a50a..0000000
--- a/src/lib/krb5/krb/s4u_authdata.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- * Copyright 2010 by the Massachusetts Institute of Technology. All
- * Rights Reserved.
- *
- * Export of this software from the United States of America may
- * require a specific license from the United States Government.
- * It is the responsibility of any person or organization contemplating
- * export to obtain such a license before exporting.
- *
- * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
- * distribute this software and its documentation for any purpose and
- * without fee is hereby granted, provided that the above copyright
- * notice appear in all copies and that both that copyright notice and
- * this permission notice appear in supporting documentation, and that
- * the name of M.I.T. not be used in advertising or publicity pertaining
- * to distribution of the software without specific, written prior
- * permission. Furthermore if you modify this software you must label
- * your software as modified software and not distribute it in such a
- * fashion that it might be confused with the original M.I.T. software.
- * M.I.T. makes no representations about the suitability of
- * this software for any purpose. It is provided "as is" without express
- * or implied warranty.
- *
- */
-
-#include "k5-int.h"
-#include "authdata.h"
-#include "auth_con.h"
-#include "int-proto.h"
-
-/*
- * Authdata backend for processing SignedPath. Presently does not handle
- * the equivalent information in [MS-PAC], as that would require an NDR
- * interpreter.
- */
-
-struct s4u2proxy_context {
- int count;
- krb5_principal *delegated;
- krb5_boolean authenticated;
-};
-
-static krb5_error_code
-s4u2proxy_init(krb5_context kcontext, void **plugin_context)
-{
- *plugin_context = NULL;
- return 0;
-}
-
-static void
-s4u2proxy_flags(krb5_context kcontext,
- void *plugin_context,
- krb5_authdatatype ad_type,
- krb5_flags *flags)
-{
- *flags = AD_USAGE_KDC_ISSUED;
-}
-
-static void
-s4u2proxy_fini(krb5_context kcontext, void *plugin_context)
-{
- return;
-}
-
-static krb5_error_code
-s4u2proxy_request_init(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void **request_context)
-{
- krb5_error_code code;
- struct s4u2proxy_context *s4uctx;
-
- s4uctx = k5alloc(sizeof(*s4uctx), &code);
- if (s4uctx == NULL)
- return code;
-
- s4uctx->count = 0;
- s4uctx->delegated = NULL;
- s4uctx->authenticated = FALSE;
-
- *request_context = s4uctx;
-
- return 0;
-}
-
-static void
-s4u2proxy_free_internal(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- void *ptr)
-{
- krb5_principal *delegated = (krb5_principal *)ptr;
- int i;
-
- if (delegated != NULL) {
- for (i = 0; delegated[i] != NULL; i++)
- krb5_free_principal(kcontext, delegated[i]);
- free(delegated);
- }
-}
-
-static krb5_error_code
-s4u2proxy_import_authdata(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- krb5_authdata **authdata,
- krb5_boolean kdc_issued,
- krb5_const_principal kdc_issuer)
-{
- struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context;
- krb5_error_code code;
- krb5_ad_signedpath *sp;
- krb5_data enc_sp;
-
- enc_sp.data = (char *)authdata[0]->contents;
- enc_sp.length = authdata[0]->length;
-
- code = decode_krb5_ad_signedpath(&enc_sp, &sp);
- if (code != 0)
- return code;
-
- s4u2proxy_free_internal(kcontext, context,
- plugin_context, request_context,
- s4uctx->delegated);
-
- s4uctx->delegated = sp->delegated;
- sp->delegated = NULL;
-
- krb5_free_ad_signedpath(kcontext, sp);
-
- s4uctx->count = 0;
-
- if (s4uctx->delegated != NULL) {
- for (s4uctx->count = 0; s4uctx->delegated[s4uctx->count];
- s4uctx->count++)
- ;
- }
-
- s4uctx->authenticated = FALSE;
-
- return 0;
-}
-
-static krb5_error_code
-s4u2proxy_export_authdata(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- krb5_flags usage,
- krb5_authdata ***out_authdata)
-{
- struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context;
- krb5_error_code code;
- krb5_ad_signedpath sp;
- krb5_authdata **authdata;
- krb5_data *data;
-
- if (s4uctx->count == 0)
- return 0;
-
- memset(&sp, 0, sizeof(sp));
- sp.delegated = s4uctx->delegated;
-
- authdata = k5calloc(2, sizeof(krb5_authdata *), &code);
- if (authdata == NULL)
- return code;
-
- authdata[0] = k5alloc(sizeof(krb5_authdata), &code);
- if (authdata[0] == NULL) {
- free(authdata);
- return code;
- }
-
- code = encode_krb5_ad_signedpath(&sp, &data);
- if (code != 0) {
- krb5_free_authdata(kcontext, authdata);
- return code;
- }
-
- authdata[0]->magic = KV5M_AUTHDATA;
- authdata[0]->ad_type = KRB5_AUTHDATA_SIGNTICKET;
- authdata[0]->length = data->length;
- authdata[0]->contents = (krb5_octet *)data->data;
-
- authdata[1] = NULL;
-
- free(data);
-
- *out_authdata = authdata;
-
- return 0;
-}
-
-static krb5_error_code
-s4u2proxy_verify(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- const krb5_auth_context *auth_context,
- const krb5_keyblock *key,
- const krb5_ap_req *req)
-{
- /*
- * XXX there is no way to verify the SignedPath without the TGS
- * key. This means that we can never mark this as authenticated.
- */
-
- return 0;
-}
-
-static void
-s4u2proxy_request_fini(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context)
-{
- struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context;
-
- if (s4uctx == NULL)
- return;
-
- s4u2proxy_free_internal(kcontext, context,
- plugin_context, request_context,
- s4uctx->delegated);
- free(s4uctx);
-}
-
-/*
- * Nomenclature defined to be similar to [MS-PAC] 2.9, for future
- * interoperability
- */
-
-static krb5_data s4u2proxy_transited_services_attr = {
- KV5M_DATA,
- sizeof("urn:constrained-delegation:transited-services") - 1,
- "urn:constrained-delegation:transited-services"
-};
-
-static krb5_error_code
-s4u2proxy_get_attribute_types(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- krb5_data **out_attrs)
-{
- struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context;
- krb5_error_code code;
- krb5_data *attrs;
- int i = 0;
-
- if (s4uctx->count == 0)
- return ENOENT;
-
- attrs = k5calloc(2, sizeof(krb5_data), &code);
- if (attrs == NULL)
- goto cleanup;
-
- code = krb5int_copy_data_contents(kcontext,
- &s4u2proxy_transited_services_attr,
- &attrs[i++]);
- if (code != 0)
- goto cleanup;
-
- attrs[i].data = NULL;
- attrs[i].length = 0;
-
- *out_attrs = attrs;
- attrs = NULL;
-
-cleanup:
- if (attrs != NULL) {
- for (i = 0; attrs[i].data; i++)
- krb5_free_data_contents(kcontext, &attrs[i]);
- free(attrs);
- }
-
- return 0;
-}
-
-static krb5_error_code
-s4u2proxy_get_attribute(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- const krb5_data *attribute,
- krb5_boolean *authenticated,
- krb5_boolean *complete,
- krb5_data *value,
- krb5_data *display_value,
- int *more)
-{
- struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context;
- krb5_error_code code;
- krb5_principal principal;
- int i;
-
- if (display_value != NULL) {
- display_value->data = NULL;
- display_value->length = 0;
- }
-
- if (!data_eq(*attribute, s4u2proxy_transited_services_attr))
- return ENOENT;
-
- i = -(*more) - 1;
- if (i < 0)
- return EINVAL;
- else if (i >= s4uctx->count)
- return ENOENT;
-
- principal = s4uctx->delegated[i];
- assert(principal != NULL);
-
- code = krb5_unparse_name_flags(kcontext, principal, 0, &value->data);
- if (code != 0)
- return code;
-
- value->length = strlen(value->data);
-
- if (display_value != NULL) {
- code = krb5_unparse_name_flags(kcontext, principal,
- KRB5_PRINCIPAL_UNPARSE_DISPLAY,
- &display_value->data);
- if (code != 0)
- return code;
-
- display_value->length = strlen(display_value->data);
- }
-
- i++;
-
- if (i == s4uctx->count)
- *more = 0;
- else
- *more = -(i + 1);
-
- *authenticated = s4uctx->authenticated;
- *complete = TRUE;
-
- return 0;
-}
-
-static krb5_error_code
-s4u2proxy_set_attribute(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- krb5_boolean complete,
- const krb5_data *attribute,
- const krb5_data *value)
-{
- /* Only the KDC can set this attribute. */
- if (!data_eq(*attribute, s4u2proxy_transited_services_attr))
- return ENOENT;
-
- return EPERM;
-}
-
-static krb5_error_code
-s4u2proxy_export_internal(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- krb5_boolean restrict_authenticated,
- void **ptr)
-{
- struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context;
- krb5_error_code code;
- int i;
- krb5_principal *delegated;
-
- *ptr = NULL;
-
- if (s4uctx->count == 0)
- return ENOENT;
-
- if (restrict_authenticated)
- return ENOENT;
-
- delegated = k5calloc(s4uctx->count + 1, sizeof(krb5_principal), &code);
- if (delegated == NULL)
- return code;
-
- for (i = 0; i < s4uctx->count; i++) {
- code = krb5_copy_principal(kcontext, s4uctx->delegated[i],
- &delegated[i]);
- if (code != 0)
- goto cleanup;
- }
-
- delegated[i] = NULL;
-
- *ptr = delegated;
- delegated = NULL;
-
-cleanup:
- s4u2proxy_free_internal(kcontext, context,
- plugin_context, request_context,
- delegated);
-
- return code;
-}
-
-static krb5_error_code
-s4u2proxy_size(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- size_t *sizep)
-{
- struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context;
- krb5_error_code code = 0;
- int i;
-
- *sizep += sizeof(krb5_int32); /* version */
- *sizep += sizeof(krb5_int32); /* princ count */
-
- for (i = 0; i < s4uctx->count; i++) {
- code = k5_size_principal(s4uctx->delegated[i], sizep);
- if (code != 0)
- return code;
- }
-
- *sizep += sizeof(krb5_int32); /* authenticated flag */
-
- return code;
-}
-
-static krb5_error_code
-s4u2proxy_externalize(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- krb5_octet **buffer,
- size_t *lenremain)
-{
- struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context;
- krb5_error_code code = 0;
- size_t required = 0;
- krb5_octet *bp;
- size_t remain;
- int i = 0;
-
- bp = *buffer;
- remain = *lenremain;
-
- s4u2proxy_size(kcontext, context, plugin_context,
- request_context, &required);
-
- if (required > remain)
- return ENOMEM;
-
- krb5_ser_pack_int32(1, &bp, &remain); /* version */
- krb5_ser_pack_int32(s4uctx->count, &bp, &remain); /* princ count */
-
- for (i = 0; i < s4uctx->count; i++) {
- code = k5_externalize_principal(s4uctx->delegated[i], &bp, &remain);
- if (code != 0)
- return code;
- }
-
- krb5_ser_pack_int32(s4uctx->authenticated, &bp, &remain); /* authenticated */
-
- *buffer = bp;
- *lenremain = remain;
-
- return 0;
-}
-
-static krb5_error_code
-s4u2proxy_internalize(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- krb5_octet **buffer,
- size_t *lenremain)
-{
- struct s4u2proxy_context *s4uctx = (struct s4u2proxy_context *)request_context;
- krb5_error_code code;
- krb5_int32 ibuf;
- krb5_octet *bp;
- size_t remain;
- int count;
- krb5_principal *delegated = NULL;
-
- bp = *buffer;
- remain = *lenremain;
-
- /* version */
- code = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
- if (code != 0)
- goto cleanup;
-
- if (ibuf != 1) {
- code = EINVAL;
- goto cleanup;
- }
-
- /* count */
- code = krb5_ser_unpack_int32(&count, &bp, &remain);
- if (code != 0)
- goto cleanup;
-
- if (count > 65535)
- return ERANGE; /* let's set some reasonable limits here */
- else if (count > 0) {
- int i;
-
- delegated = k5calloc(count + 1, sizeof(krb5_principal), &code);
- if (delegated == NULL)
- goto cleanup;
-
- for (i = 0; i < count; i++) {
- code = k5_internalize_principal(&delegated[i], &bp, &remain);
- if (code != 0)
- goto cleanup;
- }
-
- delegated[i] = NULL;
- }
-
- code = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
- if (code != 0)
- goto cleanup;
-
- s4u2proxy_free_internal(kcontext, context,
- plugin_context, request_context,
- s4uctx->delegated);
-
- s4uctx->count = count;
- s4uctx->delegated = delegated;
- s4uctx->authenticated = (ibuf != 0);
-
- delegated = NULL;
-
- *buffer = bp;
- *lenremain = remain;
-
-cleanup:
- s4u2proxy_free_internal(kcontext, context,
- plugin_context, request_context,
- delegated);
-
- return code;
-}
-
-static krb5_error_code
-s4u2proxy_copy(krb5_context kcontext,
- krb5_authdata_context context,
- void *plugin_context,
- void *request_context,
- void *dst_plugin_context,
- void *dst_request_context)
-{
- struct s4u2proxy_context *srcctx = (struct s4u2proxy_context *)request_context;
- struct s4u2proxy_context *dstctx = (struct s4u2proxy_context *)dst_request_context;
- krb5_error_code code;
-
- code = s4u2proxy_export_internal(kcontext, context,
- plugin_context, request_context,
- FALSE, (void **)&dstctx->delegated);
- if (code != 0 && code != ENOENT)
- return code;
-
- dstctx->count = srcctx->count;
- dstctx->authenticated = srcctx->authenticated;
-
- return 0;
-}
-
-static krb5_authdatatype s4u2proxy_ad_types[] = { KRB5_AUTHDATA_SIGNTICKET, 0 };
-
-krb5plugin_authdata_client_ftable_v0 k5_s4u2proxy_ad_client_ftable = {
- "constrained-delegation",
- s4u2proxy_ad_types,
- s4u2proxy_init,
- s4u2proxy_fini,
- s4u2proxy_flags,
- s4u2proxy_request_init,
- s4u2proxy_request_fini,
- s4u2proxy_get_attribute_types,
- s4u2proxy_get_attribute,
- s4u2proxy_set_attribute,
- NULL, /* delete_attribute_proc */
- s4u2proxy_export_authdata,
- s4u2proxy_import_authdata,
- s4u2proxy_export_internal,
- s4u2proxy_free_internal,
- s4u2proxy_verify,
- s4u2proxy_size,
- s4u2proxy_externalize,
- s4u2proxy_internalize,
- s4u2proxy_copy
-};
diff --git a/src/lib/krb5/libkrb5.exports b/src/lib/krb5/libkrb5.exports
index 9a7a16f..4c50e93 100644
--- a/src/lib/krb5/libkrb5.exports
+++ b/src/lib/krb5/libkrb5.exports
@@ -1,6 +1,5 @@
_krb5_conf_boolean
decode_krb5_ad_kdcissued
-decode_krb5_ad_signedpath
decode_krb5_ap_rep
decode_krb5_ap_rep_enc_part
decode_krb5_ap_req
@@ -53,8 +52,6 @@ decode_krb5_ticket
decode_krb5_typed_data
decode_utf8_strings
encode_krb5_ad_kdcissued
-encode_krb5_ad_signedpath_data
-encode_krb5_ad_signedpath
encode_krb5_ap_rep
encode_krb5_ap_rep_enc_part
encode_krb5_ap_req
@@ -323,7 +320,6 @@ krb5_expand_hostname
krb5_fcc_ops
krb5_find_authdata
krb5_free_ad_kdcissued
-krb5_free_ad_signedpath
krb5_free_address
krb5_free_addresses
krb5_free_ap_rep
diff --git a/src/plugins/kdb/db2/db2_exp.c b/src/plugins/kdb/db2/db2_exp.c
index 4d905db..7cf8aa4 100644
--- a/src/plugins/kdb/db2/db2_exp.c
+++ b/src/plugins/kdb/db2/db2_exp.c
@@ -220,11 +220,16 @@ kdb_vftabl PLUGIN_SYMBOL_NAME(krb5_db2, kdb_function_table) = {
/* put_policy */ wrap_krb5_db2_put_policy,
/* iter_policy */ wrap_krb5_db2_iter_policy,
/* delete_policy */ wrap_krb5_db2_delete_policy,
- /* blah blah blah */ 0,0,0,0,0,
+ /* fetch_master_key */ NULL,
+ /* fetch_master_key_list */ NULL,
+ /* store_master_key_list */ NULL,
+ /* dbe_search_enctype */ NULL,
+ /* change_pwd */ NULL,
/* promote_db */ wrap_krb5_db2_promote_db,
- 0, 0, 0, 0,
+ /* decrypt_key_data */ NULL,
+ /* encrypt_key_data */ NULL,
+ /* check_transited_realms */ NULL,
/* check_policy_as */ wrap_krb5_db2_check_policy_as,
- 0,
+ /* check_policy_tgs */ NULL,
/* audit_as_req */ wrap_krb5_db2_audit_as_req,
- 0, 0
};
diff --git a/src/plugins/kdb/ldap/ldap_exp.c b/src/plugins/kdb/ldap/ldap_exp.c
index 1d7cd14..d5cd82b 100644
--- a/src/plugins/kdb/ldap/ldap_exp.c
+++ b/src/plugins/kdb/ldap/ldap_exp.c
@@ -76,7 +76,6 @@ kdb_vftabl PLUGIN_SYMBOL_NAME(krb5_ldap, kdb_function_table) = {
/* promote_db */ NULL,
/* decrypt_key_data */ NULL,
/* encrypt_key_data */ NULL,
- /* sign_authdata */ NULL,
/* check_transited_realms */ NULL,
/* check_policy_as */ krb5_ldap_check_policy_as,
/* check_policy_tgs */ NULL,
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c
index 4fbf898..1f0c868 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c
@@ -294,7 +294,7 @@ krb5_ldap_check_allowed_to_delegate(krb5_context context,
krb5_error_code code;
krb5_tl_data *tlp;
- code = KRB5KDC_ERR_POLICY;
+ code = KRB5KDC_ERR_BADOPTION;
for (tlp = server->tl_data; tlp != NULL; tlp = tlp->tl_data_next) {
krb5_principal acl;
@@ -305,7 +305,7 @@ krb5_ldap_check_allowed_to_delegate(krb5_context context,
if (krb5_parse_name(context, (char *)tlp->tl_data_contents, &acl) != 0)
continue;
- if (krb5_principal_compare(context, proxy, acl)) {
+ if (proxy == NULL || krb5_principal_compare(context, proxy, acl)) {
code = 0;
krb5_free_principal(context, acl);
break;
diff --git a/src/plugins/kdb/test/kdb_test.c b/src/plugins/kdb/test/kdb_test.c
index 495bec4..8e7015d 100644
--- a/src/plugins/kdb/test/kdb_test.c
+++ b/src/plugins/kdb/test/kdb_test.c
@@ -407,9 +407,8 @@ test_get_principal(krb5_context context, krb5_const_principal search_for,
check(krb5_parse_name(context, canon, &princ));
if (!krb5_realm_compare(context, search_for, princ)) {
/* Out of realm */
- if ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) &&
- ((flags & KRB5_KDB_FLAG_CANONICALIZE) ||
- search_for->type == KRB5_NT_ENTERPRISE_PRINCIPAL)) {
+ if ((flags & KRB5_KDB_FLAG_CLIENT) &&
+ (flags & KRB5_KDB_FLAG_REFERRAL_OK)) {
/* Return a client referral by creating an entry with only the
* principal set. */
*entry = ealloc(sizeof(**entry));
@@ -417,7 +416,7 @@ test_get_principal(krb5_context context, krb5_const_principal search_for,
princ = NULL;
ret = 0;
goto cleanup;
- } else if (flags & KRB5_KDB_FLAG_CANONICALIZE) {
+ } else if (flags & KRB5_KDB_FLAG_REFERRAL_OK) {
/* Generate a server referral by looking up the TGT for the
* canonical name's realm. */
tgtprinc = tgtname(context, &princ->realm, &search_for->realm);
@@ -530,7 +529,7 @@ test_get_s4u_x509_principal(krb5_context context, const krb5_data *client_cert,
ret = test_get_principal(context, cert_princ, flags, entry);
krb5_free_principal(context, cert_princ);
- if (ret || (flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY))
+ if (ret || (flags & KRB5_KDB_FLAG_REFERRAL_OK))
return ret;
if (!krb5_realm_compare(context, princ, (*entry)->princ))
@@ -612,362 +611,12 @@ test_encrypt_key_data(krb5_context context, const krb5_keyblock *mkey,
return 0;
}
-typedef struct {
- char *pac_princ;
- struct {
- char *proxy_target;
- char *impersonator;
- } deleg_info;
- krb5_boolean not_delegated;
- krb5_pac pac;
-} pac_info;
-
-static void
-free_pac_info(krb5_context context, pac_info *info)
-{
- if (info == NULL)
- return;
-
- free(info->pac_princ);
- free(info->deleg_info.proxy_target);
- free(info->deleg_info.impersonator);
- krb5_pac_free(context, info->pac);
- free(info);
-}
-
-/*
- * Create a PAC object with a fake logon-info blob. Instead of a real
- * KERB_VALIDATION_INFO structure, store a byte indicating whether the
- * USER_NOT_DELEGATED bit is set.
- */
-static krb5_error_code
-create_pac(krb5_context context, krb5_boolean not_delegated, krb5_pac *pac_out)
-{
- krb5_data data;
- krb5_pac pac;
- char nd;
-
- nd = not_delegated ? 1 : 0;
- data = make_data(&nd, 1);
- check(krb5_pac_init(context, &pac));
- check(krb5_pac_add_buffer(context, pac, KRB5_PAC_LOGON_INFO, &data));
-
- *pac_out = pac;
- return 0;
-}
-
-/* Create a fake PAC, setting the USER_NOT_DELEGATED bit if the client DB entry
- * disallows forwardable tickets. */
-static krb5_error_code
-create_pac_db(krb5_context context, krb5_db_entry *client, krb5_pac *pac_out)
-{
- krb5_boolean not_delegated;
- /* Use disallow_forwardable as delegation_not_allowed attribute */
- not_delegated = (client->attributes & KRB5_KDB_DISALLOW_FORWARDABLE);
- return create_pac(context, not_delegated, pac_out);
-}
-
-/* Locate the PAC in tgt_authdata and set *pac_out to its PAC object
- * representation. Set it to NULL if no PAC is present. */
-static void
-parse_ticket_pac(krb5_context context, krb5_authdata **tgt_auth_data,
- krb5_pac *pac_out)
-{
- krb5_authdata **authdata;
-
- *pac_out = NULL;
-
- check(krb5_find_authdata(context, tgt_auth_data, NULL,
- KRB5_AUTHDATA_WIN2K_PAC, &authdata));
- if (authdata == NULL)
- return;
- assert(authdata[1] == NULL);
- check(krb5_pac_parse(context, authdata[0]->contents, authdata[0]->length,
- pac_out));
- krb5_free_authdata(context, authdata);
-}
-
-/* Verify the KDC signature against the local TGT key. tgt_key must be the
- * decrypted first key data entry of tgt. */
-static krb5_error_code
-verify_kdc_signature(krb5_context context, krb5_pac pac,
- krb5_keyblock *tgt_key, krb5_db_entry *tgt)
-{
- krb5_error_code ret;
- krb5_key_data *kd;
- krb5_keyblock old_key;
- krb5_kvno kvno;
- int tries;
-
- ret = krb5_pac_verify(context, pac, 0, NULL, NULL, tgt_key);
- if (ret != KRB5KRB_AP_ERR_MODIFIED)
- return ret;
-
- kvno = tgt->key_data[0].key_data_kvno - 1;
-
- /* There is no kvno in PAC signatures, so try two previous versions. */
- for (tries = 2; tries > 0 && kvno > 0; tries--, kvno--) {
- ret = krb5_dbe_find_enctype(context, tgt, -1, -1, kvno, &kd);
- if (ret)
- return KRB5KRB_AP_ERR_MODIFIED;
- ret = krb5_dbe_decrypt_key_data(context, NULL, kd, &old_key, NULL);
- if (ret)
- return ret;
- ret = krb5_pac_verify(context, pac, 0, NULL, NULL, &old_key);
- krb5_free_keyblock_contents(context, &old_key);
- if (!ret)
- return 0;
-
- /* Try the next lower kvno on the next iteration. */
- kvno = kd->key_data_kvno - 1;
- }
-
- return KRB5KRB_AP_ERR_MODIFIED;
-}
-
-static krb5_error_code
-verify_ticket_pac(krb5_context context, krb5_pac pac, unsigned int flags,
- krb5_const_principal client_princ, krb5_boolean check_realm,
- krb5_keyblock *server_key, krb5_keyblock *local_tgt_key,
- krb5_db_entry *local_tgt, krb5_timestamp authtime)
-{
- check(krb5_pac_verify_ext(context, pac, authtime, client_princ, server_key,
- NULL, check_realm));
- if (flags & KRB5_KDB_FLAG_CROSS_REALM)
- return 0;
- return verify_kdc_signature(context, pac, local_tgt_key, local_tgt);
-}
-
-static void
-get_pac_info(krb5_context context, krb5_authdata **in_authdata,
- pac_info **info_out)
-{
- krb5_error_code ret;
- krb5_pac pac = NULL;
- krb5_data data;
- char *sep = NULL;
- pac_info *info;
-
- *info_out = NULL;
-
- parse_ticket_pac(context, in_authdata, &pac);
- if (pac == NULL)
- return;
-
- info = ealloc(sizeof(*info));
-
- /* Read the fake logon-info buffer from the PAC and set not_delegated
- * according to the byte value. */
- check(krb5_pac_get_client_info(context, pac, NULL, &info->pac_princ));
- check(krb5_pac_get_buffer(context, pac, KRB5_PAC_LOGON_INFO, &data));
- assert(data.length == 1);
- info->not_delegated = *data.data;
- krb5_free_data_contents(context, &data);
-
- ret = krb5_pac_get_buffer(context, pac, KRB5_PAC_DELEGATION_INFO, &data);
- if (ret && ret != ENOENT)
- abort();
- if (!ret) {
- sep = memchr(data.data, ':', data.length);
- assert(sep != NULL);
- info->deleg_info.proxy_target = k5memdup0(data.data, sep - data.data,
- &ret);
- check(ret);
- info->deleg_info.impersonator = k5memdup0(sep + 1, data.length - 1 -
- (sep - data.data), &ret);
- check(ret);
- krb5_free_data_contents(context, &data);
- }
-
- info->pac = pac;
- *info_out = info;
-}
-
-/* Add a fake delegation-info buffer to pac containing the proxy target and
- * impersonator from info. */
-static void
-add_delegation_info(krb5_context context, krb5_pac pac, pac_info *info)
-{
- krb5_data data;
- char *str;
-
- if (info->deleg_info.proxy_target == NULL)
- return;
-
- if (asprintf(&str, "%s:%s", info->deleg_info.proxy_target,
- info->deleg_info.impersonator) < 0)
- abort();
- data = string2data(str);
- check(krb5_pac_add_buffer(context, pac, KRB5_PAC_DELEGATION_INFO, &data));
- free(str);
-}
-
-/* Set *out to an AD-IF-RELEVANT authdata element containing a PAC authdata
- * element with contents pac_data. */
-static void
-encode_pac_ad(krb5_context context, krb5_data *pac_data, krb5_authdata **out)
-{
- krb5_authdata pac_ad, *list[2], **ifrel;
-
- pac_ad.magic = KV5M_AUTHDATA;
- pac_ad.ad_type = KRB5_AUTHDATA_WIN2K_PAC;
- pac_ad.contents = (krb5_octet *)pac_data->data;;
- pac_ad.length = pac_data->length;
- list[0] = &pac_ad;
- list[1] = NULL;
-
- check(krb5_encode_authdata_container(context, KRB5_AUTHDATA_IF_RELEVANT,
- list, &ifrel));
- assert(ifrel[1] == NULL);
- *out = ifrel[0];
- free(ifrel);
-}
-
-/* Parse a PAC client-info string into a principal name. If xrealm_s4u is
- * true, expect a realm in the string. */
-static krb5_error_code
-parse_pac_princ(krb5_context context, krb5_boolean xrealm_s4u, char *pac_princ,
- krb5_principal *client_out)
-{
- int n_atsigns = 0, flags = 0;
- char *p = pac_princ;
-
- while (*p++) {
- if (*p == '@')
- n_atsigns++;
- }
- if (xrealm_s4u) {
- flags |= KRB5_PRINCIPAL_PARSE_REQUIRE_REALM;
- n_atsigns--;
- } else {
- flags |= KRB5_PRINCIPAL_PARSE_NO_REALM;
- }
- assert(n_atsigns == 0 || n_atsigns == 1);
- if (n_atsigns == 1)
- flags |= KRB5_PRINCIPAL_PARSE_ENTERPRISE;
- check(krb5_parse_name_flags(context, pac_princ, flags, client_out));
- (*client_out)->type = KRB5_NT_MS_PRINCIPAL;
- return 0;
-}
-
-/* Set *ad_out to a fake PAC for testing, or to NULL if it doesn't make sense
- * to generate a PAC for the request. */
static void
-generate_pac(krb5_context context, unsigned int flags,
- krb5_const_principal client_princ,
- krb5_const_principal server_princ, krb5_db_entry *client,
- krb5_db_entry *header_server, krb5_db_entry *local_tgt,
- krb5_keyblock *server_key, krb5_keyblock *header_key,
- krb5_keyblock *local_tgt_key, krb5_timestamp authtime,
- pac_info *info, krb5_authdata **ad_out)
-{
- krb5_boolean sign_realm, check_realm;
- krb5_data pac_data;
- krb5_pac pac = NULL;
- krb5_principal pac_princ = NULL;
-
- *ad_out = NULL;
-
- check_realm = ((flags & KRB5_KDB_FLAGS_S4U) &&
- (flags & KRB5_KDB_FLAG_CROSS_REALM));
- sign_realm = ((flags & KRB5_KDB_FLAGS_S4U) &&
- (flags & KRB5_KDB_FLAG_ISSUING_REFERRAL));
-
- if (client != NULL &&
- ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY) ||
- (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION))) {
- /* For AS or local-realm S4U2Self, generate an initial PAC. */
- check(create_pac_db(context, client, &pac));
- } else if (info == NULL) {
- /* If there is no input PAC, do not generate one. */
- assert((flags & KRB5_KDB_FLAGS_S4U) == 0);
- return;
- } else {
- if (IS_TGS_PRINC(server_princ) &&
- info->deleg_info.proxy_target != NULL) {
- /* RBCD transitive trust. */
- assert(flags & KRB5_KDB_FLAG_CROSS_REALM);
- assert(!(flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION));
- check(parse_pac_princ(context, TRUE, info->pac_princ, &pac_princ));
- client_princ = pac_princ;
- check_realm = TRUE;
- sign_realm = TRUE;
- } else if ((flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) &&
- !(flags & KRB5_KDB_FLAG_CROSS_REALM)) {
- /*
- * Initial RBCD and old constrained delegation requests to
- * impersonator realm; create delegation info blob. We cannot
- * assume that proxy_target is NULL as the evidence ticket could
- * have been acquired via constrained delegation.
- */
- free(info->deleg_info.proxy_target);
- check(krb5_unparse_name_flags(context, server_princ,
- KRB5_PRINCIPAL_UNPARSE_NO_REALM,
- &info->deleg_info.proxy_target));
- /* This is supposed to be a list of impersonators, but we currently
- * only deal with one. */
- free(info->deleg_info.impersonator);
- check(krb5_unparse_name(context, header_server->princ,
- &info->deleg_info.impersonator));
- } else if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
- /* Last cross realm RBCD request to proxy realm. */
- assert(info->deleg_info.proxy_target != NULL);
- }
-
- /* We have already verified the PAC in get_authdata_info, but we should
- * be able to verify the signatures here as well. */
- check(verify_ticket_pac(context, info->pac, flags, client_princ,
- check_realm, header_key, local_tgt_key,
- local_tgt, authtime));
-
- /* Create a new pac as we may be altering pac principal's realm */
- check(create_pac(context, info->not_delegated, &pac));
- add_delegation_info(context, pac, info);
- }
- check(krb5_pac_sign_ext(context, pac, authtime, client_princ, server_key,
- local_tgt_key, sign_realm, &pac_data));
- krb5_pac_free(context, pac);
- krb5_free_principal(context, pac_princ);
- encode_pac_ad(context, &pac_data, ad_out);
- krb5_free_data_contents(context, &pac_data);
-}
-
-static krb5_error_code
-test_sign_authdata(krb5_context context, unsigned int flags,
- krb5_const_principal client_princ,
- krb5_const_principal server_princ, krb5_db_entry *client,
- krb5_db_entry *server, krb5_db_entry *header_server,
- krb5_db_entry *local_tgt, krb5_keyblock *client_key,
- krb5_keyblock *server_key, krb5_keyblock *header_key,
- krb5_keyblock *local_tgt_key, krb5_keyblock *session_key,
- krb5_timestamp authtime, krb5_authdata **tgt_auth_data,
- void *ad_info, krb5_data ***auth_indicators,
- krb5_authdata ***signed_auth_data)
+change_auth_indicators(krb5_context context, krb5_data ***auth_indicators)
{
- krb5_authdata *pac_ad = NULL, *test_ad = NULL, **list;
krb5_data **inds, d;
int i, val;
- /* Possibly create a PAC authdata element. */
- generate_pac(context, flags, client_princ, server_princ, client,
- header_server, local_tgt, server_key, header_key,
- local_tgt_key, authtime, ad_info, &pac_ad);
-
- /* Always create a TEST_AD_TYPE element. */
- test_ad = ealloc(sizeof(*test_ad));
- test_ad->magic = KV5M_AUTHDATA;
- test_ad->ad_type = TEST_AD_TYPE;
- test_ad->contents = (uint8_t *)estrdup("db-authdata-test");
- test_ad->length = strlen((char *)test_ad->contents);
-
- /* Assemble the authdata into a one-element or two-element list.
- * The PAC must be the first element. */
- list = ealloc(3 * sizeof(*list));
- list[0] = (pac_ad != NULL) ? pac_ad : test_ad;
- list[1] = (pac_ad != NULL) ? test_ad : NULL;
- list[2] = NULL;
- *signed_auth_data = list;
-
/* If we see an auth indicator "dbincrX", replace the whole indicator list
* with "dbincr{X+1}". */
inds = *auth_indicators;
@@ -984,6 +633,58 @@ test_sign_authdata(krb5_context context, unsigned int flags,
break;
}
}
+}
+
+static krb5_error_code
+test_issue_pac(krb5_context context, unsigned int flags, krb5_db_entry *client,
+ krb5_keyblock *replaced_reply_key, krb5_db_entry *server,
+ krb5_db_entry *krb5tgt, krb5_timestamp authtime,
+ krb5_pac old_pac, krb5_pac new_pac,
+ krb5_data ***auth_indicators)
+{
+ krb5_data data = empty_data();
+ krb5_boolean found_logon_info = FALSE;
+ krb5_ui_4 *types;
+ size_t num_buffers = 0, i;
+
+ change_auth_indicators(context, auth_indicators);
+
+ if (old_pac == NULL ||
+ (client != NULL && (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION))) {
+ /* Generating an initial PAC. */
+ assert(client != NULL);
+ data = string2data("fake");
+ check(krb5_pac_add_buffer(context, new_pac, KRB5_PAC_LOGON_INFO,
+ &data));
+ return 0;
+ } else {
+ /* Field copying - my favorite! */
+ if (old_pac != NULL)
+ check(krb5_pac_get_types(context, old_pac, &num_buffers, &types));
+
+ for (i = 0; i < num_buffers; i++) {
+ /* Skip buffer types handled by KDC. */
+ if (types[i] == KRB5_PAC_SERVER_CHECKSUM ||
+ types[i] == KRB5_PAC_PRIVSVR_CHECKSUM ||
+ types[i] == KRB5_PAC_TICKET_CHECKSUM ||
+ types[i] == KRB5_PAC_CLIENT_INFO ||
+ types[i] == KRB5_PAC_DELEGATION_INFO)
+ continue;
+
+ check(krb5_pac_get_buffer(context, old_pac, types[i], &data));
+
+ if (types[i] == KRB5_PAC_LOGON_INFO) {
+ found_logon_info = TRUE;
+ assert(data_eq_string(data, "fake"));
+ }
+
+ check(krb5_pac_add_buffer(context, new_pac, types[i], &data));
+ krb5_free_data_contents(context, &data);
+ }
+
+ if (old_pac != NULL)
+ assert(found_logon_info);
+ }
return 0;
}
@@ -1003,7 +704,7 @@ match_in_table(krb5_context context, const char *table, const char *sprinc,
if (ret)
return FALSE;
for (v = values; *v != NULL; v++) {
- if (strcmp(*v, tprinc) == 0) {
+ if (tprinc == NULL || strcmp(*v, tprinc) == 0) {
found = TRUE;
break;
}
@@ -1018,114 +719,51 @@ test_check_allowed_to_delegate(krb5_context context,
const krb5_db_entry *server,
krb5_const_principal proxy)
{
- char *sprinc, *tprinc;
+ char *sprinc, *tprinc = NULL;
krb5_boolean found = FALSE;
check(krb5_unparse_name_flags(context, server->princ,
KRB5_PRINCIPAL_UNPARSE_NO_REALM, &sprinc));
- check(krb5_unparse_name_flags(context, proxy,
- KRB5_PRINCIPAL_UNPARSE_NO_REALM, &tprinc));
+ if (proxy != NULL) {
+ check(krb5_unparse_name_flags(context, proxy,
+ KRB5_PRINCIPAL_UNPARSE_NO_REALM,
+ &tprinc));
+ }
found = match_in_table(context, "delegation", sprinc, tprinc);
krb5_free_unparsed_name(context, sprinc);
krb5_free_unparsed_name(context, tprinc);
- return found ? 0 : KRB5KDC_ERR_POLICY;
+ return found ? 0 : KRB5KDC_ERR_BADOPTION;
}
static krb5_error_code
test_allowed_to_delegate_from(krb5_context context,
krb5_const_principal client,
krb5_const_principal server,
- void *server_ad_info, const krb5_db_entry *proxy)
+ krb5_pac server_pac,
+ const krb5_db_entry *proxy)
{
- char *sprinc, *tprinc;
- pac_info *info = (pac_info *)server_ad_info;
+ char *proxy_princ, *server_princ, *pac_client_princ, *client_princ;
krb5_boolean found = FALSE;
- check(krb5_unparse_name(context, proxy->princ, &sprinc));
- check(krb5_unparse_name(context, server, &tprinc));
- assert(strncmp(info->pac_princ, tprinc, strlen(info->pac_princ)) == 0);
- found = match_in_table(context, "rbcd", sprinc, tprinc);
- krb5_free_unparsed_name(context, sprinc);
- krb5_free_unparsed_name(context, tprinc);
- return found ? 0 : KRB5KDC_ERR_POLICY;
-}
+ assert(server_pac != NULL);
-static krb5_error_code
-test_get_authdata_info(krb5_context context, unsigned int flags,
- krb5_authdata **in_authdata,
- krb5_const_principal client_princ,
- krb5_const_principal server_princ,
- krb5_keyblock *server_key, krb5_keyblock *krbtgt_key,
- krb5_db_entry *krbtgt, krb5_timestamp authtime,
- void **ad_info_out, krb5_principal *client_out)
-{
- pac_info *info = NULL;
- krb5_boolean rbcd_transitive, xrealm_s4u;
- krb5_principal pac_princ = NULL;
- char *proxy_name = NULL, *impersonator_name = NULL;
-
- get_pac_info(context, in_authdata, &info);
- if (info == NULL)
- return 0;
+ check(krb5_unparse_name(context, proxy->princ, &proxy_princ));
+ check(krb5_unparse_name(context, server, &server_princ));
+ check(krb5_unparse_name(context, client, &client_princ));
- /* Transitive RBCD requests are not flagged as constrained delegation */
- if (info->not_delegated &&
- (info->deleg_info.proxy_target ||
- (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION))) {
- free_pac_info(context, info);
- return KRB5KDC_ERR_BADOPTION;
- }
-
- rbcd_transitive = IS_TGS_PRINC(server_princ) &&
- (flags & KRB5_KDB_FLAG_CROSS_REALM) && info->deleg_info.proxy_target &&
- !(flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION);
-
- xrealm_s4u = rbcd_transitive || ((flags & KRB5_KDB_FLAG_CROSS_REALM) &&
- (flags & KRB5_KDB_FLAGS_S4U));
-
- check(parse_pac_princ(context, xrealm_s4u, info->pac_princ, &pac_princ));
-
- /* Cross-realm and transitive trust RBCD requests */
- if (rbcd_transitive || ((flags & KRB5_KDB_FLAG_CROSS_REALM) &&
- (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION))) {
- assert(info->deleg_info.proxy_target != NULL);
- assert(info->deleg_info.impersonator != NULL);
- /* We must be able to find the impersonator in the delegation info. */
- assert(!krb5_principal_compare(context, client_princ, pac_princ));
- check(krb5_unparse_name(context, client_princ, &impersonator_name));
- assert(strcmp(info->deleg_info.impersonator, impersonator_name) == 0);
- krb5_free_unparsed_name(context, impersonator_name);
- client_princ = pac_princ;
- /* In the non-transitive case we can match the proxy too. */
- if (!rbcd_transitive) {
- check(krb5_unparse_name_flags(context, server_princ,
- KRB5_PRINCIPAL_UNPARSE_NO_REALM,
- &proxy_name));
- assert(info->deleg_info.proxy_target != NULL);
- assert(strcmp(info->deleg_info.proxy_target, proxy_name) == 0);
- krb5_free_unparsed_name(context, proxy_name);
- }
- }
+ check(krb5_pac_get_client_info(context, server_pac, NULL,
+ &pac_client_princ));
- check(verify_ticket_pac(context, info->pac, flags, client_princ,
- xrealm_s4u, server_key, krbtgt_key, krbtgt,
- authtime));
+ /* Skip realm portion if not present in PAC. */
+ assert(strncmp(pac_client_princ, server_princ,
+ strlen(pac_client_princ)) == 0);
- *ad_info_out = info;
- if (client_out != NULL)
- *client_out = pac_princ;
- else
- krb5_free_principal(context, pac_princ);
-
- return 0;
-}
-
-static void
-test_free_authdata_info(krb5_context context, void *ad_info)
-{
- pac_info *info = (pac_info *)ad_info;
+ free(pac_client_princ);
- free_pac_info(context, info);
+ found = match_in_table(context, "rbcd", proxy_princ, server_princ);
+ krb5_free_unparsed_name(context, proxy_princ);
+ krb5_free_unparsed_name(context, server_princ);
+ return found ? 0 : KRB5KDC_ERR_BADOPTION;
}
kdb_vftabl PLUGIN_SYMBOL_NAME(krb5_test, kdb_function_table) = {
@@ -1158,7 +796,6 @@ kdb_vftabl PLUGIN_SYMBOL_NAME(krb5_test, kdb_function_table) = {
NULL, /* promote_db */
test_decrypt_key_data,
test_encrypt_key_data,
- test_sign_authdata,
NULL, /* check_transited_realms */
NULL, /* check_policy_as */
NULL, /* check_policy_tgs */
@@ -1168,6 +805,5 @@ kdb_vftabl PLUGIN_SYMBOL_NAME(krb5_test, kdb_function_table) = {
NULL, /* free_principal_e_data */
test_get_s4u_x509_principal,
test_allowed_to_delegate_from,
- test_get_authdata_info,
- test_free_authdata_info
+ test_issue_pac,
};
diff --git a/src/tests/asn.1/krb5_decode_leak.c b/src/tests/asn.1/krb5_decode_leak.c
index 77fd3ee..2a5313b 100644
--- a/src/tests/asn.1/krb5_decode_leak.c
+++ b/src/tests/asn.1/krb5_decode_leak.c
@@ -634,16 +634,6 @@ main(int argc, char **argv)
ktest_empty_ad_kdcissued(&kdci);
}
/****************************************************************/
- /* encode_krb5_ad_signedpath */
- {
- krb5_ad_signedpath sp, *tmp;
- ktest_make_sample_ad_signedpath(&sp);
- leak_test(sp, encode_krb5_ad_signedpath,
- decode_krb5_ad_signedpath,
- krb5_free_ad_signedpath);
- ktest_empty_ad_signedpath(&sp);
- }
- /****************************************************************/
/* encode_krb5_iakerb_header */
{
krb5_iakerb_header ih, *tmp;
diff --git a/src/tests/asn.1/krb5_decode_test.c b/src/tests/asn.1/krb5_decode_test.c
index 4fa67bf..926aa94 100644
--- a/src/tests/asn.1/krb5_decode_test.c
+++ b/src/tests/asn.1/krb5_decode_test.c
@@ -999,14 +999,6 @@ int main(argc, argv)
}
/****************************************************************/
- /* decode_ad_signedpath */
- {
- setup(krb5_ad_signedpath,ktest_make_sample_ad_signedpath);
- decode_run("ad_signedpath","","30 3E A0 03 02 01 01 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61",decode_krb5_ad_signedpath,ktest_equal_ad_signedpath,krb5_free_ad_signedpath);
- ktest_empty_ad_signedpath(&ref);
- }
-
- /****************************************************************/
/* decode_iakerb_header */
{
setup(krb5_iakerb_header,ktest_make_sample_iakerb_header);
diff --git a/src/tests/asn.1/krb5_encode_test.c b/src/tests/asn.1/krb5_encode_test.c
index 72c0134..26c064e 100644
--- a/src/tests/asn.1/krb5_encode_test.c
+++ b/src/tests/asn.1/krb5_encode_test.c
@@ -640,23 +640,6 @@ main(argc, argv)
ktest_empty_ad_kdcissued(&kdci);
}
/****************************************************************/
- /* encode_krb5_ad_signedpath_data */
- {
- krb5_ad_signedpath_data spd;
- ktest_make_sample_ad_signedpath_data(&spd);
- encode_run(spd, "ad_signedpath_data", "",
- encode_krb5_ad_signedpath_data);
- ktest_empty_ad_signedpath_data(&spd);
- }
- /****************************************************************/
- /* encode_krb5_ad_signedpath */
- {
- krb5_ad_signedpath sp;
- ktest_make_sample_ad_signedpath(&sp);
- encode_run(sp, "ad_signedpath", "", encode_krb5_ad_signedpath);
- ktest_empty_ad_signedpath(&sp);
- }
- /****************************************************************/
/* encode_krb5_iakerb_header */
{
krb5_iakerb_header ih;
diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c
index 270d5b7..d37e4fa 100644
--- a/src/tests/asn.1/ktest.c
+++ b/src/tests/asn.1/ktest.c
@@ -560,28 +560,6 @@ ktest_make_sample_ad_kdcissued(krb5_ad_kdcissued *p)
}
void
-ktest_make_sample_ad_signedpath_data(krb5_ad_signedpath_data *p)
-{
- ktest_make_sample_principal(&p->client);
- p->authtime = SAMPLE_TIME;
- p->delegated = ealloc(2 * sizeof(krb5_principal));
- ktest_make_sample_principal(&p->delegated[0]);
- p->delegated[1] = NULL;
- ktest_make_sample_authorization_data(&p->authorization_data);
- ktest_make_sample_pa_data_array(&p->method_data);
-}
-
-void
-ktest_make_sample_ad_signedpath(krb5_ad_signedpath *p)
-{
- p->enctype = 1;
- ktest_make_sample_checksum(&p->checksum);
- p->delegated = ealloc(2 * sizeof(krb5_principal));
- p->delegated[1] = NULL;
- ktest_make_sample_pa_data_array(&p->method_data);
-}
-
-void
ktest_make_sample_iakerb_header(krb5_iakerb_header *ih)
{
ktest_make_sample_data(&(ih->target_realm));
@@ -1525,39 +1503,6 @@ ktest_empty_ad_kdcissued(krb5_ad_kdcissued *p)
}
void
-ktest_empty_ad_signedpath_data(krb5_ad_signedpath_data *p)
-{
- int i;
-
- ktest_destroy_principal(&p->client);
- if (p->delegated != NULL) {
- for (i = 0; p->delegated[i] != NULL; i++) {
- krb5_principal princ = p->delegated[i];
- ktest_destroy_principal(&princ);
- }
- free(p->delegated);
- }
- ktest_destroy_pa_data_array(&p->method_data);
- ktest_destroy_authorization_data(&p->authorization_data);
-}
-
-void
-ktest_empty_ad_signedpath(krb5_ad_signedpath *p)
-{
- int i;
-
- free(p->checksum.contents);
- if (p->delegated != NULL) {
- for (i = 0; p->delegated[i] != NULL; i++) {
- krb5_principal princ = p->delegated[i];
- ktest_destroy_principal(&princ);
- }
- free(p->delegated);
- }
- ktest_destroy_pa_data_array(&p->method_data);
-}
-
-void
ktest_empty_iakerb_header(krb5_iakerb_header *p)
{
krb5_free_data_contents(NULL, &p->target_realm);
diff --git a/src/tests/asn.1/ktest.h b/src/tests/asn.1/ktest.h
index d9cc90a..53180ab 100644
--- a/src/tests/asn.1/ktest.h
+++ b/src/tests/asn.1/ktest.h
@@ -85,8 +85,6 @@ void ktest_make_sample_enc_sam_response_enc_2(krb5_enc_sam_response_enc_2 *p);
void ktest_make_sample_pa_for_user(krb5_pa_for_user *p);
void ktest_make_sample_pa_s4u_x509_user(krb5_pa_s4u_x509_user *p);
void ktest_make_sample_ad_kdcissued(krb5_ad_kdcissued *p);
-void ktest_make_sample_ad_signedpath_data(krb5_ad_signedpath_data *p);
-void ktest_make_sample_ad_signedpath(krb5_ad_signedpath *p);
void ktest_make_sample_iakerb_header(krb5_iakerb_header *p);
void ktest_make_sample_iakerb_finished(krb5_iakerb_finished *p);
void ktest_make_sample_fast_response(krb5_fast_response *p);
@@ -179,8 +177,6 @@ void ktest_empty_enc_sam_response_enc_2(krb5_enc_sam_response_enc_2 *p);
void ktest_empty_pa_for_user(krb5_pa_for_user *p);
void ktest_empty_pa_s4u_x509_user(krb5_pa_s4u_x509_user *p);
void ktest_empty_ad_kdcissued(krb5_ad_kdcissued *p);
-void ktest_empty_ad_signedpath_data(krb5_ad_signedpath_data *p);
-void ktest_empty_ad_signedpath(krb5_ad_signedpath *p);
void ktest_empty_iakerb_header(krb5_iakerb_header *p);
void ktest_empty_iakerb_finished(krb5_iakerb_finished *p);
void ktest_empty_fast_response(krb5_fast_response *p);
diff --git a/src/tests/asn.1/ktest_equal.c b/src/tests/asn.1/ktest_equal.c
index f4678b6..b48a028 100644
--- a/src/tests/asn.1/ktest_equal.c
+++ b/src/tests/asn.1/ktest_equal.c
@@ -538,34 +538,6 @@ ktest_equal_ad_kdcissued(krb5_ad_kdcissued *ref, krb5_ad_kdcissued *var)
}
int
-ktest_equal_ad_signedpath_data(krb5_ad_signedpath_data *ref,
- krb5_ad_signedpath_data *var)
-{
- int p = TRUE;
- if (ref == var) return TRUE;
- else if (ref == NULL || var == NULL) return FALSE;
- p = p && ptr_equal(client,ktest_equal_principal_data);
- p = p && scalar_equal(authtime);
- p = p && ptr_equal(delegated,ktest_equal_sequence_of_principal);
- p = p && ptr_equal(method_data,ktest_equal_sequence_of_pa_data);
- p = p && ptr_equal(authorization_data,ktest_equal_authorization_data);
- return p;
-}
-
-int
-ktest_equal_ad_signedpath(krb5_ad_signedpath *ref, krb5_ad_signedpath *var)
-{
- int p = TRUE;
- if (ref == var) return TRUE;
- else if (ref == NULL || var == NULL) return FALSE;
- p = p && scalar_equal(enctype);
- p = p && struct_equal(checksum,ktest_equal_checksum);
- p = p && ptr_equal(delegated,ktest_equal_sequence_of_principal);
- p = p && ptr_equal(method_data,ktest_equal_sequence_of_pa_data);
- return p;
-}
-
-int
ktest_equal_iakerb_header(krb5_iakerb_header *ref, krb5_iakerb_header *var)
{
int p = TRUE;
diff --git a/src/tests/asn.1/ktest_equal.h b/src/tests/asn.1/ktest_equal.h
index 80a0d78..8c15cc0 100644
--- a/src/tests/asn.1/ktest_equal.h
+++ b/src/tests/asn.1/ktest_equal.h
@@ -118,10 +118,6 @@ int ktest_equal_pa_for_user(krb5_pa_for_user *ref, krb5_pa_for_user *var);
int ktest_equal_pa_s4u_x509_user(krb5_pa_s4u_x509_user *ref,
krb5_pa_s4u_x509_user *var);
int ktest_equal_ad_kdcissued(krb5_ad_kdcissued *ref, krb5_ad_kdcissued *var);
-int ktest_equal_ad_signedpath_data(krb5_ad_signedpath_data *ref,
- krb5_ad_signedpath_data *var);
-int ktest_equal_ad_signedpath(krb5_ad_signedpath *ref,
- krb5_ad_signedpath *var);
int ktest_equal_iakerb_header(krb5_iakerb_header *ref,
krb5_iakerb_header *var);
int ktest_equal_iakerb_finished(krb5_iakerb_finished *ref,
diff --git a/src/tests/asn.1/reference_encode.out b/src/tests/asn.1/reference_encode.out
index 80b18a2..faa3dba 100644
--- a/src/tests/asn.1/reference_encode.out
+++ b/src/tests/asn.1/reference_encode.out
@@ -55,8 +55,6 @@ encode_krb5_enc_sam_response_enc_2: 30 1F A0 03 02 01 58 A1 18 04 16 65 6E 63 5F
encode_krb5_pa_for_user: 30 4B A0 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A3 0A 1B 08 6B 72 62 35 64 61 74 61
encode_krb5_pa_s4u_x509_user: 30 68 A0 55 30 53 A0 06 02 04 00 CA 14 9A A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 12 04 10 70 61 5F 73 34 75 5F 78 35 30 39 5F 75 73 65 72 A4 07 03 05 00 80 00 00 00 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
encode_krb5_ad_kdcissued: 30 65 A0 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A2 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A3 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
-encode_krb5_ad_signedpath_data: 30 81 C7 A0 30 30 2E A0 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 32 30 30 30 2E A0 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A4 24 30 22 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72 30 0F A0 03 02 01 01 A1 08 04 06 66 6F 6F 62 61 72
-encode_krb5_ad_signedpath: 30 3E A0 03 02 01 01 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A3 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61
encode_krb5_iakerb_header: 30 18 A1 0A 04 08 6B 72 62 35 64 61 74 61 A2 0A 04 08 6B 72 62 35 64 61 74 61
encode_krb5_iakerb_finished: 30 11 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
encode_krb5_fast_response: 30 81 9F A0 26 30 24 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 30 10 A1 03 02 01 0D A2 09 04 07 70 61 2D 64 61 74 61 A1 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A2 5B 30 59 A0 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A1 05 02 03 01 E2 40 A2 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A3 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A4 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34 A3 03 02 01 2A
diff --git a/src/tests/asn.1/trval_reference.out b/src/tests/asn.1/trval_reference.out
index 432fdce..9bedad4 100644
--- a/src/tests/asn.1/trval_reference.out
+++ b/src/tests/asn.1/trval_reference.out
@@ -1251,55 +1251,6 @@ encode_krb5_ad_kdcissued:
. . . [0] [Integer] 1
. . . [1] [Octet String] "foobar"
-encode_krb5_ad_signedpath_data:
-
-[Sequence/Sequence Of]
-. [0] [Sequence/Sequence Of]
-. . [0] [Sequence/Sequence Of]
-. . . [0] [Integer] 1
-. . . [1] [Sequence/Sequence Of]
-. . . . [General string] "hftsai"
-. . . . [General string] "extra"
-. . [1] [General string] "ATHENA.MIT.EDU"
-. [1] [Generalized Time] "19940610060317Z"
-. [2] [Sequence/Sequence Of]
-. . [Sequence/Sequence Of]
-. . . [0] [Sequence/Sequence Of]
-. . . . [0] [Integer] 1
-. . . . [1] [Sequence/Sequence Of]
-. . . . . [General string] "hftsai"
-. . . . . [General string] "extra"
-. . . [1] [General string] "ATHENA.MIT.EDU"
-. [3] [Sequence/Sequence Of]
-. . [Sequence/Sequence Of]
-. . . [1] [Integer] 13
-. . . [2] [Octet String] "pa-data"
-. . [Sequence/Sequence Of]
-. . . [1] [Integer] 13
-. . . [2] [Octet String] "pa-data"
-. [4] [Sequence/Sequence Of]
-. . [Sequence/Sequence Of]
-. . . [0] [Integer] 1
-. . . [1] [Octet String] "foobar"
-. . [Sequence/Sequence Of]
-. . . [0] [Integer] 1
-. . . [1] [Octet String] "foobar"
-
-encode_krb5_ad_signedpath:
-
-[Sequence/Sequence Of]
-. [0] [Integer] 1
-. [1] [Sequence/Sequence Of]
-. . [0] [Integer] 1
-. . [1] [Octet String] "1234"
-. [3] [Sequence/Sequence Of]
-. . [Sequence/Sequence Of]
-. . . [1] [Integer] 13
-. . . [2] [Octet String] "pa-data"
-. . [Sequence/Sequence Of]
-. . . [1] [Integer] 13
-. . . [2] [Octet String] "pa-data"
-
encode_krb5_iakerb_header:
[Sequence/Sequence Of]
diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py
index 746c07f..4a1cdb2 100755
--- a/src/tests/gssapi/t_s4u.py
+++ b/src/tests/gssapi/t_s4u.py
@@ -298,8 +298,7 @@ a_princs = {'krbtgt/A': {'keys': 'aes128-cts'},
'sensitive': {'keys': 'aes128-cts',
'flags': '+disallow_forwardable'},
'impersonator': {'keys': 'aes128-cts'},
- 'service1': {'keys': 'aes128-cts',
- 'flags': '+ok_to_auth_as_delegate'},
+ 'service1': {'keys': 'aes128-cts'},
'rb2': {'keys': 'aes128-cts'},
'rb': {'keys': 'aes128-cts'}}
a_kconf = {'realms': {'$realm': {'database_module': 'test'}},
@@ -311,7 +310,6 @@ a_kconf = {'realms': {'$realm': {'database_module': 'test'}},
'alias': {'rb at A': 'rb',
'rb at B': '@B',
'rb at C': '@B',
- 'rb2_alias': 'rb2',
'service/rb.a': 'rb',
'service/rb.b': '@B',
'service/rb.c': '@B' }}}}
@@ -338,7 +336,8 @@ c_kconf = {'realms': {'$realm': {'database_module': 'test'}},
'capaths': { 'A' : { 'C' : 'B' }},
'dbmodules': {'test': {'db_library': 'test',
'princs': c_princs,
- 'rbcd': {'rb at C': 'impersonator at A'},
+ 'rbcd': {'rb at C': ['impersonator at A',
+ 'service1 at A']},
'alias': {'rb at C': 'rb',
'service/rb.c': 'rb' }}}}
@@ -356,7 +355,7 @@ domain_realm = {'domain_realm': {'.a':'A', '.b':'B', '.c':'C'}}
domain_conf = ra.special_env('domain_conf', False, krb5_conf=domain_realm)
ra.extract_keytab('impersonator at A', ra.keytab)
-ra.kinit('impersonator at A', None, ['-F', '-k', '-t', ra.keytab])
+ra.kinit('impersonator at A', None, ['-f', '-k', '-t', ra.keytab])
mark('Local-realm RBCD')
ra.run(['./t_s4u', 'p:' + ra.user_princ, 'p:rb'])
@@ -388,13 +387,14 @@ ra.run(['./t_s4u', 'p:' + ra.user_princ, 'h:service at rb.c'], env=domain_conf)
ra.run(['./t_s4u', 'p:' + 'sensitive at A', 'h:service at rb.c'], expected_code=1)
ra.run(['./t_s4u', 'p:' + rb.user_princ, 'h:service at rb.c'])
-mark('With both delegation types, 2nd ticket must be forwardable')
+# Although service1 has RBCD delegation privileges to rb2 at A, it does
+# not have ok-to-auth-as-delegate and does have traditional delegation
+# privileges, so it cannot get a forwardable S4U2Self ticket.
+mark('RBCD forwardable blocked by forward delegation privileges')
ra.extract_keytab('service1 at A', ra.keytab)
-ra.kinit('service1 at A', None, ['-F', '-k', '-t', ra.keytab])
-ra.run(['./t_s4u', 'p:' + ra.user_princ, 'p:rb2'], expected_code=1)
-ra.run(['./t_s4u', 'p:' + ra.user_princ, 'p:rb2_alias'])
ra.kinit('service1 at A', None, ['-f', '-k', '-t', ra.keytab])
-ra.run(['./t_s4u', 'p:' + ra.user_princ, 'p:rb2'])
+ra.run(['./t_s4u', 'p:' + ra.user_princ, 'e:rb2 at A'], expected_code=1,
+ expected_msg='KDC can\'t fulfill requested option')
ra.stop()
rb.stop()
diff --git a/src/tests/t_authdata.py b/src/tests/t_authdata.py
index a1d7c7e..fef8a79 100644
--- a/src/tests/t_authdata.py
+++ b/src/tests/t_authdata.py
@@ -6,12 +6,12 @@ greet_path = os.path.join(buildtop, 'plugins', 'authdata', 'greet_server',
conf = {'plugins': {'kdcauthdata': {'module': 'greet:' + greet_path}}}
realm = K5Realm(krb5_conf=conf)
-# With no requested authdata, we expect to see SIGNTICKET (512) in an
+# With no requested authdata, we expect to see PAC (128) in an
# if-relevant container and the greet authdata in a kdc-issued
# container.
mark('baseline authdata')
out = realm.run(['./adata', realm.host_princ])
-if '?512: ' not in out or '^-42: Hello' not in out:
+if '?128: ' not in out or '^-42: Hello' not in out:
fail('expected authdata not seen for basic request')
# Requested authdata is copied into the ticket, with KDC-only types
@@ -29,27 +29,25 @@ mark('AD-MANDATORY-FOR-KDC')
realm.run(['./adata', realm.host_princ, '!-1', 'mandatoryforkdc'],
expected_code=1, expected_msg='KDC policy rejects request')
-# The no_auth_data_required server flag should suppress SIGNTICKET,
-# but not module or request authdata.
+# The no_auth_data_required server flag should suppress the PAC, but
+# not module or request authdata.
mark('no_auth_data_required server flag')
realm.run([kadminl, 'ank', '-randkey', '+no_auth_data_required', 'noauth'])
realm.extract_keytab('noauth', realm.keytab)
out = realm.run(['./adata', 'noauth', '-2', 'test'])
if '^-42: Hello' not in out or ' -2: test' not in out:
fail('expected authdata not seen for no_auth_data_required request')
-if '512: ' in out:
- fail('SIGNTICKET authdata seen for no_auth_data_required request')
+if '128: ' in out:
+ fail('PAC authdata seen for no_auth_data_required request')
-# Cross-realm TGT requests should also suppress SIGNTICKET, but not
-# module or request authdata.
+# Cross-realm TGT requests should not suppress PAC or request
+# authdata.
mark('cross-realm')
realm.addprinc('krbtgt/XREALM')
realm.extract_keytab('krbtgt/XREALM', realm.keytab)
out = realm.run(['./adata', 'krbtgt/XREALM', '-3', 'test'])
-if '^-42: Hello' not in out or ' -3: test' not in out:
+if '128:' not in out or '^-42: Hello' not in out or ' -3: test' not in out:
fail('expected authdata not seen for cross-realm TGT request')
-if '512: ' in out:
- fail('SIGNTICKET authdata seen in cross-realm TGT')
realm.stop()
@@ -69,14 +67,14 @@ else:
realm.addprinc('WELLKNOWN/ANONYMOUS')
realm.kinit('@%s' % realm.realm, flags=['-n'])
- # SIGNTICKET and module authdata should be suppressed for
- # anonymous tickets, but not request authdata.
+ # PAC and module authdata should be suppressed for anonymous
+ # tickets, but not request authdata.
mark('anonymous')
out = realm.run(['./adata', realm.host_princ, '-4', 'test'])
if ' -4: test' not in out:
fail('expected authdata not seen for anonymous request')
- if '512: ' in out or '-42: ' in out:
- fail('SIGNTICKET or greet authdata seen for anonymous request')
+ if '128: ' in out or '-42: ' in out:
+ fail('PAC or greet authdata seen for anonymous request')
realm.stop()
@@ -264,40 +262,20 @@ realm.kinit(realm.user_princ, None,
['-k', '-X', 'indicators=strong dbincr1', '-S', 'rservice'],
expected_code=1)
-# Test that KDB module authdata is included in an AS request, by
-# default or with an explicit PAC request.
-mark('AS-REQ KDB module authdata')
-realm.kinit(realm.user_princ, None, ['-k'])
-realm.run(['./adata', realm.krbtgt_princ],
- expected_msg='-456: db-authdata-test')
-realm.kinit(realm.user_princ, None, ['-k', '--request-pac'])
-realm.run(['./adata', realm.krbtgt_princ],
- expected_msg='-456: db-authdata-test')
-
-# Test that KDB module authdata is suppressed in an AS request by a
-# negative PAC request.
-mark('AS-REQ KDB module authdata client supression')
+# Test that the PAC is suppressed in an AS request by a negative PAC
+# request.
+mark('AS-REQ PAC client supression')
realm.kinit(realm.user_princ, None, ['-k', '--no-request-pac'])
out = realm.run(['./adata', realm.krbtgt_princ])
-if '-456: db-authdata-test' in out:
- fail('DB authdata not suppressed by --no-request-pac')
-
-# Test that KDB authdata is included in a TGS request by default.
-mark('TGS-REQ KDB authdata')
-realm.run(['./adata', 'service/1'], expected_msg='-456: db-authdata-test')
-
-# Test that KDB authdata is suppressed in a TGS request by the
-# +no_auth_data_required flag.
-mark('TGS-REQ KDB authdata service suppression')
-out = realm.run(['./adata', 'noauthdata'])
-if '-456: db-authdata-test' in out:
- fail('DB authdata not suppressed by +no_auth_data_required')
+if '128:' in out:
+ fail('PAC not suppressed by --no-request-pac')
mark('S4U2Proxy with a foreign client')
a_princs = {'krbtgt/A': {'keys': 'aes128-cts'},
'krbtgt/B': {'keys': 'aes128-cts'},
'impersonator': {'keys': 'aes128-cts'},
+ 'impersonator2': {'keys': 'aes128-cts'},
'resource': {'keys': 'aes128-cts'}}
a_kconf = {'realms': {'$realm': {'database_module': 'test'}},
'dbmodules': {'test': {'db_library': 'test',
@@ -312,9 +290,9 @@ b_princs = {'krbtgt/B': {'keys': 'aes128-cts'},
b_kconf = {'realms': {'$realm': {'database_module': 'test'}},
'dbmodules': {'test': {'db_library': 'test',
'princs': b_princs,
- 'rbcd': {'rb at B': 'impersonator at A'},
+ 'rbcd': {'rb at B': 'impersonator2 at A'},
'alias': {'service/rb.b': 'rb',
- 'impersonator at A': '@A'}}}}
+ 'impersonator2 at A': '@A'}}}}
ra, rb = cross_realms(2, xtgts=(),
args=({'realm': 'A', 'kdc_conf': a_kconf},
@@ -325,6 +303,7 @@ ra.start_kdc()
rb.start_kdc()
ra.extract_keytab('impersonator at A', ra.keytab)
+ra.extract_keytab('impersonator2 at A', ra.keytab)
rb.extract_keytab('user at B', rb.keytab)
usercache = 'FILE:' + os.path.join(rb.testdir, 'usercache')
@@ -336,11 +315,11 @@ ra.run(['./s4u2proxy', usercache, 'resource at A'])
mark('Cross realm S4U authdata tests')
-ra.kinit('impersonator at A', None, ['-k', '-t', ra.keytab])
-ra.run(['./s4u2self', rb.user_princ, 'impersonator at A', usercache, '-2',
+ra.kinit('impersonator2 at A', None, ['-f', '-k', '-t', ra.keytab])
+ra.run(['./s4u2self', rb.user_princ, 'impersonator2 at A', usercache, '-2',
'cross_s4u_self_ad'])
out = ra.run(['./adata', '-c', usercache, '-p', rb.user_princ,
- 'impersonator at A', '-2', 'cross_s4u_self_ad'])
+ 'impersonator2 at A', '-2', 'cross_s4u_self_ad'])
if out.count(' -2: cross_s4u_self_ad') != 1:
fail('expected one cross_s4u_self_ad, got: %s' % count)
@@ -357,9 +336,4 @@ if out.count(' -2: cross_s4u_proxy_ad') != 1:
ra.stop()
rb.stop()
-# Additional KDB module authdata behavior we don't currently test:
-# * KDB module authdata is suppressed in TGS requests if the TGT
-# contains no authdata and the request is not cross-realm or S4U.
-# * KDB module authdata is suppressed for anonymous tickets.
-
success('Authorization data tests')
More information about the cvs-krb5
mailing list