diff --git a/kdc/digest-service.c b/kdc/digest-service.c index 9d6ef9a3f..6608d0a06 100644 --- a/kdc/digest-service.c +++ b/kdc/digest-service.c @@ -44,7 +44,6 @@ typedef struct pk_client_params pk_client_params; struct DigestREQ; struct Kx509Request; -typedef struct kdc_request_desc *kdc_request_t; #include diff --git a/kdc/fast.c b/kdc/fast.c index fe036e9c8..43f36ad58 100644 --- a/kdc/fast.c +++ b/kdc/fast.c @@ -36,7 +36,8 @@ #include "kdc_locl.h" static krb5_error_code -get_fastuser_crypto(kdc_request_t r, krb5_enctype enctype, krb5_crypto *crypto) +get_fastuser_crypto(astgs_request_t r, krb5_enctype enctype, + krb5_crypto *crypto) { krb5_principal fast_princ; hdb_entry_ex *fast_user = NULL; @@ -79,7 +80,7 @@ get_fastuser_crypto(kdc_request_t r, krb5_enctype enctype, krb5_crypto *crypto) static krb5_error_code -fast_parse_cookie(kdc_request_t r, const PA_DATA *pa) +fast_parse_cookie(astgs_request_t r, const PA_DATA *pa) { krb5_crypto crypto = NULL; krb5_error_code ret; @@ -127,7 +128,7 @@ fast_parse_cookie(kdc_request_t r, const PA_DATA *pa) } static krb5_error_code -fast_add_cookie(kdc_request_t r, METHOD_DATA *method_data) +fast_add_cookie(astgs_request_t r, METHOD_DATA *method_data) { krb5_crypto crypto = NULL; KDCFastCookie shell; @@ -237,8 +238,7 @@ _kdc_fast_mk_response(krb5_context context, krb5_error_code -_kdc_fast_mk_error(krb5_context context, - kdc_request_t r, +_kdc_fast_mk_error(astgs_request_t r, METHOD_DATA *error_method, krb5_crypto armor_crypto, const KDC_REQ_BODY *req_body, @@ -250,6 +250,7 @@ _kdc_fast_mk_error(krb5_context context, time_t *csec, int *cusec, krb5_data *error_msg) { + krb5_context context = r->context; krb5_error_code ret; krb5_data e_data; size_t size; @@ -342,7 +343,7 @@ _kdc_fast_mk_error(krb5_context context, } krb5_error_code -_kdc_fast_unwrap_request(kdc_request_t r) +_kdc_fast_unwrap_request(astgs_request_t r) { krb5_principal armor_server = NULL; hdb_entry_ex *armor_user = NULL; diff --git a/kdc/kdc.h b/kdc/kdc.h index 9f871a7fd..5b4474b01 100644 --- a/kdc/kdc.h +++ b/kdc/kdc.h @@ -101,18 +101,14 @@ typedef struct krb5_kdc_configuration { const char *app; } krb5_kdc_configuration; +typedef struct kdc_request_desc *kdc_request_t; +typedef struct astgs_request_desc *astgs_request_t; + struct krb5_kdc_service { unsigned int flags; #define KS_KRB5 1 #define KS_NO_LENGTH 2 - krb5_error_code (*process)(krb5_context context, - krb5_kdc_configuration *config, - krb5_data *req_buffer, - krb5_data *reply, - const char *from, - struct sockaddr *addr, - int datagram_reply, - int *claim); + krb5_error_code (*process)(kdc_request_t *, int *claim); }; #include diff --git a/kdc/kdc_locl.h b/kdc/kdc_locl.h index adbb94765..d8d8fb4c0 100644 --- a/kdc/kdc_locl.h +++ b/kdc/kdc_locl.h @@ -43,24 +43,54 @@ typedef struct pk_client_params pk_client_params; struct DigestREQ; struct Kx509Request; -typedef struct kdc_request_desc *kdc_request_t; #include #define FAST_EXPIRATION_TIME (3 * 60) +#define KDC_AUDIT_EATWHITE 0x1 +#define KDC_AUDIT_VIS 0x2 + +/* KFE == KDC_FIND_ETYPE */ +#define KFE_IS_TGS 0x1 +#define KFE_IS_PREAUTH 0x2 +#define KFE_USE_CLIENT 0x4 + +#define KDC_REQUEST_DESC_COMMON_ELEMENTS \ + /* Input */ \ + krb5_context context; \ + krb5_kdc_configuration *config; \ + const char *from; \ + struct sockaddr *addr; \ + int datagram_reply; \ + krb5_data request; \ + \ + /* Output */ \ + krb5_data *reply; \ + krb5_boolean use_request_t; \ + \ + /* Common state, to be freed in process.c */ \ + struct timeval tv_start; \ + struct timeval tv_end; \ + const char *reqtype; \ + char *cname; \ + char *sname; \ + const char *e_text; \ + char *e_text_buf; \ + heim_array_t kv + struct kdc_request_desc { - krb5_context context; - krb5_kdc_configuration *config; + KDC_REQUEST_DESC_COMMON_ELEMENTS; +}; - /* */ +struct astgs_request_desc { + KDC_REQUEST_DESC_COMMON_ELEMENTS; - krb5_data request; + /* Both AS and TGS */ KDC_REQ req; + + /* Only AS */ METHOD_DATA *padata; - - /* out */ - METHOD_DATA outpadata; KDC_REP rep; @@ -72,16 +102,12 @@ struct kdc_request_desc { krb5_keyblock reply_key; krb5_keyblock session_key; - const char *e_text; - /* state */ krb5_principal client_princ; - char *client_name; hdb_entry_ex *client; HDB *clientdb; krb5_principal server_princ; - char *server_name; hdb_entry_ex *server; krb5_crypto armor_crypto; @@ -89,7 +115,6 @@ struct kdc_request_desc { KDCFastState fast; }; - extern sig_atomic_t exit_flag; extern size_t max_request_udp; extern size_t max_request_tcp; diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 9a3cad6f1..d1152630f 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -35,6 +35,9 @@ #define MAX_TIME ((time_t)((1U << 31) - 1)) +#undef __attribute__ +#define __attribute__(X) + void _kdc_fix_time(time_t **t) { @@ -140,12 +143,17 @@ _kdc_is_anon_request(const KDC_REQ *req) */ krb5_error_code -_kdc_find_etype(krb5_context context, krb5_boolean use_strongest_session_key, - krb5_boolean is_preauth, hdb_entry_ex *princ, - krb5_principal request_princ, krb5_enctype *etypes, unsigned len, +_kdc_find_etype(astgs_request_t r, uint32_t flags, + krb5_enctype *etypes, unsigned len, krb5_enctype *ret_enctype, Key **ret_key, krb5_boolean *ret_default_salt) { + krb5_context context = r->context; + krb5_boolean use_strongest_session_key; + krb5_boolean is_preauth = flags & KFE_IS_PREAUTH; + krb5_boolean is_tgs = flags & KFE_IS_TGS; + hdb_entry_ex *princ; + krb5_principal request_princ; krb5_error_code ret; krb5_salt def_salt; krb5_enctype enctype = (krb5_enctype)ETYPE_NULL; @@ -153,6 +161,19 @@ _kdc_find_etype(krb5_context context, krb5_boolean use_strongest_session_key, Key *key = NULL; int i, k; + if (flags & KFE_USE_CLIENT) { + princ = r->client; + request_princ = r->client_princ; + } else { + princ = r->server; + request_princ = r->server->entry.principal; + } + + use_strongest_session_key = + is_preauth ? r->config->preauth_use_strongest_session_key + : (is_tgs ? r->config->tgt_use_strongest_session_key : + r->config->svc_use_strongest_session_key); + /* We'll want to avoid keys with v4 salted keys in the pre-auth case... */ ret = krb5_get_pw_salt(context, request_princ, &def_salt); if (ret) @@ -295,7 +316,8 @@ failed: } static void -_kdc_r_log(kdc_request_t r, int level, const char *fmt, ...) +_kdc_r_log(astgs_request_t r, int level, const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 3, 4))) { va_list ap; char *s; @@ -305,23 +327,55 @@ _kdc_r_log(kdc_request_t r, int level, const char *fmt, ...) va_end(ap); } -static void -_kdc_set_e_text(kdc_request_t r, const char *e_text) +void +_kdc_set_e_text(astgs_request_t r, char *fmt, ...) + __attribute__ ((__format__ (__printf__, 2, 3))) { + va_list ap; + char *e_text; + + va_start(ap, fmt); + vasprintf(&e_text, fmt, ap); + va_end(ap); + + if (!e_text) + /* not much else to do... */ + return; + + /* We should never see this */ + if (r->e_text) { + kdc_log(r->context, r->config, 1, "trying to replace e-text: %s\n", + e_text); + free(e_text); + return; + } + r->e_text = e_text; + r->e_text_buf = e_text; kdc_log(r->context, r->config, 0, "%s", e_text); } void -_kdc_log_timestamp(krb5_context context, - krb5_kdc_configuration *config, - const char *type, +_kdc_log_timestamp(astgs_request_t r, const char *type, KerberosTime authtime, KerberosTime *starttime, KerberosTime endtime, KerberosTime *renew_till) { + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; char authtime_str[100], starttime_str[100], endtime_str[100], renewtime_str[100]; + if (authtime) + _kdc_audit_addkv((kdc_request_t)r, 0, "auth", "%ld", (long)authtime); + if (starttime && *starttime) + _kdc_audit_addkv((kdc_request_t)r, 0, "start", "%ld", + (long)*starttime); + if (endtime) + _kdc_audit_addkv((kdc_request_t)r, 0, "end", "%ld", (long)endtime); + if (renew_till && *renew_till) + _kdc_audit_addkv((kdc_request_t)r, 0, "renew", "%ld", + (long)*renew_till); + krb5_format_time(context, authtime, authtime_str, sizeof(authtime_str), TRUE); if (starttime) @@ -349,39 +403,32 @@ _kdc_log_timestamp(krb5_context context, #ifdef PKINIT static krb5_error_code -pa_pkinit_validate(kdc_request_t r, const PA_DATA *pa) +pa_pkinit_validate(astgs_request_t r, const PA_DATA *pa) { pk_client_params *pkp = NULL; char *client_cert = NULL; krb5_error_code ret; - ret = _kdc_pk_rd_padata(r->context, r->config, &r->req, pa, r->client, &pkp); + ret = _kdc_pk_rd_padata(r, pa, &pkp); if (ret || pkp == NULL) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - _kdc_r_log(r, 2, "Failed to decode PKINIT PA-DATA -- %s", - r->client_name); + _kdc_r_log(r, 4, "Failed to decode PKINIT PA-DATA -- %s", + r->cname); goto out; } - ret = _kdc_pk_check_client(r->context, - r->config, - r->clientdb, - r->client, - pkp, - &client_cert); + ret = _kdc_pk_check_client(r, pkp, &client_cert); if (ret) { _kdc_set_e_text(r, "PKINIT certificate not allowed to " "impersonate principal"); goto out; } - _kdc_r_log(r, 3, "PKINIT pre-authentication succeeded -- %s using %s", - r->client_name, client_cert); + _kdc_r_log(r, 4, "PKINIT pre-authentication succeeded -- %s using %s", + r->cname, client_cert); free(client_cert); - ret = _kdc_pk_mk_pa_reply(r->context, r->config, pkp, r->client, - r->sessionetype, &r->req, &r->request, - &r->reply_key, &r->session_key, &r->outpadata); + ret = _kdc_pk_mk_pa_reply(r, pkp); if (ret) { _kdc_set_e_text(r, "Failed to build PK-INIT reply"); goto out; @@ -404,9 +451,10 @@ pa_pkinit_validate(kdc_request_t r, const PA_DATA *pa) */ static krb5_error_code -make_pa_enc_challange(krb5_context context, METHOD_DATA *md, - krb5_crypto crypto) +make_pa_enc_challange(astgs_request_t r, krb5_crypto crypto) { + krb5_context context = r->context; + METHOD_DATA *md = &r->outpadata; PA_ENC_TS_ENC p; unsigned char *buf; size_t buf_size; @@ -451,7 +499,7 @@ make_pa_enc_challange(krb5_context context, METHOD_DATA *md, } static krb5_error_code -pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) +pa_enc_chal_validate(astgs_request_t r, const PA_DATA *pa) { krb5_data pepper1, pepper2, ts_data; int invalidPassword = 0; @@ -476,8 +524,8 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) &size); if (ret) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - _kdc_r_log(r, 2, "Failed to decode PA-DATA -- %s", - r->client_name); + _kdc_r_log(r, 4, "Failed to decode PA-DATA -- %s", + r->cname); return ret; } @@ -527,7 +575,7 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) str = NULL; _kdc_r_log(r, 2, "Failed to decrypt ENC-CHAL -- %s " "(enctype %s) error %s", - r->client_name, str ? str : "unknown enctype", msg); + r->cname, str ? str : "unknown enctype", msg); krb5_free_error_message(r->context, msg); free(str); @@ -542,8 +590,8 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) if(ret){ krb5_crypto_destroy(r->context, challangecrypto); ret = KRB5KDC_ERR_PREAUTH_FAILED; - _kdc_r_log(r, 2, "Failed to decode PA-ENC-TS_ENC -- %s", - r->client_name); + _kdc_r_log(r, 4, "Failed to decode PA-ENC-TS_ENC -- %s", + r->cname); continue; } @@ -561,7 +609,7 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) client_time, (unsigned)labs(kdc_time - p.patimestamp), r->context->max_skew, - r->client_name); + r->cname); free_PA_ENC_TS_ENC(&p); goto out; @@ -569,8 +617,7 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) free_PA_ENC_TS_ENC(&p); - ret = make_pa_enc_challange(r->context, &r->outpadata, - challangecrypto); + ret = make_pa_enc_challange(r, challangecrypto); krb5_crypto_destroy(r->context, challangecrypto); if (ret) goto out; @@ -602,7 +649,7 @@ pa_enc_chal_validate(kdc_request_t r, const PA_DATA *pa) } static krb5_error_code -pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) +pa_enc_ts_validate(astgs_request_t r, const PA_DATA *pa) { EncryptedData enc_data; krb5_error_code ret; @@ -619,8 +666,8 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) &len); if (ret) { ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; - _kdc_r_log(r, 2, "Failed to decode PA-DATA -- %s", - r->client_name); + _kdc_r_log(r, 4, "Failed to decode PA-DATA -- %s", + r->cname); goto out; } @@ -635,11 +682,11 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) if(estr == NULL) _kdc_r_log(r, 2, "No client key matching pa-data (%d) -- %s", - enc_data.etype, r->client_name); + enc_data.etype, r->cname); else _kdc_r_log(r, 2, "No client key matching pa-data (%s) -- %s", - estr, r->client_name); + estr, r->cname); free(estr); free_EncryptedData(&enc_data); goto out; @@ -676,7 +723,7 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) str = NULL; _kdc_r_log(r, 2, "Failed to decrypt PA-DATA -- %s " "(enctype %s) error %s", - r->client_name, str ? str : "unknown enctype", msg); + r->cname, str ? str : "unknown enctype", msg); krb5_free_error_message(r->context, msg); free(str); @@ -701,8 +748,8 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) krb5_data_free(&ts_data); if(ret){ ret = KRB5KDC_ERR_PREAUTH_FAILED; - _kdc_r_log(r, 2, "Failed to decode PA-ENC-TS_ENC -- %s", - r->client_name); + _kdc_r_log(r, 4, "Failed to decode PA-ENC-TS_ENC -- %s", + r->cname); goto out; } if (labs(kdc_time - p.patimestamp) > r->context->max_skew) { @@ -717,7 +764,7 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) client_time, (unsigned)labs(kdc_time - p.patimestamp), r->context->max_skew, - r->client_name); + r->cname); /* * The following is needed to make windows clients to @@ -739,8 +786,10 @@ pa_enc_ts_validate(kdc_request_t r, const PA_DATA *pa) ret = krb5_enctype_to_string(r->context, pa_key->key.keytype, &str); if (ret) str = NULL; - _kdc_r_log(r, 3, "ENC-TS Pre-authentication succeeded -- %s using %s", - r->client_name, str ? str : "unknown enctype"); + _kdc_r_log(r, 4, "ENC-TS Pre-authentication succeeded -- %s using %s", + r->cname, str ? str : "unknown enctype"); + _kdc_audit_addkv((kdc_request_t)r, 0, "pa-etype", "%d", + (int)pa_key->key.keytype); free(str); ret = 0; @@ -756,7 +805,7 @@ struct kdc_patypes { unsigned int flags; #define PA_ANNOUNCE 1 #define PA_REQ_FAST 2 /* only use inside fast */ - krb5_error_code (*validate)(kdc_request_t, const PA_DATA *pa); + krb5_error_code (*validate)(astgs_request_t, const PA_DATA *pa); }; static const struct kdc_patypes pat[] = { @@ -796,10 +845,10 @@ static const struct kdc_patypes pat[] = { }; static void -log_patypes(krb5_context context, - krb5_kdc_configuration *config, - METHOD_DATA *padata) +log_patypes(astgs_request_t r, METHOD_DATA *padata) { + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; struct rk_strpool *p = NULL; char *str; size_t n, m; @@ -825,6 +874,8 @@ log_patypes(krb5_context context, str = rk_strpoolcollect(p); kdc_log(context, config, 4, "Client sent patypes: %s", str); + _kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, + "client-pa", "%s", str); free(str); } @@ -1309,18 +1360,28 @@ get_pa_etype_info_both(krb5_context context, * */ -static void -log_as_req(krb5_context context, - krb5_kdc_configuration *config, - krb5_enctype cetype, - krb5_enctype setype, - const KDC_REQ_BODY *b) +void +_log_astgs_req(astgs_request_t r, krb5_enctype setype) { + krb5_context context = r->context; + const KDC_REQ_BODY *b = &r->req.req_body; + krb5_enctype cetype = r->reply_key.keytype; krb5_error_code ret; struct rk_strpool *p; + struct rk_strpool *s = NULL; char *str; + char *cet; + char *set; size_t i; + /* + * we are collecting ``p'' and ``s''. The former is a textual + * representation of the enctypes as strings which will be used + * for debugging. The latter is a terse comma separated list of + * the %d's of the enctypes to emit into our audit trail to + * conserve space in the logs. + */ + p = rk_strpoolprintf(NULL, "%s", "Client supported enctypes: "); for (i = 0; i < b->etype.len; i++) { @@ -1330,44 +1391,55 @@ log_as_req(krb5_context context, free(str); } else p = rk_strpoolprintf(p, "%d", b->etype.val[i]); - if (p && i + 1 < b->etype.len) - p = rk_strpoolprintf(p, ", "); if (p == NULL) { - kdc_log(context, config, 1, "out of memory"); + rk_strpoolfree(s); + _kdc_r_log(r, 4, "out of memory"); return; } + s = rk_strpoolprintf(s, "%d", b->etype.val[i]); + if (i + 1 < b->etype.len) { + p = rk_strpoolprintf(p, ", "); + s = rk_strpoolprintf(s, ","); + } } if (p == NULL) p = rk_strpoolprintf(p, "no encryption types"); - { - char *cet; - char *set; + str = rk_strpoolcollect(s); + if (str) + _kdc_audit_addkv((kdc_request_t)r, 0, "etypes", "%s", str); + free(str); - ret = krb5_enctype_to_string(context, cetype, &cet); - if(ret == 0) { - ret = krb5_enctype_to_string(context, setype, &set); - if (ret == 0) { - p = rk_strpoolprintf(p, ", using %s/%s", cet, set); - free(set); - } - free(cet); + ret = krb5_enctype_to_string(context, cetype, &cet); + if(ret == 0) { + ret = krb5_enctype_to_string(context, setype, &set); + if (ret == 0) { + p = rk_strpoolprintf(p, ", using %s/%s", cet, set); + free(set); } - if (ret != 0) - p = rk_strpoolprintf(p, ", using enctypes %d/%d", - cetype, setype); + free(cet); } + if (ret != 0) + p = rk_strpoolprintf(p, ", using enctypes %d/%d", + cetype, setype); str = rk_strpoolcollect(p); - kdc_log(context, config, 3, "%s", str); + if (str) + _kdc_r_log(r, 4, "%s", str); free(str); + _kdc_audit_addkv((kdc_request_t)r, 0, "etype", "%d/%d", cetype, setype); + { char fixedstr[128]; + unparse_flags(KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(), fixedstr, sizeof(fixedstr)); - if(*fixedstr) - kdc_log(context, config, 3, "Requested flags: %s", fixedstr); + if (*fixedstr) { + _kdc_r_log(r, 4, "Requested flags: %s", fixedstr); + _kdc_audit_addkv((kdc_request_t)r, KDC_AUDIT_EATWHITE, + "flags", "%s", fixedstr); + } } } @@ -1513,10 +1585,11 @@ kdc_check_flags(krb5_context context, */ krb5_boolean -_kdc_check_addresses(krb5_context context, - krb5_kdc_configuration *config, - HostAddresses *addresses, const struct sockaddr *from) +_kdc_check_addresses(astgs_request_t r, HostAddresses *addresses, + const struct sockaddr *from) { + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; krb5_error_code ret; krb5_address addr; krb5_boolean result; @@ -1557,14 +1630,11 @@ _kdc_check_addresses(krb5_context context, * */ krb5_error_code -_kdc_check_anon_policy (krb5_context context, - krb5_kdc_configuration *config, - hdb_entry_ex *client, - hdb_entry_ex *server) +_kdc_check_anon_policy(astgs_request_t r) { - if (!config->allow_anonymous){ - kdc_log(context, config, 2, - "Request for anonymous ticket denied by local policy"); + if (!r->config->allow_anonymous) { + _kdc_r_log(r, 2, + "Request for anonymous ticket denied by local policy"); return KRB5KDC_ERR_POLICY; } @@ -1605,7 +1675,7 @@ send_pac_p(krb5_context context, KDC_REQ *req) */ static krb5_error_code -generate_pac(kdc_request_t r, Key *skey) +generate_pac(astgs_request_t r, Key *skey) { krb5_error_code ret; krb5_pac p = NULL; @@ -1613,8 +1683,8 @@ generate_pac(kdc_request_t r, Key *skey) ret = _kdc_pac_generate(r->context, r->client, &p); if (ret) { - _kdc_r_log(r, 1, "PAC generation failed for -- %s", - r->client_name); + _kdc_r_log(r, 4, "PAC generation failed for -- %s", + r->cname); return ret; } if (p == NULL) @@ -1627,8 +1697,8 @@ generate_pac(kdc_request_t r, Key *skey) &data); krb5_pac_free(r->context, p); if (ret) { - _kdc_r_log(r, 1, "PAC signing failed for -- %s", - r->client_name); + _kdc_r_log(r, 4, "PAC signing failed for -- %s", + r->cname); return ret; } @@ -1651,7 +1721,7 @@ _kdc_is_anonymous(krb5_context context, krb5_const_principal principal) } static int -require_preauth_p(kdc_request_t r) +require_preauth_p(astgs_request_t r) { return r->config->require_preauth || r->client->entry.flags.require_preauth @@ -1664,7 +1734,7 @@ require_preauth_p(kdc_request_t r) */ static krb5_error_code -add_enc_pa_rep(kdc_request_t r) +add_enc_pa_rep(astgs_request_t r) { krb5_error_code ret; krb5_crypto crypto; @@ -1710,15 +1780,12 @@ add_enc_pa_rep(kdc_request_t r) */ krb5_error_code -_kdc_as_rep(kdc_request_t r, - krb5_data *reply, - const char *from, - struct sockaddr *from_addr, - int datagram_reply) +_kdc_as_rep(astgs_request_t r) { krb5_context context = r->context; krb5_kdc_configuration *config = r->config; KDC_REQ *req = &r->req; + const char *from = r->from; KDC_REQ_BODY *b = NULL; AS_REP rep; KDCOptions f; @@ -1730,6 +1797,7 @@ _kdc_as_rep(kdc_request_t r, METHOD_DATA error_method; const PA_DATA *pa; krb5_boolean is_tgs; + const char *msg; memset(&rep, 0, sizeof(rep)); error_method.len = 0; @@ -1750,69 +1818,61 @@ _kdc_as_rep(kdc_request_t r, if (f.canonicalize) flags |= HDB_F_CANON; - if(b->sname == NULL){ + if (b->sname == NULL) { ret = KRB5KRB_ERR_GENERIC; _kdc_set_e_text(r, "No server in request"); - } else{ - ret = _krb5_principalname2krb5_principal (context, - &r->server_princ, - *(b->sname), - b->realm); - if (ret == 0) - ret = krb5_unparse_name(context, r->server_princ, &r->server_name); - } - if (ret) { - kdc_log(context, config, 2, - "AS-REQ malformed server name from %s", from); goto out; } - if(b->cname == NULL){ + + ret = _krb5_principalname2krb5_principal(context, &r->server_princ, + *(b->sname), b->realm); + if (!ret) + ret = krb5_unparse_name(context, r->server_princ, &r->sname); + if (ret) { + kdc_log(context, config, 2, + "AS_REQ malformed server name from %s", from); + goto out; + } + + if (b->cname == NULL) { ret = KRB5KRB_ERR_GENERIC; _kdc_set_e_text(r, "No client in request"); - } else { - ret = _krb5_principalname2krb5_principal (context, - &r->client_princ, - *(b->cname), - b->realm); - if (ret) - goto out; - - ret = krb5_unparse_name(context, r->client_princ, &r->client_name); + goto out; } + + ret = _krb5_principalname2krb5_principal(context, &r->client_princ, + *(b->cname), b->realm); + if (!ret) + ret = krb5_unparse_name(context, r->client_princ, &r->cname); if (ret) { kdc_log(context, config, 2, "AS-REQ malformed client name from %s", from); goto out; } - kdc_log(context, config, 3, "AS-REQ %s from %s for %s", - r->client_name, from, r->server_name); + kdc_log(context, config, 4, "AS-REQ %s from %s for %s", + r->cname, r->from, r->sname); is_tgs = krb5_principal_is_krbtgt(context, r->server_princ); - /* - * - */ - if (_kdc_is_anonymous(context, r->client_princ) && - !_kdc_is_anon_request(&r->req)) { + !_kdc_is_anon_request(req)) { kdc_log(context, config, 2, "Anonymous client w/o anonymous flag"); ret = KRB5KDC_ERR_BADOPTION; goto out; } - /* - * - */ - ret = _kdc_db_fetch(context, config, r->client_princ, HDB_F_GET_CLIENT | flags, NULL, &r->clientdb, &r->client); - if(ret == HDB_ERR_NOT_FOUND_HERE) { + switch (ret) { + case 0: /* Success */ + break; + case HDB_ERR_NOT_FOUND_HERE: kdc_log(context, config, 5, "client %s does not have secrets at this KDC, need to proxy", - r->client_name); + r->cname); goto out; - } else if (ret == HDB_ERR_WRONG_REALM) { + case HDB_ERR_WRONG_REALM: { char *fixed_client_name = NULL; ret = krb5_unparse_name(context, r->client->entry.principal, @@ -1821,25 +1881,20 @@ _kdc_as_rep(kdc_request_t r, goto out; } - kdc_log(context, config, 2, "WRONG_REALM - %s -> %s", - r->client_name, fixed_client_name); + kdc_log(context, config, 4, "WRONG_REALM - %s -> %s", + r->cname, fixed_client_name); free(fixed_client_name); - ret = _kdc_fast_mk_error(context, r, - &error_method, - r->armor_crypto, - &req->req_body, - KRB5_KDC_ERR_WRONG_REALM, - NULL, - r->server_princ, - NULL, + ret = _kdc_fast_mk_error(r, &error_method, r->armor_crypto, + &req->req_body, KRB5_KDC_ERR_WRONG_REALM, + NULL, r->server_princ, NULL, &r->client->entry.principal->realm, - NULL, NULL, - reply); + NULL, NULL, r->reply); goto out; - } else if(ret){ - const char *msg = krb5_get_error_message(context, ret); - kdc_log(context, config, 2, "UNKNOWN -- %s: %s", r->client_name, msg); + } + default: + msg = krb5_get_error_message(context, ret); + kdc_log(context, config, 4, "UNKNOWN -- %s: %s", r->cname, msg); krb5_free_error_message(context, msg); ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; goto out; @@ -1847,13 +1902,16 @@ _kdc_as_rep(kdc_request_t r, ret = _kdc_db_fetch(context, config, r->server_princ, HDB_F_GET_SERVER | flags | (is_tgs ? HDB_F_GET_KRBTGT : 0), NULL, NULL, &r->server); - if(ret == HDB_ERR_NOT_FOUND_HERE) { + switch (ret) { + case 0: /* Success */ + break; + case HDB_ERR_NOT_FOUND_HERE: kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", - r->server_name); + r->sname); goto out; - } else if(ret){ - const char *msg = krb5_get_error_message(context, ret); - kdc_log(context, config, 2, "UNKNOWN -- %s: %s", r->server_name, msg); + default: + msg = krb5_get_error_message(context, ret); + kdc_log(context, config, 4, "UNKNOWN -- %s: %s", r->sname, msg); krb5_free_error_message(context, msg); ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; goto out; @@ -1870,17 +1928,14 @@ _kdc_as_rep(kdc_request_t r, * decrypt. */ - ret = _kdc_find_etype(context, - is_tgs ? config->tgt_use_strongest_session_key - : config->svc_use_strongest_session_key, - FALSE, r->client, r->client_princ, + ret = _kdc_find_etype(r, (is_tgs ? KFE_IS_TGS:0) | KFE_USE_CLIENT, b->etype.val, b->etype.len, &r->sessionetype, NULL, NULL); if (ret) { kdc_log(context, config, 2, "Client (%s) from %s has no common enctypes with KDC " "to use for the session key", - r->client_name, from); + r->cname, from); goto out; } @@ -1891,7 +1946,7 @@ _kdc_as_rep(kdc_request_t r, if(req->padata){ unsigned int n; - log_patypes(context, config, req->padata); + log_patypes(r, req->padata); /* Check if preauth matching */ @@ -1902,10 +1957,11 @@ _kdc_as_rep(kdc_request_t r, continue; kdc_log(context, config, 5, - "Looking for %s pa-data -- %s", pat[n].name, r->client_name); + "Looking for %s pa-data -- %s", pat[n].name, r->cname); i = 0; pa = _kdc_find_padata(req, &i, pat[n].type); if (pa) { + _kdc_audit_addkv((kdc_request_t)r, 0, "pa", "%s", pat[n].name); ret = pat[n].validate(r, pa); if (ret != 0) { krb5_error_code ret2; @@ -1915,10 +1971,9 @@ _kdc_as_rep(kdc_request_t r, /* * If there is a client key, send ETYPE_INFO{,2} */ - ret2 = _kdc_find_etype(context, - config->preauth_use_strongest_session_key, - TRUE, r->client, r->client_princ, b->etype.val, - b->etype.len, NULL, &ckey, &default_salt); + ret2 = _kdc_find_etype(r, KFE_IS_PREAUTH|KFE_USE_CLIENT, + b->etype.val, b->etype.len, + NULL, &ckey, &default_salt); if (ret2 == 0) { ret2 = get_pa_etype_info_both(context, config, &b->etype, &error_method, ckey, !default_salt); @@ -1929,7 +1984,7 @@ _kdc_as_rep(kdc_request_t r, } kdc_log(context, config, 3, "%s pre-authentication succeeded -- %s", - pat[n].name, r->client_name); + pat[n].name, r->cname); found_pa = 1; r->et.flags.pre_authent = 1; } @@ -1953,11 +2008,9 @@ _kdc_as_rep(kdc_request_t r, /* * If there is a client key, send ETYPE_INFO{,2} */ - ret = _kdc_find_etype(context, - config->preauth_use_strongest_session_key, TRUE, - r->client, r->client_princ, - b->etype.val, b->etype.len, NULL, - &ckey, &default_salt); + ret = _kdc_find_etype(r, KFE_IS_PREAUTH|KFE_USE_CLIENT, + b->etype.val, b->etype.len, + NULL, &ckey, &default_salt); if (ret == 0) { ret = get_pa_etype_info_both(context, config, &b->etype, &error_method, ckey, !default_salt); @@ -1987,7 +2040,7 @@ _kdc_as_rep(kdc_request_t r, } if (r->clientdb->hdb_auth_status) { - r->clientdb->hdb_auth_status(context, r->clientdb, r->client, + r->clientdb->hdb_auth_status(context, r->clientdb, r->client, HDB_AUTH_SUCCESS); } @@ -1996,14 +2049,12 @@ _kdc_as_rep(kdc_request_t r, * with in a preauth mech. */ - ret = _kdc_check_access(context, config, r->client, r->client_name, - r->server, r->server_name, - req, &error_method); + ret = _kdc_check_access(r, req, &error_method); if(ret) goto out; if (_kdc_is_anon_request(&r->req)) { - ret = _kdc_check_anon_policy(context, config, r->client, r->server); + ret = _kdc_check_anon_policy(r); if (ret) { _kdc_set_e_text(r, "Anonymous ticket requests are disabled"); goto out; @@ -2018,7 +2069,7 @@ _kdc_as_rep(kdc_request_t r, */ ret = _kdc_get_preferred_key(context, config, - r->server, r->server_name, + r->server, r->sname, &setype, &skey); if(ret) goto out; @@ -2094,7 +2145,7 @@ _kdc_as_rep(kdc_request_t r, } /* check for valid set of addresses */ - if(!_kdc_check_addresses(context, config, b->addresses, from_addr)) { + if (!_kdc_check_addresses(r, b->addresses, r->addr)) { _kdc_set_e_text(r, "Bad address list in requested"); ret = KRB5KRB_AP_ERR_BADADDR; goto out; @@ -2274,8 +2325,9 @@ _kdc_as_rep(kdc_request_t r, generate_pac(r, skey); } - _kdc_log_timestamp(context, config, "AS-REQ", r->et.authtime, r->et.starttime, - r->et.endtime, r->et.renew_till); + _kdc_log_timestamp(r, "AS-REQ", r->et.authtime, + r->et.starttime, r->et.endtime, + r->et.renew_till); { krb5_principal client_principal; @@ -2299,7 +2351,7 @@ _kdc_as_rep(kdc_request_t r, goto out; } - log_as_req(context, config, r->reply_key.keytype, setype, b); + _log_astgs_req(r, setype); /* * We always say we support FAST/enc-pa-rep @@ -2317,7 +2369,7 @@ _kdc_as_rep(kdc_request_t r, ret = add_enc_pa_rep(r); if (ret) { - const char *msg = krb5_get_error_message(r->context, ret); + msg = krb5_get_error_message(r->context, ret); _kdc_r_log(r, 1, "add_enc_pa_rep failed: %s: %d", msg, ret); krb5_free_error_message(r->context, msg); goto out; @@ -2330,17 +2382,18 @@ _kdc_as_rep(kdc_request_t r, ret = _kdc_encode_reply(context, config, r->armor_crypto, req->req_body.nonce, - &rep, &r->et, &r->ek, setype, r->server->entry.kvno, - &skey->key, r->client->entry.kvno, - &r->reply_key, 0, &r->e_text, reply); + &rep, &r->et, &r->ek, setype, + r->server->entry.kvno, &skey->key, + r->client->entry.kvno, + &r->reply_key, 0, &r->e_text, r->reply); if (ret) goto out; /* * Check if message too large */ - if (datagram_reply && reply->length > config->max_datagram_reply_length) { - krb5_data_free(reply); + if (r->datagram_reply && r->reply->length > config->max_datagram_reply_length) { + krb5_data_free(r->reply); ret = KRB5KRB_ERR_RESPONSE_TOO_BIG; _kdc_set_e_text(r, "Reply packet too large"); } @@ -2351,23 +2404,20 @@ out: /* * In case of a non proxy error, build an error message. */ - if (ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE && reply->length == 0) { - ret = _kdc_fast_mk_error(context, r, - &error_method, - r->armor_crypto, - &req->req_body, - ret, r->e_text, - r->server_princ, - r->client_princ ? - &r->client_princ->name : NULL, - r->client_princ ? - &r->client_princ->realm : NULL, - NULL, NULL, - reply); - if (ret) - goto out2; - } -out2: + if (ret != 0 && ret != HDB_ERR_NOT_FOUND_HERE && r->reply->length == 0) + /* We don't want to clobber the original error here... */ + _kdc_fast_mk_error(r, &error_method, + r->armor_crypto, + &req->req_body, + ret, r->e_text, + r->server_princ, + r->client_princ ? + &r->client_princ->name : NULL, + r->client_princ ? + &r->client_princ->realm : NULL, + NULL, NULL, + r->reply); + free_EncTicketPart(&r->et); free_EncKDCRepPart(&r->ek); free_KDCFastState(&r->fast); @@ -2380,18 +2430,10 @@ out2: krb5_free_principal(context, r->client_princ); r->client_princ = NULL; } - if (r->client_name) { - free(r->client_name); - r->client_name = NULL; - } if (r->server_princ){ krb5_free_principal(context, r->server_princ); r->server_princ = NULL; } - if (r->server_name) { - free(r->server_name); - r->server_name = NULL; - } if (r->client) _kdc_free_ent(context, r->client); if (r->server) diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index 111edbe27..686590662 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -757,9 +757,7 @@ fix_transited_encoding(krb5_context context, static krb5_error_code -tgs_make_reply(krb5_context context, - krb5_kdc_configuration *config, - KDC_REQ_BODY *b, +tgs_make_reply(astgs_request_t r, krb5_const_principal tgt_name, const EncTicketPart *tgt, const krb5_keyblock *replykey, @@ -770,7 +768,6 @@ tgs_make_reply(krb5_context context, AuthorizationData *auth_data, hdb_entry_ex *server, krb5_principal server_principal, - const char *server_name, hdb_entry_ex *client, krb5_principal client_principal, const char *tgt_realm, @@ -778,10 +775,13 @@ tgs_make_reply(krb5_context context, krb5_enctype krbtgt_etype, krb5_principals spp, const krb5_data *rspac, - const METHOD_DATA *enc_pa_data, - const char **e_text, - krb5_data *reply) + const METHOD_DATA *enc_pa_data) { + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; + KDC_REQ_BODY *b = &r->req.req_body; + const char **e_text = &r->e_text; + krb5_data *reply = r->reply; KDC_REP rep; EncKDCRepPart ek; EncTicketPart et; @@ -988,14 +988,14 @@ tgs_make_reply(krb5_context context, ek.srealm = rep.ticket.realm; ek.sname = rep.ticket.sname; - _kdc_log_timestamp(context, config, "TGS-REQ", et.authtime, et.starttime, + _kdc_log_timestamp(r, "TGS-REQ", et.authtime, et.starttime, et.endtime, et.renew_till); /* Don't sign cross realm tickets, they can't be checked anyway */ { - char *r = get_krbtgt_realm(&ek.sname); + char *realm = get_krbtgt_realm(&ek.sname); - if (r == NULL || strcmp(r, ek.srealm) == 0) { + if (realm == NULL || strcmp(realm, ek.srealm) == 0) { ret = _kdc_add_KRB5SignedPath(context, config, krbtgt, @@ -1046,6 +1046,9 @@ tgs_make_reply(krb5_context context, if (is_weak) krb5_enctype_disable(context, serverkey->keytype); + r->reply_key.keytype = replykey->keytype; + _log_astgs_req(r, serverkey->keytype); + out: free_TGS_REP(&rep); free_TransitedEncoding(&et.transited); @@ -1182,9 +1185,7 @@ need_referral(krb5_context context, krb5_kdc_configuration *config, } static krb5_error_code -tgs_parse_request(krb5_context context, - krb5_kdc_configuration *config, - KDC_REQ_BODY *b, +tgs_parse_request(astgs_request_t r, const PA_DATA *tgs_req, hdb_entry_ex **krbtgt, krb5_enctype *krbtgt_etype, @@ -1198,6 +1199,9 @@ tgs_parse_request(krb5_context context, krb5_keyblock **replykey, int *rk_is_subkey) { + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; + KDC_REQ_BODY *b = &r->req.req_body; static char failed[] = ""; krb5_ap_req ap_req; krb5_error_code ret; @@ -1544,21 +1548,21 @@ eout: } static krb5_error_code -tgs_build_reply(krb5_context context, - krb5_kdc_configuration *config, - KDC_REQ *req, - KDC_REQ_BODY *b, +tgs_build_reply(astgs_request_t priv, hdb_entry_ex *krbtgt, krb5_enctype krbtgt_etype, const krb5_keyblock *replykey, int rk_is_subkey, krb5_ticket *ticket, - krb5_data *reply, - const char *from, const char **e_text, AuthorizationData **auth_data, const struct sockaddr *from_addr) { + krb5_context context = priv->context; + krb5_kdc_configuration *config = priv->config; + KDC_REQ *req = &priv->req; + KDC_REQ_BODY *b = &priv->req.req_body; + const char *from = priv->from; krb5_error_code ret, ret2; krb5_principal cp = NULL, sp = NULL, rsp = NULL, tp = NULL, dp = NULL; krb5_principal krbtgt_out_principal = NULL; @@ -1667,13 +1671,15 @@ tgs_build_reply(krb5_context context, } _krb5_principalname2krb5_principal(context, &sp, *s, r); - ret = krb5_unparse_name(context, sp, &spn); + ret = krb5_unparse_name(context, sp, &priv->sname); if (ret) goto out; + spn = priv->sname; _krb5_principalname2krb5_principal(context, &cp, tgt->cname, tgt->crealm); - ret = krb5_unparse_name(context, cp, &cpn); + ret = krb5_unparse_name(context, cp, &priv->cname); if (ret) goto out; + cpn = priv->cname; unparse_flags (KDCOptions2int(b->kdc_options), asn1_KDCOptions_units(), opt_str, sizeof(opt_str)); @@ -1692,7 +1698,7 @@ tgs_build_reply(krb5_context context, server_lookup: ret = _kdc_db_fetch(context, config, sp, HDB_F_GET_SERVER | flags, NULL, NULL, &server); - + priv->server = server; if (ret == HDB_ERR_NOT_FOUND_HERE) { kdc_log(context, config, 5, "target %s does not have secrets at this KDC, need to proxy", spn); goto out; @@ -1714,11 +1720,12 @@ server_lookup: ref_realm, NULL); if (ret) goto out; - free(spn); - spn = NULL; - ret = krb5_unparse_name(context, sp, &spn); + free(priv->sname); + priv->sname = NULL; + ret = krb5_unparse_name(context, sp, &priv->sname); if (ret) goto out; + spn = priv->sname; goto server_lookup; } else if (ret) { @@ -1753,11 +1760,12 @@ server_lookup: sp = NULL; krb5_make_principal(context, &sp, r, KRB5_TGS_NAME, ref_realm, NULL); - free(spn); - spn = NULL; - ret = krb5_unparse_name(context, sp, &spn); + free(priv->sname); + priv->sname = NULL; + ret = krb5_unparse_name(context, sp, &priv->sname); if (ret) goto out; + spn = priv->sname; goto server_lookup; } } else if (need_referral(context, config, &b->kdc_options, sp, &realms)) { @@ -1770,13 +1778,14 @@ server_lookup: sp = NULL; krb5_make_principal(context, &sp, r, KRB5_TGS_NAME, realms[0], NULL); - free(spn); - spn = NULL; - ret = krb5_unparse_name(context, sp, &spn); + free(priv->sname); + priv->sname = NULL; + ret = krb5_unparse_name(context, sp, &priv->sname); if (ret) { krb5_free_host_realm(context, realms); goto out; } + spn = priv->sname; free(ref_realm); ref_realm = strdup(realms[0]); @@ -1832,13 +1841,9 @@ server_lookup: } else { Key *skey; - ret = _kdc_find_etype(context, - krb5_principal_is_krbtgt(context, sp) ? - config->tgt_use_strongest_session_key : - config->svc_use_strongest_session_key, FALSE, - server, server->entry.principal, - b->etype.val, b->etype.len, &etype, - NULL, + ret = _kdc_find_etype(priv, krb5_principal_is_krbtgt(context, sp) + ? KFE_IS_TGS : 0, + b->etype.val, b->etype.len, &etype, NULL, NULL); if(ret) { kdc_log(context, config, 2, @@ -1956,6 +1961,7 @@ server_lookup: ret = _kdc_db_fetch(context, config, cp, HDB_F_GET_CLIENT | flags, NULL, &clientdb, &client); + priv->client = client; if(ret == HDB_ERR_NOT_FOUND_HERE) { /* This is OK, we are just trying to find out if they have * been disabled or deleted in the meantime, missing secrets @@ -2332,6 +2338,7 @@ server_lookup: goto out; } + _kdc_audit_addkv((kdc_request_t)priv, 0, "impersonatee", tpn); kdc_log(context, config, 3, "constrained delegation for %s " "from %s (%s) to %s", tpn, cpn, dpn, spn); } @@ -2357,7 +2364,7 @@ server_lookup: } /* check for valid set of addresses */ - if(!_kdc_check_addresses(context, config, tgt->caddr, from_addr)) { + if (!_kdc_check_addresses(priv, tgt->caddr, from_addr)) { ret = KRB5KRB_AP_ERR_BADADDR; kdc_log(context, config, 2, "Request from wrong address"); goto out; @@ -2365,7 +2372,7 @@ server_lookup: /* check local and per-principal anonymous ticket issuance policy */ if (is_anon_tgs_request_p(b, tgt)) { - ret = _kdc_check_anon_policy(context, config, client, server); + ret = _kdc_check_anon_policy(priv); if (ret) goto out; } @@ -2408,9 +2415,7 @@ server_lookup: * */ - ret = tgs_make_reply(context, - config, - b, + ret = tgs_make_reply(priv, tp, tgt, replykey, @@ -2421,7 +2426,6 @@ server_lookup: *auth_data, server, rsp, - spn, client, cp, tgt_realm, @@ -2429,15 +2433,11 @@ server_lookup: tkey_sign->key.keytype, spp, &rspac, - &enc_pa_data, - e_text, - reply); + &enc_pa_data); out: if (tpn != cpn) free(tpn); - free(spn); - free(cpn); free(dpn); free(krbtgt_out_n); _krb5_free_capath(context, capath); @@ -2472,14 +2472,15 @@ out: */ krb5_error_code -_kdc_tgs_rep(krb5_context context, - krb5_kdc_configuration *config, - KDC_REQ *req, - krb5_data *data, - const char *from, - struct sockaddr *from_addr, - int datagram_reply) +_kdc_tgs_rep(astgs_request_t r) { + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; + KDC_REQ *req = &r->req; + krb5_data *data = r->reply; + const char *from = r->from; + struct sockaddr *from_addr = r->addr; + int datagram_reply = r->datagram_reply; AuthorizationData *auth_data = NULL; krb5_error_code ret; int i = 0; @@ -2511,8 +2512,7 @@ _kdc_tgs_rep(krb5_context context, "TGS-REQ from %s without PA-TGS-REQ", from); goto out; } - ret = tgs_parse_request(context, config, - &req->req_body, tgs_req, + ret = tgs_parse_request(r, tgs_req, &krbtgt, &krbtgt_etype, &ticket, @@ -2539,17 +2539,12 @@ _kdc_tgs_rep(krb5_context context, } - ret = tgs_build_reply(context, - config, - req, - &req->req_body, + ret = tgs_build_reply(r, krbtgt, krbtgt_etype, replykey, rk_is_subkey, ticket, - data, - from, &e_text, &auth_data, from_addr); @@ -2576,7 +2571,7 @@ out: kdc_log(context, config, 5, "tgs-req: sending error: %d to client", ret); - ret = _kdc_fast_mk_error(context, NULL, + ret = _kdc_fast_mk_error(r, &error_method, NULL, NULL, diff --git a/kdc/pkinit.c b/kdc/pkinit.c index 67026ef33..9fe316f46 100644 --- a/kdc/pkinit.c +++ b/kdc/pkinit.c @@ -392,13 +392,15 @@ get_dh_param(krb5_context context, } krb5_error_code -_kdc_pk_rd_padata(krb5_context context, - krb5_kdc_configuration *config, - const KDC_REQ *req, +_kdc_pk_rd_padata(astgs_request_t priv, const PA_DATA *pa, - hdb_entry_ex *client, pk_client_params **ret_params) { + /* XXXrcd: we use priv vs r due to a conflict */ + krb5_context context = priv->context; + krb5_kdc_configuration *config = priv->config; + const KDC_REQ *req = &priv->req; + hdb_entry_ex *client = priv->client; pk_client_params *cp; krb5_error_code ret; heim_oid eContentType = { 0, NULL }, contentInfoOid = { 0, NULL }; @@ -1124,17 +1126,16 @@ pk_mk_pa_reply_dh(krb5_context context, */ krb5_error_code -_kdc_pk_mk_pa_reply(krb5_context context, - krb5_kdc_configuration *config, - pk_client_params *cp, - const hdb_entry_ex *client, - krb5_enctype sessionetype, - const KDC_REQ *req, - const krb5_data *req_buffer, - krb5_keyblock *reply_key, - krb5_keyblock *sessionkey, - METHOD_DATA *md) +_kdc_pk_mk_pa_reply(astgs_request_t r, pk_client_params *cp) { + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; + krb5_enctype sessionetype = r->sessionetype; + const KDC_REQ *req = &r->req; + const krb5_data *req_buffer = &r->request; + krb5_keyblock *reply_key = &r->reply_key; + krb5_keyblock *sessionkey = &r->session_key; + METHOD_DATA *md = &r->outpadata; krb5_error_code ret; void *buf = NULL; size_t len = 0, size = 0; @@ -1663,13 +1664,14 @@ out: } krb5_error_code -_kdc_pk_check_client(krb5_context context, - krb5_kdc_configuration *config, - HDB *clientdb, - hdb_entry_ex *client, +_kdc_pk_check_client(astgs_request_t r, pk_client_params *cp, char **subject_name) { + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; + HDB *clientdb = r->clientdb; + hdb_entry_ex *client = r->client; const HDB_Ext_PKINIT_acl *acl; const HDB_Ext_PKINIT_cert *pc; krb5_error_code ret; diff --git a/kdc/process.c b/kdc/process.c index 64d78e65c..5af163e32 100644 --- a/kdc/process.c +++ b/kdc/process.c @@ -33,11 +33,174 @@ */ #include "kdc_locl.h" +#include /* * */ +#undef __attribute__ +#define __attribute__(x) + +/* + * append_token adds a token which is optionally a kv-pair and it + * also optionally eats the whitespace. If k == NULL, then it's + * not a kv-pair. + */ + +void +_kdc_audit_addkv(kdc_request_t r, int flags, const char *k, + const char *fmt, ...) + __attribute__ ((__format__ (__printf__, 4, 5))) +{ + va_list ap; + heim_string_t str; + size_t i,j; + char *buf1; + char *buf2; + char *buf3; + + va_start(ap, fmt); + vasprintf(&buf1, fmt, ap); + va_end(ap); + if (!buf1) + return; + + j = asprintf(&buf2, "%s=%s", k, buf1); + free(buf1); + if (!buf2) + return; + + /* We optionally eat the whitespace. */ + + if (flags | KDC_AUDIT_EATWHITE) { + for (i=0, j=0; buf2[i]; i++) + if (buf2[i] != ' ' && buf2[i] != '\t') + buf2[j++] = buf2[i]; + buf2[j] = '\0'; + } + + if (flags | KDC_AUDIT_VIS) { + buf3 = malloc((j + 1) * 4 + 1); + strvisx(buf3, buf2, j, VIS_OCTAL); + free(buf2); + } else + buf3 = buf2; + + str = heim_string_create(buf3); + free(buf3); + if (!str) + return; + + heim_array_append_value(r->kv, str); +} + +void +_kdc_audit_addkv_timediff(kdc_request_t r, const char *k, + const struct timeval *start, + const struct timeval *end) +{ + time_t sec; + int usec; + const char *sign = ""; + + if (end->tv_sec > start->tv_sec || + (end->tv_sec == start->tv_sec && end->tv_usec >= start->tv_usec)) { + sec = end->tv_sec - start->tv_sec; + usec = end->tv_usec - start->tv_usec; + } else { + sec = start->tv_sec - end->tv_sec; + usec = start->tv_usec - end->tv_usec; + sign = "-"; + } + + if (usec < 0) { + usec += 1000000; + sec -= 1; + } + + _kdc_audit_addkv(r, 0, k, "%s%ld.%06d", sign, sec, usec); +} + +void +_kdc_audit_trail(kdc_request_t r, krb5_error_code ret) +{ + const char *retval; + char kvbuf[1024]; + size_t nelem; + size_t i, j; + +#define CASE(x) case x : retval = #x; break + switch (ret) { + CASE(ENOMEM); + CASE(HDB_ERR_NOT_FOUND_HERE); + CASE(HDB_ERR_WRONG_REALM); + CASE(HDB_ERR_EXISTS); + CASE(HDB_ERR_KVNO_NOT_FOUND); + CASE(HDB_ERR_NOENTRY); + CASE(HDB_ERR_NO_MKEY); + CASE(KRB5KDC_ERR_BADOPTION); + CASE(KRB5KDC_ERR_CANNOT_POSTDATE); + CASE(KRB5KDC_ERR_CLIENT_NOTYET); + CASE(KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN); + CASE(KRB5KDC_ERR_ETYPE_NOSUPP); + CASE(KRB5KDC_ERR_KEY_EXPIRED); + CASE(KRB5KDC_ERR_NAME_EXP); + CASE(KRB5KDC_ERR_NEVER_VALID); + CASE(KRB5KDC_ERR_NONE); + CASE(KRB5KDC_ERR_NULL_KEY); + CASE(KRB5KDC_ERR_PADATA_TYPE_NOSUPP); + CASE(KRB5KDC_ERR_POLICY); + CASE(KRB5KDC_ERR_PREAUTH_FAILED); + CASE(KRB5KDC_ERR_PREAUTH_REQUIRED); + CASE(KRB5KDC_ERR_SERVER_NOMATCH); + CASE(KRB5KDC_ERR_SERVICE_EXP); + CASE(KRB5KDC_ERR_SERVICE_NOTYET); + CASE(KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN); + CASE(KRB5KDC_ERR_TRTYPE_NOSUPP); + CASE(KRB5KRB_ERR_RESPONSE_TOO_BIG); + case 0: + retval = "SUCCESS"; + break; + default: + retval = "UNKNOWN"; + break; + } + + /* Let's save a few bytes */ +#define PREFIX "KRB5KDC_" + if (!strncmp(PREFIX, retval, strlen(PREFIX))) + retval += strlen(PREFIX); +#undef PREFIX + + /* Calculate metrics and add them */ + + _kdc_audit_addkv_timediff(r, "elapsed", &r->tv_start, &r->tv_end); + + if (r->e_text) + _kdc_audit_addkv(r, KDC_AUDIT_VIS, "e-text", r->e_text); + + nelem = heim_array_get_length(r->kv); + for (i=0, j=0; i < nelem; i++) { + heim_string_t s; + const char *kvpair; + + s = heim_array_get_value(r->kv, i); + /* XXXrcd: in string.c the check? */ + kvpair = heim_string_get_utf8(s); + + if (j < sizeof(kvbuf) - 1) + kvbuf[j++] = ' '; + for (; *kvpair && j < sizeof(kvbuf) - 1; j++) + kvbuf[j] = *kvpair++; + } + kvbuf[j] = '\0'; + + kdc_log(r->context, r->config, 3, "%s %s %s %s %s%s", + r->reqtype, retval, r->from, r->cname, + r->sname, kvbuf); +} + void krb5_kdc_update_time(struct timeval *tv) { @@ -47,89 +210,86 @@ krb5_kdc_update_time(struct timeval *tv) _kdc_now = *tv; } + +#define EXTEND_REQUEST_T(LHS, RHS) do { \ + RHS = realloc(LHS, sizeof(*RHS)); \ + if (!RHS) \ + return krb5_enomem((LHS)->context); \ + LHS = (void *)RHS; \ + memset(((char *)LHS) + sizeof(*LHS), \ + 0x0, \ + sizeof(*RHS) - sizeof(*LHS)); \ + } while (0) + static krb5_error_code -kdc_as_req(krb5_context context, - krb5_kdc_configuration *config, - krb5_data *req_buffer, - krb5_data *reply, - const char *from, - struct sockaddr *addr, - int datagram_reply, - int *claim) +kdc_as_req(kdc_request_t *rptr, int *claim) { - struct kdc_request_desc r; + astgs_request_t r; krb5_error_code ret; size_t len; - memset(&r, 0, sizeof(r)); + /* We must free things in the extensions */ + EXTEND_REQUEST_T(*rptr, r); - ret = decode_AS_REQ(req_buffer->data, req_buffer->length, &r.req, &len); + ret = decode_AS_REQ(r->request.data, r->request.length, &r->req, &len); if (ret) return ret; - r.context = context; - r.config = config; - r.request.data = req_buffer->data; - r.request.length = req_buffer->length; - + r->reqtype = "AS-REQ"; + r->use_request_t = 1; *claim = 1; - ret = _kdc_as_rep(&r, reply, from, addr, datagram_reply); - free_AS_REQ(&r.req); + ret = _kdc_as_rep(r); + free_AS_REQ(&r->req); return ret; } static krb5_error_code -kdc_tgs_req(krb5_context context, - krb5_kdc_configuration *config, - krb5_data *req_buffer, - krb5_data *reply, - const char *from, - struct sockaddr *addr, - int datagram_reply, - int *claim) +kdc_tgs_req(kdc_request_t *rptr, int *claim) { + astgs_request_t r; krb5_error_code ret; - KDC_REQ req; size_t len; - ret = decode_TGS_REQ(req_buffer->data, req_buffer->length, &req, &len); + /* We must free things in the extensions */ + EXTEND_REQUEST_T(*rptr, r); + + ret = decode_TGS_REQ(r->request.data, r->request.length, &r->req, &len); if (ret) return ret; + r->reqtype = "TGS-REQ"; + r->use_request_t = 1; *claim = 1; - ret = _kdc_tgs_rep(context, config, &req, reply, - from, addr, datagram_reply); - free_TGS_REQ(&req); + ret = _kdc_tgs_rep(r); + free_TGS_REQ(&r->req); return ret; } #ifdef DIGEST static krb5_error_code -kdc_digest(krb5_context context, - krb5_kdc_configuration *config, - krb5_data *req_buffer, - krb5_data *reply, - const char *from, - struct sockaddr *addr, - int datagram_reply, - int *claim) +kdc_digest(kdc_request_t *rptr, int *claim) { + kdc_request_t r; DigestREQ digestreq; krb5_error_code ret; size_t len; - ret = decode_DigestREQ(req_buffer->data, req_buffer->length, + r = *rptr; + + ret = decode_DigestREQ(r->request.data, r->request.length, &digestreq, &len); if (ret) return ret; + r->use_request_t = 0; *claim = 1; - ret = _kdc_do_digest(context, config, &digestreq, reply, from, addr); + ret = _kdc_do_digest(r->context, r->config, &digestreq, + r->reply, r->from, r->addr); free_DigestREQ(&digestreq); return ret; } @@ -139,15 +299,15 @@ kdc_digest(krb5_context context, #ifdef KX509 static krb5_error_code -kdc_kx509(krb5_context context, - krb5_kdc_configuration *config, - krb5_data *req_buffer, - krb5_data *reply, - const char *from, - struct sockaddr *addr, - int datagram_reply, - int *claim) +kdc_kx509(kdc_request_t *rptr, int *claim) { + kdc_request_t r = *rptr; + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; + krb5_data *req_buffer = &r->request; + krb5_data *reply = r->reply; + const char *from = r->from; + struct sockaddr *addr = r->addr; Kx509Request kx509req; krb5_error_code ret; @@ -156,6 +316,7 @@ kdc_kx509(krb5_context context, if (ret) return ret; + r->use_request_t = 0; *claim = 1; ret = _kdc_do_kx509(context, config, &kx509req, reply, from, addr); @@ -178,6 +339,70 @@ static struct krb5_kdc_service services[] = { { 0, NULL } }; +static int +process_request(krb5_context context, + krb5_kdc_configuration *config, + unsigned int krb5_only, + unsigned char *buf, + size_t len, + krb5_data *reply, + krb5_boolean *prependlength, + const char *from, + struct sockaddr *addr, + int datagram_reply) +{ + kdc_request_t r; + krb5_error_code ret; + unsigned int i; + int claim = 0; + heim_auto_release_t pool = heim_auto_release_create(); + + r = calloc(sizeof(*r), 1); + if (!r) + return krb5_enomem(context); + + r->context = context; + r->config = config; + r->from = from; + r->request.data = buf; + r->request.length = len; + r->datagram_reply = datagram_reply; + r->reply = reply; + r->kv = heim_array_create(); + if (!r->kv) { + free(r); + return krb5_enomem(context); + } + + gettimeofday(&r->tv_start, NULL); + + for (i = 0; services[i].process != NULL; i++) { + if (krb5_only && (services[i].flags & KS_KRB5) == 0) + continue; + ret = (*services[i].process)(&r, &claim); + if (claim) { + if (prependlength && services[i].flags & KS_NO_LENGTH) + *prependlength = 0; + + if (r->use_request_t) { + gettimeofday(&r->tv_end, NULL); + _kdc_audit_trail(r, ret); + free(r->cname); + free(r->sname); + free(r->e_text_buf); + heim_release(r->kv); + } + + heim_release(pool); + return ret; + } + } + + heim_release(pool); + + return -1; +} + /* * handle the request in `buf, len', from `addr' (or `from' as a string), * sending a reply in `reply'. @@ -194,33 +419,10 @@ krb5_kdc_process_request(krb5_context context, struct sockaddr *addr, int datagram_reply) { - krb5_error_code ret; - unsigned int i; - krb5_data req_buffer; - int claim = 0; - heim_auto_release_t pool = heim_auto_release_create(); - - req_buffer.data = buf; - req_buffer.length = len; - - for (i = 0; services[i].process != NULL; i++) { - ret = (*services[i].process)(context, config, &req_buffer, - reply, from, addr, datagram_reply, - &claim); - if (claim) { - if (services[i].flags & KS_NO_LENGTH) - *prependlength = 0; - - heim_release(pool); - return ret; - } - } - - heim_release(pool); - - return -1; + return process_request(context, config, 0, buf, len, reply, prependlength, + from, addr, datagram_reply); } - + /* * handle the request in `buf, len', from `addr' (or `from' as a string), * sending a reply in `reply'. @@ -238,27 +440,11 @@ krb5_kdc_process_krb5_request(krb5_context context, struct sockaddr *addr, int datagram_reply) { - krb5_error_code ret; - unsigned int i; - krb5_data req_buffer; - int claim = 0; - - req_buffer.data = buf; - req_buffer.length = len; - - for (i = 0; services[i].process != NULL; i++) { - if ((services[i].flags & KS_KRB5) == 0) - continue; - ret = (*services[i].process)(context, config, &req_buffer, - reply, from, addr, datagram_reply, - &claim); - if (claim) - return ret; - } - - return -1; + return process_request(context, config, 1, buf, len, reply, NULL, + from, addr, datagram_reply); } + /* * */ diff --git a/kdc/windc.c b/kdc/windc.c index dda921b4c..762212921 100644 --- a/kdc/windc.c +++ b/kdc/windc.c @@ -187,13 +187,14 @@ check(krb5_context context, const void *plug, void *plugctx, void *userctx) krb5_error_code -_kdc_check_access(krb5_context context, - krb5_kdc_configuration *config, - hdb_entry_ex *client_ex, const char *client_name, - hdb_entry_ex *server_ex, const char *server_name, - KDC_REQ *req, - METHOD_DATA *method_data) +_kdc_check_access(astgs_request_t r, KDC_REQ *req, METHOD_DATA *method_data) { + krb5_context context = r->context; + krb5_kdc_configuration *config = r->config; + hdb_entry_ex *client_ex = r->client; + const char *client_name = r->cname; + hdb_entry_ex *server_ex = r->server; + const char *server_name = r->sname; krb5_error_code ret = KRB5_PLUGIN_NO_HANDLE; struct check_uc uc;