From 4a56b697b6adcf095e25895c4a9ba3192ed34124 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 15 Oct 2007 16:11:48 -0700 Subject: [PATCH] Move to protocol independent code in most of lib/util_sock.c We don't use gethostbyname any more except in one case where we're looking for host aliases (I don't know how to do that with getaddrinfo yet). New function should be getaddrinfo(). Next step will be fixing lib/access.c, and then changing libsmb/namequery.c to cope with IPv6 address returns. Jeremy. --- source/lib/interface.c | 6 +- source/lib/system.c | 43 ---- source/lib/util.c | 103 +++----- source/lib/util_sock.c | 337 ++++++++++++++++--------- source/libsmb/namequery.c | 60 ++++- source/nsswitch/winbind_krb5_locator.c | 3 +- 6 files changed, 313 insertions(+), 239 deletions(-) diff --git a/source/lib/interface.c b/source/lib/interface.c index ded70683e0d..d2aa69a2893 100644 --- a/source/lib/interface.c +++ b/source/lib/interface.c @@ -461,7 +461,7 @@ static void interpret_interface(char *token) /* maybe it is a DNS name */ p = strchr_m(token,'/'); if (p == NULL) { - if (!interpret_string_addr(&ss, token)) { + if (!interpret_string_addr(&ss, token, 0)) { DEBUG(2, ("interpret_interface: Can't find address " "for %s\n", token)); return; @@ -481,7 +481,7 @@ static void interpret_interface(char *token) /* parse it into an IP address/netmasklength pair */ *p = 0; - goodaddr = interpret_string_addr(&ss, token); + goodaddr = interpret_string_addr(&ss, token, 0); *p++ = '/'; if (!goodaddr) { @@ -492,7 +492,7 @@ static void interpret_interface(char *token) } if (strlen(p) > 2) { - goodaddr = interpret_string_addr(&ss_mask, p); + goodaddr = interpret_string_addr(&ss_mask, p, 0); if (!goodaddr) { DEBUG(2,("interpret_interface: " "can't determine netmask from %s\n", diff --git a/source/lib/system.c b/source/lib/system.c index bc7de847675..bf35722ea59 100644 --- a/source/lib/system.c +++ b/source/lib/system.c @@ -682,49 +682,6 @@ int sys_chroot(const char *dname) #endif } -/************************************************************************** -A wrapper for gethostbyname() that tries avoids looking up hostnames -in the root domain, which can cause dial-on-demand links to come up for no -apparent reason. -****************************************************************************/ - -struct hostent *sys_gethostbyname(const char *name) -{ -#ifdef REDUCE_ROOT_DNS_LOOKUPS - char query[HOST_NAME_MAX], hostname[HOST_NAME_MAX]; - char *domain; - - /* Does this name have any dots in it? If so, make no change */ - - if (strchr_m(name, '.')) - return(gethostbyname(name)); - - /* Get my hostname, which should have domain name - attached. If not, just do the gethostname on the - original string. - */ - - gethostname(hostname, sizeof(hostname) - 1); - hostname[sizeof(hostname) - 1] = 0; - if ((domain = strchr_m(hostname, '.')) == NULL) - return(gethostbyname(name)); - - /* Attach domain name to query and do modified query. - If names too large, just do gethostname on the - original string. - */ - - if((strlen(name) + strlen(domain)) >= sizeof(query)) - return(gethostbyname(name)); - - slprintf(query, sizeof(query)-1, "%s%s", name, domain); - return(gethostbyname(query)); -#else /* REDUCE_ROOT_DNS_LOOKUPS */ - return(gethostbyname(name)); -#endif /* REDUCE_ROOT_DNS_LOOKUPS */ -} - - #if defined(HAVE_POSIX_CAPABILITIES) #ifdef HAVE_SYS_CAPABILITY_H diff --git a/source/lib/util.c b/source/lib/util.c index f457e53c47f..b25190b2f77 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -1208,37 +1208,6 @@ BOOL get_myname(char *my_name) return(True); } -/**************************************************************************** - Get my own canonical name, including domain. -****************************************************************************/ - -BOOL get_mydnsfullname(fstring my_dnsname) -{ - static fstring dnshostname; - struct hostent *hp; - - if (!*dnshostname) { - /* get my host name */ - if (gethostname(dnshostname, sizeof(dnshostname)) == -1) { - *dnshostname = '\0'; - DEBUG(0,("gethostname failed\n")); - return False; - } - - /* Ensure null termination. */ - dnshostname[sizeof(dnshostname)-1] = '\0'; - - /* Ensure we get the cannonical name. */ - if (!(hp = sys_gethostbyname(dnshostname))) { - *dnshostname = '\0'; - return False; - } - fstrcpy(dnshostname, hp->h_name); - } - fstrcpy(my_dnsname, dnshostname); - return True; -} - /**************************************************************************** Get my own domain name. ****************************************************************************/ @@ -2742,48 +2711,48 @@ BOOL unix_wild_match(const char *pattern, const char *string) /********************************************************************** Converts a name to a fully qualified domain name. - Returns True if lookup succeeded, False if not (then fqdn is set to name) + Returns true if lookup succeeded, false if not (then fqdn is set to name) + Note we deliberately use gethostbyname here, not getaddrinfo as we want + to examine the h_aliases and I don't know how to do that with getaddrinfo. ***********************************************************************/ - -BOOL name_to_fqdn(fstring fqdn, const char *name) + +bool name_to_fqdn(fstring fqdn, const char *name) { - struct hostent *hp = sys_gethostbyname(name); + char *full = NULL; + struct hostent *hp = gethostbyname(name); - if ( hp && hp->h_name && *hp->h_name ) { - char *full = NULL; - - /* find out if the fqdn is returned as an alias - * to cope with /etc/hosts files where the first - * name is not the fqdn but the short name */ - if (hp->h_aliases && (! strchr_m(hp->h_name, '.'))) { - int i; - for (i = 0; hp->h_aliases[i]; i++) { - if (strchr_m(hp->h_aliases[i], '.')) { - full = hp->h_aliases[i]; - break; - } - } - } - if (full && (StrCaseCmp(full, "localhost.localdomain") == 0)) { - DEBUG(1, ("WARNING: your /etc/hosts file may be broken!\n")); - DEBUGADD(1, (" Specifing the machine hostname for address 127.0.0.1 may lead\n")); - DEBUGADD(1, (" to Kerberos authentication problems as localhost.localdomain\n")); - DEBUGADD(1, (" may end up being used instead of the real machine FQDN.\n")); - full = hp->h_name; - } - - if (!full) { - full = hp->h_name; - } - - DEBUG(10,("name_to_fqdn: lookup for %s -> %s.\n", name, full)); - fstrcpy(fqdn, full); - return True; - } else { + if (!hp || !hp->h_name || !*hp->h_name) { DEBUG(10,("name_to_fqdn: lookup for %s failed.\n", name)); fstrcpy(fqdn, name); - return False; + return false; } + + /* Find out if the fqdn is returned as an alias + * to cope with /etc/hosts files where the first + * name is not the fqdn but the short name */ + if (hp->h_aliases && (! strchr_m(hp->h_name, '.'))) { + int i; + for (i = 0; hp->h_aliases[i]; i++) { + if (strchr_m(hp->h_aliases[i], '.')) { + full = hp->h_aliases[i]; + break; + } + } + } + if (full && (StrCaseCmp(full, "localhost.localdomain") == 0)) { + DEBUG(1, ("WARNING: your /etc/hosts file may be broken!\n")); + DEBUGADD(1, (" Specifing the machine hostname for address 127.0.0.1 may lead\n")); + DEBUGADD(1, (" to Kerberos authentication problems as localhost.localdomain\n")); + DEBUGADD(1, (" may end up being used instead of the real machine FQDN.\n")); + full = hp->h_name; + } + if (!full) { + full = hp->h_name; + } + + DEBUG(10,("name_to_fqdn: lookup for %s -> %s.\n", name, full)); + fstrcpy(fqdn, full); + return true; } /********************************************************************** diff --git a/source/lib/util_sock.c b/source/lib/util_sock.c index 80799326208..eb3b35339c1 100644 --- a/source/lib/util_sock.c +++ b/source/lib/util_sock.c @@ -29,63 +29,133 @@ static int client_fd = -1; static char client_ip_string[INET6_ADDRSTRLEN]; /**************************************************************************** - Return true if a string could be a pure IPv4 address. + Return true if a string could be an IPv4 address. ****************************************************************************/ bool is_ipaddress_v4(const char *str) { - bool pure_address = true; - int i; + int ret = -1; + struct in_addr dest; - for (i=0; pure_address && str[i]; i++) { - if (!(isdigit((int)str[i]) || str[i] == '.')) { - pure_address = false; - } + ret = inet_pton(AF_INET, str, &dest); + if (ret > 0) { + return true; } + return false; +} - /* Check that a pure number is not misinterpreted as an IP */ - pure_address = pure_address && (strchr_m(str, '.') != NULL); - return pure_address; +/**************************************************************************** + Return true if a string could be an IPv4 or IPv6 address. +****************************************************************************/ + +bool is_ipaddress(const char *str) +{ + int ret = -1; + +#if defined(AF_INET6) + struct in6_addr dest6; + + ret = inet_pton(AF_INET6, str, &dest6); + if (ret > 0) { + return true; + } +#endif + return is_ipaddress_v4(str); +} + +/******************************************************************* + Wrap getaddrinfo... +******************************************************************/ + +static bool interpret_string_addr_internal(struct addrinfo **ppres, + const char *str, int flags) +{ + int ret; + struct addrinfo hints; + + memset(&hints, '\0', sizeof(hints)); + /* By default make sure it supports TCP. */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = flags; + + ret = getaddrinfo(str, NULL, + &hints, + ppres); + if (ret) { + DEBUG(3,("interpret_string_addr_interal: getaddrinfo failed " + "for name %s [%s]\n", + str, + gai_strerror(ret) )); + return false; + } + return true; } /**************************************************************************** Interpret an internet address or name into an IP address in 4 byte form. + RETURNS IN NETWORK BYTE ORDER (big endian). ****************************************************************************/ uint32 interpret_addr(const char *str) { - struct hostent *hp; - uint32 res; + uint32 ret; - if (strcmp(str,"0.0.0.0") == 0) - return(0); - if (strcmp(str,"255.255.255.255") == 0) - return(0xFFFFFFFF); - - /* if it's in the form of an IP address then + /* If it's in the form of an IP address then * get the lib to interpret it */ if (is_ipaddress_v4(str)) { - res = inet_addr(str); + struct in_addr dest; + + if (inet_pton(AF_INET, str, &dest) <= 0) { + /* Error - this shouldn't happen ! */ + DEBUG(0,("interpret_addr: inet_pton failed " + "host %s\n", + str)); + return 0; + } + ret = dest.s_addr; /* NETWORK BYTE ORDER ! */ } else { - /* otherwise assume it's a network name of some sort and use - sys_gethostbyname */ - if ((hp = sys_gethostbyname(str)) == 0) { - DEBUG(3,("sys_gethostbyname: Unknown host. %s\n",str)); + /* Otherwise assume it's a network name of some sort and use + getadddrinfo. */ + struct addrinfo *res = NULL; + struct addrinfo *res_list = NULL; + if (!interpret_string_addr_internal(&res_list, + str, + AI_ADDRCONFIG)) { + DEBUG(3,("interpret_addr: Unknown host. %s\n",str)); return 0; } - if(hp->h_addr == NULL) { - DEBUG(3,("sys_gethostbyname: host address is " + /* Find the first IPv4 address. */ + for (res = res_list; res; res = res->ai_next) { + if (res->ai_family != AF_INET) { + continue; + } + if (res->ai_addr == NULL) { + continue; + } + break; + } + if(res == NULL) { + DEBUG(3,("interpret_addr: host address is " "invalid for host %s\n",str)); + if (res_list) { + freeaddrinfo(res_list); + } return 0; } - putip((char *)&res,(char *)hp->h_addr); + putip((char *)&ret, + &((struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr); + if (res_list) { + freeaddrinfo(res_list); + } } - if (res == (uint32)-1) - return(0); + /* This is so bogus - all callers need fixing... JRA. */ + if (ret == (uint32)-1) { + return 0; + } - return(res); + return ret; } /******************************************************************* @@ -105,31 +175,20 @@ struct in_addr *interpret_addr2(const char *str) struct sockaddr_storage. ******************************************************************/ -bool interpret_string_addr(struct sockaddr_storage *pss, const char *str) +bool interpret_string_addr(struct sockaddr_storage *pss, + const char *str, + int flags) { - int ret; struct addrinfo *res = NULL; - struct addrinfo hints; memset(pss,'\0', sizeof(*pss)); - memset(&hints, '\0', sizeof(hints)); - /* By default make sure it supports TCP. */ - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_ADDRCONFIG; - - ret = getaddrinfo(str, NULL, - &hints, - &res); - - if (ret) { - DEBUG(3,("interpret_string_addr: getaddrinfo failed for " - "name %s [%s]\n", - str, - gai_strerror(ret) )); + if (!interpret_string_addr_internal(&res, str, flags|AI_ADDRCONFIG)) { + return false; + } + if (!res) { return false; } - /* Copy the first sockaddr. */ memcpy(pss, res->ai_addr, res->ai_addrlen); freeaddrinfo(res); @@ -155,7 +214,8 @@ bool is_loopback_addr(const struct sockaddr_storage *pss) { #if defined(AF_INET6) if (pss->ss_family == AF_INET) { - struct in6_addr *pin6 = &((struct sockaddr_in6 *)pss)->sin6_addr; + struct in6_addr *pin6 = + &((struct sockaddr_in6 *)pss)->sin6_addr; return IN6_IS_ADDR_LOOPBACK(pin6); } #endif @@ -185,7 +245,8 @@ bool is_zero_addr(const struct sockaddr_storage *pss) { #if defined(AF_INET6) if (pss->ss_family == AF_INET) { - struct in6_addr *pin6 = &((struct sockaddr_in6 *)pss)->sin6_addr; + struct in6_addr *pin6 = + &((struct sockaddr_in6 *)pss)->sin6_addr; return IN6_IS_ADDR_UNSPECIFIED(pin6); } #endif @@ -1215,7 +1276,7 @@ bool send_smb(int fd, char *buffer) int open_socket_in(int type, int port, int dlevel, - uint32 socket_addr, + uint32 socket_addr, /* NETWORK BYTE ORDER */ bool rebind ) { struct sockaddr_in sock; @@ -1595,22 +1656,14 @@ static bool matchname(const char *remotehost, const struct sockaddr_storage *pss, socklen_t len) { - struct addrinfo hints; struct addrinfo *res = NULL; struct addrinfo *ailist = NULL; char addr_buf[INET6_ADDRSTRLEN]; - int ret = -1; + bool ret = interpret_string_addr_internal(&ailist, + remotehost, + AI_ADDRCONFIG|AI_CANONNAME); - memset(&hints,'\0',sizeof(struct addrinfo)); - /* By default make sure it supports TCP. */ - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_ADDRCONFIG|AI_CANONNAME; - - ret = getaddrinfo(remotehost, NULL, - &hints, - &res); - - if (ret || res == NULL) { + if (!ret || ailist == NULL) { DEBUG(3,("matchname: getaddrinfo failed for " "name %s [%s]\n", remotehost, @@ -1622,24 +1675,25 @@ static bool matchname(const char *remotehost, * Make sure that getaddrinfo() returns the "correct" host name. */ - if (res->ai_canonname == NULL || - (!strequal(remotehost, res->ai_canonname) && + if (ailist->ai_canonname == NULL || + (!strequal(remotehost, ailist->ai_canonname) && !strequal(remotehost, "localhost"))) { DEBUG(0,("matchname: host name/name mismatch: %s != %s\n", remotehost, - res->ai_canonname ? res->ai_canonname : "(NULL)")); - freeaddrinfo(res); + ailist->ai_canonname ? + ailist->ai_canonname : "(NULL)")); + freeaddrinfo(ailist); return false; } /* Look up the host address in the address list we just got. */ - for (ailist = res; ailist; ailist = ailist->ai_next) { - if (!ailist->ai_addr) { + for (res = ailist; res; res = res->ai_next) { + if (!res->ai_addr) { continue; } - if (addr_equal((const struct sockaddr_storage *)ailist->ai_addr, + if (addr_equal((const struct sockaddr_storage *)res->ai_addr, pss)) { - freeaddrinfo(res); + freeaddrinfo(ailist); return true; } } @@ -1655,9 +1709,11 @@ static bool matchname(const char *remotehost, sizeof(addr_buf), pss, len), - res->ai_canonname ? res->ai_canonname : "(NULL)")); + ailist->ai_canonname ? ailist->ai_canonname : "(NULL)")); - freeaddrinfo(res); + if (ailist) { + freeaddrinfo(ailist); + } return false; } @@ -1837,8 +1893,62 @@ out_umask: #endif /* HAVE_UNIXSOCKET */ } +/**************************************************************************** + Get my own canonical name, including domain. +****************************************************************************/ + +bool get_mydnsfullname(fstring my_dnsname) +{ + static fstring dnshostname; + + if (!*dnshostname) { + struct addrinfo *res = NULL; + bool ret; + + /* get my host name */ + if (gethostname(dnshostname, sizeof(dnshostname)) == -1) { + *dnshostname = '\0'; + DEBUG(0,("get_mydnsfullname: gethostname failed\n")); + return false; + } + + /* Ensure null termination. */ + dnshostname[sizeof(dnshostname)-1] = '\0'; + + ret = interpret_string_addr_internal(&res, + dnshostname, + AI_ADDRCONFIG|AI_CANONNAME); + + if (!ret || res == NULL) { + DEBUG(3,("get_mydnsfullname: getaddrinfo failed for " + "name %s [%s]\n", + dnshostname, + gai_strerror(ret) )); + return false; + } + + /* + * Make sure that getaddrinfo() returns the "correct" host name. + */ + + if (res->ai_canonname == NULL) { + DEBUG(3,("get_mydnsfullname: failed to get " + "canonical name for %s\n", + dnshostname)); + freeaddrinfo(res); + return false; + } + + + fstrcpy(dnshostname, res->ai_canonname); + freeaddrinfo(res); + } + fstrcpy(my_dnsname, dnshostname); + return true; +} + /************************************************************ - Is this my name ? Needs fixing for IPv6. + Is this my name ? ************************************************************/ bool is_myname_or_ipaddr(const char *s) @@ -1846,83 +1956,82 @@ bool is_myname_or_ipaddr(const char *s) fstring name, dnsname; char *servername; - if ( !s ) { + if (!s) { return false; } - /* santize the string from '\\name' */ + /* Santize the string from '\\name' */ + fstrcpy(name, s); - fstrcpy( name, s ); - - servername = strrchr_m( name, '\\' ); - if ( !servername ) + servername = strrchr_m(name, '\\' ); + if (!servername) { servername = name; - else + } else { servername++; + } - /* optimize for the common case */ - - if (strequal(servername, global_myname())) + /* Optimize for the common case */ + if (strequal(servername, global_myname())) { return true; + } - /* check for an alias */ - - if (is_myname(servername)) + /* Check for an alias */ + if (is_myname(servername)) { return true; + } - /* check for loopback */ - - if (strequal(servername, "127.0.0.1")) + /* Check for loopback */ + if (strequal(servername, "127.0.0.1") || + strequal(servername, "::1")) { return true; + } - if (strequal(servername, "localhost")) + if (strequal(servername, "localhost")) { return true; + } - /* maybe it's my dns name */ - - if ( get_mydnsfullname( dnsname ) ) - if ( strequal( servername, dnsname ) ) + /* Maybe it's my dns name */ + if (get_mydnsfullname(dnsname)) { + if (strequal(servername, dnsname)) { return true; + } + } - /* handle possible CNAME records */ - - if ( !is_ipaddress_v4( servername ) ) { - /* use DNS to resolve the name, but only the first address */ - struct hostent *hp; - - if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) { - struct in_addr return_ip; - putip( (char*)&return_ip, (char*)hp->h_addr ); - fstrcpy( name, inet_ntoa( return_ip ) ); + /* Handle possible CNAME records - convert to an IP addr. */ + if (!is_ipaddress(servername)) { + /* Use DNS to resolve the name, but only the first address */ + struct sockaddr_storage ss; + if (interpret_string_addr(&ss, servername,0)) { + print_sockaddr(name, + sizeof(name), + &ss, + sizeof(ss)); servername = name; } } - /* maybe its an IP address? */ - if (is_ipaddress_v4(servername)) { + /* Maybe its an IP address? */ + if (is_ipaddress(servername)) { struct sockaddr_storage ss; struct iface_struct nics[MAX_INTERFACES]; int i, n; - struct in_addr ip; - ip = *interpret_addr2(servername); - if (is_zero_ip_v4(ip) || is_loopback_ip_v4(ip)) { + if (!interpret_string_addr(&ss, servername, AI_NUMERICHOST)) { return false; } - in_addr_to_sockaddr_storage(&ss, ip); + if (is_zero_addr(&ss) || is_loopback_addr(&ss)) { + return false; + } n = get_interfaces(nics, MAX_INTERFACES); for (i=0; i\n", name_type)); return NT_STATUS_INVALID_PARAMETER; @@ -1039,18 +1043,54 @@ static NTSTATUS resolve_hosts(const char *name, int name_type, *return_count = 0; DEBUG(3,("resolve_hosts: Attempting host lookup for name %s<0x%x>\n", name, name_type)); - - if (((hp = sys_gethostbyname(name)) != NULL) && (hp->h_addr != NULL)) { + + ZERO_STRUCT(hints); + /* By default make sure it supports TCP. */ + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_ADDRCONFIG; + + ret = getaddrinfo(name, + NULL, + &hints, + &ailist); + if (ret) { + DEBUG(3,("resolve_hosts: getaddrinfo failed for name %s [%s]\n", + name, + gai_strerror(ret) )); + } + + for (res = ailist; res; res = res->ai_next) { struct in_addr return_ip; - putip((char *)&return_ip,(char *)hp->h_addr); - *return_iplist = SMB_MALLOC_P(struct ip_service); - if(*return_iplist == NULL) { + + /* IPv4 only for now until I convert ip_service */ + if (res->ai_family != AF_INET) { + continue; + } + if (!res->ai_addr) { + continue; + } + + putip((char *)&return_ip, + &((struct sockaddr_in *)res->ai_addr)->sin_addr); + + *return_count += 1; + i++; + + *return_iplist = SMB_REALLOC_ARRAY(*return_iplist, + struct ip_service, + *return_count); + if (!*return_iplist) { DEBUG(3,("resolve_hosts: malloc fail !\n")); + freeaddrinfo(ailist); return NT_STATUS_NO_MEMORY; } - (*return_iplist)->ip = return_ip; - (*return_iplist)->port = PORT_NONE; - *return_count = 1; + (*return_iplist)[i].ip = return_ip; + (*return_iplist)[i].port = PORT_NONE; + } + if (ailist) { + freeaddrinfo(ailist); + } + if (*return_count) { return NT_STATUS_OK; } return NT_STATUS_UNSUCCESSFUL; diff --git a/source/nsswitch/winbind_krb5_locator.c b/source/nsswitch/winbind_krb5_locator.c index 18a9fe3429f..dc2664b67c2 100644 --- a/source/nsswitch/winbind_krb5_locator.c +++ b/source/nsswitch/winbind_krb5_locator.c @@ -171,7 +171,7 @@ static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name, int (*cbfunc)(void *, int, struct sockaddr *), void *cbdata) { - struct addrinfo *out; + struct addrinfo *out = NULL; int ret; int count = 3; @@ -206,7 +206,6 @@ static krb5_error_code smb_krb5_locator_call_cbfunc(const char *name, #endif freeaddrinfo(out); - return ret; }