From fd77c4000dff70fdab17d8be19801608f4c8ca43 Mon Sep 17 00:00:00 2001 From: Taylor R Campbell Date: Fri, 9 Jun 2023 00:08:21 +0000 Subject: [PATCH] Ensure all calls to getaddrinfo are headed by a block_dns check. If block_dns is set, call getaddrinfo with AI_NUMERICHOST set and AI_CANONNAME clear. Some paths may not have set AI_CANONNAME, but it's easier to audit this way when the getaddrinfo prelude is uniform across call sites, and the compiler can optimize it away. --- kadmin/kadm_conn.c | 5 +++++ kdc/hprop.c | 5 +++++ lib/kadm5/init_c.c | 5 +++++ lib/kadm5/ipropd_slave.c | 5 +++++ lib/krb5/addr_families.c | 5 +++++ lib/krb5/expand_hostname.c | 3 ++- lib/krb5/get_addrs.c | 8 ++++++++ lib/krb5/get_for_creds.c | 11 ++++++++--- lib/krb5/krbhst.c | 17 +++++++++++++++++ lib/krb5/send_to_kdc.c | 5 +++++ lib/krb5/verify_krb5_conf.c | 5 +++++ 11 files changed, 70 insertions(+), 4 deletions(-) diff --git a/kadmin/kadm_conn.c b/kadmin/kadm_conn.c index 0eeaf508d..37b239f13 100644 --- a/kadmin/kadm_conn.c +++ b/kadmin/kadm_conn.c @@ -246,6 +246,11 @@ start_server(krb5_context contextp, const char *port_str) hints.ai_flags = AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hints.ai_flags &= ~AI_CANONNAME; + hints.ai_flags |= AI_NUMERICHOST|AI_NUMERICSERV; + } e = getaddrinfo(NULL, p->port, &hints, &ai); if(e) { snprintf(portstr, sizeof(portstr), "%u", p->def_port); diff --git a/kdc/hprop.c b/kdc/hprop.c index c1db11b97..d6ff6133a 100644 --- a/kdc/hprop.c +++ b/kdc/hprop.c @@ -61,6 +61,11 @@ open_socket(krb5_context context, const char *hostname, const char *port) hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hints.ai_flags &= ~AI_CANONNAME; + hints.ai_flags |= AI_NUMERICHOST|AI_NUMERICSERV; + } error = getaddrinfo (hostname, port, &hints, &ai); if (error) { warnx ("%s: %s", hostname, gai_strerror(error)); diff --git a/lib/kadm5/init_c.c b/lib/kadm5/init_c.c index ffbb63958..2aa797523 100644 --- a/lib/kadm5/init_c.c +++ b/lib/kadm5/init_c.c @@ -571,6 +571,11 @@ kadm_connect(kadm5_client_context *ctx) if (slash != NULL) hostname = slash + 1; + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hints.ai_flags &= ~AI_CANONNAME; + hints.ai_flags |= AI_NUMERICHOST; + } error = getaddrinfo(hostname, portstr, &hints, &ai); if (error) { ret = KADM5_BAD_SERVER_NAME; diff --git a/lib/kadm5/ipropd_slave.c b/lib/kadm5/ipropd_slave.c index e572bffa7..d72413fd6 100644 --- a/lib/kadm5/ipropd_slave.c +++ b/lib/kadm5/ipropd_slave.c @@ -70,6 +70,11 @@ connect_to_master (krb5_context context, const char *master, port_str = port; } + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hints.ai_flags &= ~AI_CANONNAME; + hints.ai_flags |= AI_NUMERICHOST; + } error = getaddrinfo(master, port_str, &hints, &ai); if (error) { krb5_warnx(context, "Failed to get address of to %s: %s", diff --git a/lib/krb5/addr_families.c b/lib/krb5/addr_families.c index 7d13211a2..1e54ffdf0 100644 --- a/lib/krb5/addr_families.c +++ b/lib/krb5/addr_families.c @@ -1210,6 +1210,11 @@ krb5_parse_address(krb5_context context, /* if not parsed as numeric address, do a name lookup */ memset(&hint, 0, sizeof(hint)); hint.ai_family = AF_UNSPEC; + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hint.ai_flags &= ~AI_CANONNAME; + hint.ai_flags |= AI_NUMERICHOST; + } error = getaddrinfo (string, NULL, &hint, &ai); if (error) { krb5_error_code ret2; diff --git a/lib/krb5/expand_hostname.c b/lib/krb5/expand_hostname.c index 5023d1677..1f1824f76 100644 --- a/lib/krb5/expand_hostname.c +++ b/lib/krb5/expand_hostname.c @@ -68,7 +68,8 @@ krb5_expand_hostname (krb5_context context, struct addrinfo *ai, *a, hints; int error; - if ((context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) == 0) + if ((context->flags & KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME) == 0 || + krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", NULL)) return copy_hostname (context, orig_hostname, new_hostname); memset (&hints, 0, sizeof(hints)); diff --git a/lib/krb5/get_addrs.c b/lib/krb5/get_addrs.c index 824650418..9f14d43c0 100644 --- a/lib/krb5/get_addrs.c +++ b/lib/krb5/get_addrs.c @@ -50,6 +50,14 @@ gethostname_fallback (krb5_context context, krb5_addresses *res) char hostname[MAXHOSTNAMELEN]; struct hostent *hostent; + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + ret = ENXIO; + krb5_set_error_message(context, ret, + "DNS blocked in gethostname fallback"); + return ret; + } + if (gethostname (hostname, sizeof(hostname))) { ret = errno; krb5_set_error_message(context, ret, "gethostname: %s", strerror(ret)); diff --git a/lib/krb5/get_for_creds.c b/lib/krb5/get_for_creds.c index 3a6be1090..eba58bf06 100644 --- a/lib/krb5/get_for_creds.c +++ b/lib/krb5/get_for_creds.c @@ -329,7 +329,7 @@ get_addresses(krb5_context context, krb5_creds *ticket; krb5_const_realm realm; krb5_boolean noaddr; - struct addrinfo *ai; + struct addrinfo *ai, hints; int eai; if (hostname == 0) @@ -349,8 +349,13 @@ get_addresses(krb5_context context, return 0; /* Need addresses, get the address of the remote host. */ - - eai = getaddrinfo (hostname, NULL, NULL, &ai); + memset(&hints, 0, sizeof(hints)); + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hints.ai_flags &= ~AI_CANONNAME; + hints.ai_flags |= AI_NUMERICHOST; + } + eai = getaddrinfo(hostname, NULL, &hints, &ai); if (eai) { ret = krb5_eai_to_heim_errno(eai, errno); krb5_set_error_message(context, ret, diff --git a/lib/krb5/krbhst.c b/lib/krb5/krbhst.c index 99a96d298..91cce2bfa 100644 --- a/lib/krb5/krbhst.c +++ b/lib/krb5/krbhst.c @@ -430,6 +430,11 @@ krb5_krbhst_get_addrinfo(krb5_context context, krb5_krbhst_info *host, snprintf (portstr, sizeof(portstr), "%d", host->port); make_hints(&hints, host->proto); + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hints.ai_flags &= ~AI_CANONNAME; + hints.ai_flags |= AI_NUMERICHOST; + } ret = getaddrinfo(host->hostname, portstr, &hints, &host->ai); if (ret) { ret = krb5_eai_to_heim_errno(ret, errno); @@ -550,6 +555,11 @@ fallback_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, make_hints(&hints, proto); snprintf(portstr, sizeof(portstr), "%d", port); + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hints.ai_flags &= ~AI_CANONNAME; + hints.ai_flags |= AI_NUMERICHOST; + } ret = getaddrinfo(host, portstr, &hints, &ai); if (ret) { /* no more hosts, so we're done here */ @@ -718,6 +728,13 @@ plugin_get_hosts(krb5_context context, { struct plctx ctx = { type, kd, 0 }; + /* + * XXX Need a way to pass this through -- unsure if any of this is + * useful without DNS, though. + */ + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", NULL)) + return; + if (_krb5_homedir_access(context)) ctx.flags |= KRB5_PLF_ALLOW_HOMEDIR; diff --git a/lib/krb5/send_to_kdc.c b/lib/krb5/send_to_kdc.c index 5d8ec4215..a22be88e4 100644 --- a/lib/krb5/send_to_kdc.c +++ b/lib/krb5/send_to_kdc.c @@ -857,6 +857,11 @@ submit_request(krb5_context context, krb5_sendto_ctx ctx, krb5_krbhst_info *hi) nport = init_port(el, htons(80)); snprintf(portstr, sizeof(portstr), "%d", ntohs(nport)); + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hints.ai_flags &= ~AI_CANONNAME; + hints.ai_flags |= AI_NUMERICHOST; + } ret = getaddrinfo(proxy, portstr, &hints, &ai); free(proxy2); if (ret) diff --git a/lib/krb5/verify_krb5_conf.c b/lib/krb5/verify_krb5_conf.c index 609b560ff..f93136550 100644 --- a/lib/krb5/verify_krb5_conf.c +++ b/lib/krb5/verify_krb5_conf.c @@ -202,6 +202,11 @@ check_host(krb5_context context, const char *path, char *data) defport = tmp; snprintf(service, sizeof(service), "%u", defport); } + if (krb5_config_get_bool(context, NULL, "libdefaults", "block_dns", + NULL)) { + hints.ai_flags &= ~AI_CANONNAME; + hints.ai_flags |= AI_NUMERICHOST; + } ret = getaddrinfo(hostname, service, &hints, &ai); if (ret == EAI_SERVICE && !isdigit((unsigned char)service[0])) { snprintf(service, sizeof(service), "%u", defport);