diff --git a/kdc/default_config.c b/kdc/default_config.c index 7ba08d123..08f7a3a77 100644 --- a/kdc/default_config.c +++ b/kdc/default_config.c @@ -93,6 +93,7 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) c->svc_use_strongest_session_key = FALSE; c->use_strongest_server_key = TRUE; c->check_ticket_addresses = TRUE; + c->warn_ticket_addresses = FALSE; c->allow_null_ticket_addresses = TRUE; c->allow_anonymous = FALSE; c->historical_anon_realm = FALSE; @@ -176,6 +177,11 @@ krb5_kdc_get_config(krb5_context context, krb5_kdc_configuration **config) c->check_ticket_addresses, "kdc", "check-ticket-addresses", NULL); + c->warn_ticket_addresses = + krb5_config_get_bool_default(context, NULL, + c->warn_ticket_addresses, + "kdc", + "warn_ticket_addresses", NULL); c->allow_null_ticket_addresses = krb5_config_get_bool_default(context, NULL, c->allow_null_ticket_addresses, diff --git a/kdc/kdc.h b/kdc/kdc.h index 84a5b4a05..96c3457b6 100644 --- a/kdc/kdc.h +++ b/kdc/kdc.h @@ -68,6 +68,7 @@ typedef struct krb5_kdc_configuration { krb5_boolean use_strongest_server_key; krb5_boolean check_ticket_addresses; + krb5_boolean warn_ticket_addresses; krb5_boolean allow_null_ticket_addresses; krb5_boolean allow_anonymous; krb5_boolean historical_anon_realm; diff --git a/kdc/kerberos5.c b/kdc/kerberos5.c index 01095892d..1129cad9e 100644 --- a/kdc/kerberos5.c +++ b/kdc/kerberos5.c @@ -1644,10 +1644,15 @@ _kdc_check_addresses(astgs_request_t r, HostAddresses *addresses, krb5_boolean only_netbios = TRUE; size_t i; - if(config->check_ticket_addresses == 0) + if (!config->check_ticket_addresses && !config->warn_ticket_addresses) return TRUE; - if(addresses == NULL) + /* + * Fields of HostAddresses type are always OPTIONAL and should be non- + * empty, but we check for empty just in case as our compiler doesn't + * support size constraints on SEQUENCE OF. + */ + if (addresses == NULL || addresses->len == 0) return config->allow_null_ticket_addresses; for (i = 0; i < addresses->len; ++i) { diff --git a/kdc/krb5tgs.c b/kdc/krb5tgs.c index 2f43aa2ee..dda7684d8 100644 --- a/kdc/krb5tgs.c +++ b/kdc/krb5tgs.c @@ -1214,7 +1214,7 @@ tgs_parse_request(astgs_request_t r, krb5_principal princ; krb5_auth_context ac = NULL; krb5_flags ap_req_options; - krb5_flags verify_ap_req_flags; + krb5_flags verify_ap_req_flags = 0; krb5_crypto crypto; krb5uint32 krbtgt_kvno; /* kvno used for the PA-TGS-REQ AP-REQ Ticket */ krb5uint32 krbtgt_kvno_try; @@ -1337,9 +1337,10 @@ next_kvno: } if (b->kdc_options.validate) - verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID; - else - verify_ap_req_flags = 0; + verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_INVALID; + + if (r->config->warn_ticket_addresses) + verify_ap_req_flags |= KRB5_VERIFY_AP_REQ_IGNORE_ADDRS; ret = krb5_verify_ap_req2(context, &ac, @@ -1350,6 +1351,11 @@ next_kvno: &ap_req_options, ticket, KRB5_KU_TGS_REQ_AUTH); + if (r->config->warn_ticket_addresses && ret == KRB5KRB_AP_ERR_BADADDR && + *ticket != NULL) { + kdc_log(context, config, 4, "Request from wrong address (ignoring)"); + ret = 0; + } if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY && kvno_search_tries > 0) { kvno_search_tries--; krbtgt_kvno_try--; @@ -2388,9 +2394,13 @@ server_lookup: /* check for valid set of addresses */ if (!_kdc_check_addresses(priv, tgt->caddr, from_addr)) { - ret = KRB5KRB_AP_ERR_BADADDR; - kdc_log(context, config, 4, "Request from wrong address"); - goto out; + if (config->check_ticket_addresses) { + ret = KRB5KRB_AP_ERR_BADADDR; + kdc_log(context, config, 4, "Request from wrong address"); + goto out; + } else if (config->warn_ticket_addresses) { + kdc_log(context, config, 4, "Request from wrong address (ignoring)"); + } } /* check local and per-principal anonymous ticket issuance policy */ diff --git a/lib/krb5/krb5.conf.5 b/lib/krb5/krb5.conf.5 index 75b512735..5cf10ddaf 100644 --- a/lib/krb5/krb5.conf.5 +++ b/lib/krb5/krb5.conf.5 @@ -773,6 +773,9 @@ target service principal's hdb entry's current keyset. Defaults to TRUE. .It Li check-ticket-addresses = Va BOOL Verify the addresses in the tickets used in tgs requests. .\" XXX +.It Li warn_ticket_addresses = Va BOOL +Warn about, but allow, usage of tickets from hosts that don't match the +addresses in the tickets. .It Li allow-null-ticket-addresses = Va BOOL Allow address-less tickets. .\" XXX diff --git a/lib/krb5/krb5.h b/lib/krb5/krb5.h index e78873db8..fa2be7ba1 100644 --- a/lib/krb5/krb5.h +++ b/lib/krb5/krb5.h @@ -439,6 +439,7 @@ typedef union { /* flags for krb5_verify_ap_req */ #define KRB5_VERIFY_AP_REQ_IGNORE_INVALID (1 << 0) +#define KRB5_VERIFY_AP_REQ_IGNORE_ADDRS (1 << 1) #define KRB5_GC_CACHED (1U << 0) #define KRB5_GC_USER_USER (1U << 1) diff --git a/lib/krb5/rd_req.c b/lib/krb5/rd_req.c index 1cd8b2658..dd4585f7a 100644 --- a/lib/krb5/rd_req.c +++ b/lib/krb5/rd_req.c @@ -307,6 +307,7 @@ krb5_verify_ap_req2(krb5_context context, krb5_auth_context ac; krb5_error_code ret; EtypeList etypes; + int badaddr = 0; memset(&etypes, 0, sizeof(etypes)); @@ -391,9 +392,19 @@ krb5_verify_ap_req2(krb5_context context, && !krb5_address_search (context, ac->remote_address, t->ticket.caddr)) { - ret = KRB5KRB_AP_ERR_BADADDR; - krb5_clear_error_message (context); - goto out; + /* + * Hack alert. If KRB5_VERIFY_AP_REQ_IGNORE_ADDRS and the client's + * address didn't check out then we'll return KRB5KRB_AP_ERR_BADADDR + * even on success, and we'll let the caller figure it out because + * `*ticket != NULL' or `*auth_context != NULL'. + */ + if ((flags & KRB5_VERIFY_AP_REQ_IGNORE_ADDRS)) { + badaddr = 1; + } else { + ret = KRB5KRB_AP_ERR_BADADDR; + krb5_clear_error_message(context); + goto out; + } } /* check timestamp in authenticator */ @@ -463,6 +474,11 @@ krb5_verify_ap_req2(krb5_context context, } else krb5_auth_con_free (context, ac); free_EtypeList(&etypes); + + if (badaddr) { + krb5_clear_error_message(context); + return KRB5KRB_AP_ERR_BADADDR; + } return 0; out: free_EtypeList(&etypes);