diff options
author | Greg Hudson <ghudson@mit.edu> | 2022-01-07 22:41:30 -0500 |
---|---|---|
committer | Greg Hudson <ghudson@mit.edu> | 2022-01-12 13:28:07 -0500 |
commit | a441fbe329ebbd7775eb5d4ccc4a05eef370f08b (patch) | |
tree | ed56952614e5c72981d48d75398d33b2a7fffb05 | |
parent | c85894cfb784257a6acb4d77d8c75137d2508f5e (diff) | |
download | krb5-a441fbe329ebbd7775eb5d4ccc4a05eef370f08b.zip krb5-a441fbe329ebbd7775eb5d4ccc4a05eef370f08b.tar.gz krb5-a441fbe329ebbd7775eb5d4ccc4a05eef370f08b.tar.bz2 |
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)
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@A': 'rb', 'rb@B': '@B', 'rb@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@C': 'impersonator@A'}, + 'rbcd': {'rb@C': ['impersonator@A', + 'service1@A']}, 'alias': {'rb@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@A', ra.keytab) -ra.kinit('impersonator@A', None, ['-F', '-k', '-t', ra.keytab]) +ra.kinit('impersonator@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@rb.c'], env=domain_conf) ra.run(['./t_s4u', 'p:' + 'sensitive@A', 'h:service@rb.c'], expected_code=1) ra.run(['./t_s4u', 'p:' + rb.user_princ, 'h:service@rb.c']) -mark('With both delegation types, 2nd ticket must be forwardable') +# Although service1 has RBCD delegation privileges to rb2@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@A', ra.keytab) -ra.kinit('service1@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@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@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@B': 'impersonator@A'}, + 'rbcd': {'rb@B': 'impersonator2@A'}, 'alias': {'service/rb.b': 'rb', - 'impersonator@A': '@A'}}}} + 'impersonator2@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@A', ra.keytab) +ra.extract_keytab('impersonator2@A', ra.keytab) rb.extract_keytab('user@B', rb.keytab) usercache = 'FILE:' + os.path.join(rb.testdir, 'usercache') @@ -336,11 +315,11 @@ ra.run(['./s4u2proxy', usercache, 'resource@A']) mark('Cross realm S4U authdata tests') -ra.kinit('impersonator@A', None, ['-k', '-t', ra.keytab]) -ra.run(['./s4u2self', rb.user_princ, 'impersonator@A', usercache, '-2', +ra.kinit('impersonator2@A', None, ['-f', '-k', '-t', ra.keytab]) +ra.run(['./s4u2self', rb.user_princ, 'impersonator2@A', usercache, '-2', 'cross_s4u_self_ad']) out = ra.run(['./adata', '-c', usercache, '-p', rb.user_princ, - 'impersonator@A', '-2', 'cross_s4u_self_ad']) + 'impersonator2@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') |