From e511090a4339221dfd1fa597964af7455f96ec28 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Fri, 5 Oct 2007 23:54:12 +0000 Subject: r25543: Merge libreplace support for inet_pton, inet_ntop, getaddrinfo, getnameinfo (and friends) from SAMBA_3_2, with some minor tweaks: - avoid including network headers in replace.h unless absolutely required - autoconf tests for getaddrinfo() in lib/replace The heimdal-specific code also no longer looks for these functions anymore. (This used to be commit b6d3fd84a5d7d814035e60d6fa22f19bed9f77da) --- source4/lib/replace/getaddrinfo.c | 502 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 502 insertions(+) create mode 100644 source4/lib/replace/getaddrinfo.c (limited to 'source4/lib/replace/getaddrinfo.c') diff --git a/source4/lib/replace/getaddrinfo.c b/source4/lib/replace/getaddrinfo.c new file mode 100644 index 0000000000..519c30066b --- /dev/null +++ b/source4/lib/replace/getaddrinfo.c @@ -0,0 +1,502 @@ +/* +PostgreSQL Database Management System +(formerly known as Postgres, then as Postgres95) + +Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group + +Portions Copyright (c) 1994, The Regents of the University of California + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this paragraph +and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, +EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS +TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*/ + +/*------------------------------------------------------------------------- + * + * getaddrinfo.c + * Support getaddrinfo() on platforms that don't have it. + * + * We also supply getnameinfo() here, assuming that the platform will have + * it if and only if it has getaddrinfo(). If this proves false on some + * platform, we'll need to split this file and provide a separate configure + * test for getnameinfo(). + * + * Copyright (c) 2003-2007, PostgreSQL Global Development Group + * + * Copyright (C) 2007 Jeremy Allison. + * Modified to return multiple IPv4 addresses for Samba. + * + *------------------------------------------------------------------------- + */ + +#include "replace.h" +#include "system/network.h" + +#ifndef SMB_MALLOC +#define SMB_MALLOC(s) malloc(s) +#endif + +#ifndef SMB_STRDUP +#define SMB_STRDUP(s) strdup(s) +#endif + +static int check_hostent_err(struct hostent *hp) +{ + if (!hp) { + switch (h_errno) { + case HOST_NOT_FOUND: + case NO_DATA: + return EAI_NONAME; + case TRY_AGAIN: + return EAI_AGAIN; + case NO_RECOVERY: + default: + return EAI_FAIL; + } + } + if (!hp->h_name || hp->h_addrtype != AF_INET) { + return EAI_FAIL; + } + return 0; +} + +static char *canon_name_from_hostent(struct hostent *hp, + int *perr) +{ + char *ret = NULL; + + *perr = check_hostent_err(hp); + if (*perr) { + return NULL; + } + ret = SMB_STRDUP(hp->h_name); + if (!ret) { + *perr = EAI_MEMORY; + } + return ret; +} + +static char *get_my_canon_name(int *perr) +{ + char name[HOST_NAME_MAX+1]; + + if (gethostname(name, HOST_NAME_MAX) == -1) { + *perr = EAI_FAIL; + return NULL; + } + /* Ensure null termination. */ + name[HOST_NAME_MAX] = '\0'; + return canon_name_from_hostent(gethostbyname(name), perr); +} + +static char *get_canon_name_from_addr(struct in_addr ip, + int *perr) +{ + return canon_name_from_hostent( + gethostbyaddr(&ip, sizeof(ip), AF_INET), + perr); +} + +static struct addrinfo *alloc_entry(const struct addrinfo *hints, + struct in_addr ip, + unsigned short port) +{ + struct sockaddr_in *psin = NULL; + struct addrinfo *ai = SMB_MALLOC(sizeof(*ai)); + + if (!ai) { + return NULL; + } + memset(ai, '\0', sizeof(*ai)); + + psin = SMB_MALLOC(sizeof(*psin)); + if (!psin) { + free(ai); + return NULL; + } + + memset(psin, '\0', sizeof(*psin)); + + psin->sin_family = AF_INET; + psin->sin_port = htons(port); + psin->sin_addr = ip; + + ai->ai_flags = 0; + ai->ai_family = AF_INET; + ai->ai_socktype = hints->ai_socktype; + ai->ai_protocol = hints->ai_protocol; + ai->ai_addrlen = sizeof(*psin); + ai->ai_addr = (struct sockaddr *) psin; + ai->ai_canonname = NULL; + ai->ai_next = NULL; + + return ai; +} + +/* + * get address info for a single ipv4 address. + * + * Bugs: - servname can only be a number, not text. + */ + +static int getaddr_info_single_addr(const char *service, + uint32_t addr, + const struct addrinfo *hints, + struct addrinfo **res) +{ + + struct addrinfo *ai = NULL; + struct in_addr ip; + unsigned short port = 0; + + if (service) { + port = (unsigned short)atoi(service); + } + ip.s_addr = htonl(addr); + + ai = alloc_entry(hints, ip, port); + if (!ai) { + return EAI_MEMORY; + } + + /* If we're asked for the canonical name, + * make sure it returns correctly. */ + if (!(hints->ai_flags & AI_NUMERICSERV) && + hints->ai_flags & AI_CANONNAME) { + int err; + if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) { + ai->ai_canonname = get_my_canon_name(&err); + } else { + ai->ai_canonname = + get_canon_name_from_addr(ip,&err); + } + if (ai->ai_canonname == NULL) { + freeaddrinfo(ai); + return err; + } + } + + *res = ai; + return 0; +} + +/* + * get address info for multiple ipv4 addresses. + * + * Bugs: - servname can only be a number, not text. + */ + +static int getaddr_info_name(const char *node, + const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + struct addrinfo *listp = NULL, *prevp = NULL; + char **pptr = NULL; + int err; + struct hostent *hp = NULL; + unsigned short port = 0; + + if (service) { + port = (unsigned short)atoi(service); + } + + hp = gethostbyname(node); + err = check_hostent_err(hp); + if (err) { + return err; + } + + for(pptr = hp->h_addr_list; *pptr; pptr++) { + struct in_addr ip = *(struct in_addr *)pptr; + struct addrinfo *ai = alloc_entry(hints, ip, port); + + if (!ai) { + freeaddrinfo(listp); + return EAI_MEMORY; + } + + if (!listp) { + listp = ai; + prevp = ai; + ai->ai_canonname = SMB_STRDUP(hp->h_name); + if (!ai->ai_canonname) { + freeaddrinfo(listp); + return EAI_MEMORY; + } + } else { + prevp->ai_next = ai; + prevp = ai; + } + } + *res = listp; + return 0; +} + +/* + * get address info for ipv4 sockets. + * + * Bugs: - servname can only be a number, not text. + */ + +int getaddrinfo(const char *node, + const char *service, + const struct addrinfo * hintp, + struct addrinfo ** res) +{ + struct addrinfo hints; + + /* Setup the hints struct. */ + if (hintp == NULL) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + } else { + memcpy(&hints, hintp, sizeof(hints)); + } + + if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) { + return EAI_FAMILY; + } + + if (hints.ai_socktype == 0) { + hints.ai_socktype = SOCK_STREAM; + } + + if (!node && !service) { + return EAI_NONAME; + } + + if (node) { + if (node[0] == '\0') { + return getaddr_info_single_addr(service, + INADDR_ANY, + &hints, + res); + } else if (hints.ai_flags & AI_NUMERICHOST) { + struct in_addr ip; + if (!inet_aton(node, &ip)) { + return EAI_FAIL; + } + return getaddr_info_single_addr(service, + ntohl(ip.s_addr), + &hints, + res); + } else { + return getaddr_info_name(node, + service, + &hints, + res); + } + } else if (hints.ai_flags & AI_PASSIVE) { + return getaddr_info_single_addr(service, + INADDR_ANY, + &hints, + res); + } + return getaddr_info_single_addr(service, + INADDR_LOOPBACK, + &hints, + res); +} + + +void freeaddrinfo(struct addrinfo *res) +{ + struct addrinfo *next = NULL; + + for (;res; res = next) { + next = res->ai_next; + if (res->ai_canonname) { + free(res->ai_canonname); + } + if (res->ai_addr) { + free(res->ai_addr); + } + free(res); + } +} + + +const char *gai_strerror(int errcode) +{ +#ifdef HAVE_HSTRERROR + int hcode; + + switch (errcode) + { + case EAI_NONAME: + hcode = HOST_NOT_FOUND; + break; + case EAI_AGAIN: + hcode = TRY_AGAIN; + break; + case EAI_FAIL: + default: + hcode = NO_RECOVERY; + break; + } + + return hstrerror(hcode); +#else /* !HAVE_HSTRERROR */ + + switch (errcode) + { + case EAI_NONAME: + return "Unknown host"; + case EAI_AGAIN: + return "Host name lookup failure"; +#ifdef EAI_BADFLAGS + case EAI_BADFLAGS: + return "Invalid argument"; +#endif +#ifdef EAI_FAMILY + case EAI_FAMILY: + return "Address family not supported"; +#endif +#ifdef EAI_MEMORY + case EAI_MEMORY: + return "Not enough memory"; +#endif +#ifdef EAI_NODATA + case EAI_NODATA: + return "No host data of that type was found"; +#endif +#ifdef EAI_SERVICE + case EAI_SERVICE: + return "Class type not found"; +#endif +#ifdef EAI_SOCKTYPE + case EAI_SOCKTYPE: + return "Socket type not supported"; +#endif + default: + return "Unknown server error"; + } +#endif /* HAVE_HSTRERROR */ +} + +static int gethostnameinfo(const struct sockaddr *sa, + char *node, + size_t nodelen, + int flags) +{ + int ret = -1; + char *p = NULL; + + if (!(flags & NI_NUMERICHOST)) { + struct hostent *hp = gethostbyaddr( + &((struct sockaddr_in *)sa)->sin_addr, + sizeof(struct in_addr), + sa->sa_family); + ret = check_hostent_err(hp); + if (ret == 0) { + /* Name looked up successfully. */ + ret = snprintf(node, nodelen, "%s", hp->h_name); + if (ret == -1 || ret > nodelen) { + return EAI_MEMORY; + } + if (flags & NI_NOFQDN) { + p = strchr(node,'.'); + if (p) { + *p = '\0'; + } + } + return 0; + } + + if (flags & NI_NAMEREQD) { + /* If we require a name and didn't get one, + * automatically fail. */ + return ret; + } + /* Otherwise just fall into the numeric host code... */ + } + p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr); + ret = snprintf(node, nodelen, "%s", p); + if (ret == -1 || ret > nodelen) { + return EAI_MEMORY; + } + return 0; +} + +static int getservicenameinfo(const struct sockaddr *sa, + char *service, + size_t servicelen, + int flags) +{ + int ret = -1; + int port = ntohs(((struct sockaddr_in *)sa)->sin_port); + + if (!(flags & NI_NUMERICSERV)) { + struct servent *se = getservbyport( + port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + if (se && se->s_name) { + /* Service name looked up successfully. */ + ret = snprintf(service, servicelen, "%s", se->s_name); + if (ret == -1 || ret > servicelen) { + return EAI_MEMORY; + } + return 0; + } + /* Otherwise just fall into the numeric service code... */ + } + ret = snprintf(service, servicelen, "%d", port); + if (ret == -1 || ret > servicelen) { + return EAI_MEMORY; + } + return 0; +} + +/* + * Convert an ipv4 address to a hostname. + * + * Bugs: - No IPv6 support. + */ +int getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *node, size_t nodelen, + char *service, size_t servicelen, int flags) +{ + + /* Invalid arguments. */ + if (sa == NULL || (node == NULL && service == NULL)) { + return EAI_FAIL; + } + + if (sa->sa_family != AF_INET) { + return EAI_FAIL; + } + + if (salen < sizeof(struct sockaddr_in)) { + return EAI_FAIL; + } + + /* We don't support those. */ + if ((node && !(flags & NI_NUMERICHOST)) + || (service && !(flags & NI_NUMERICSERV))) + return EAI_FAIL; + + if (node) { + return gethostnameinfo(sa, node, nodelen, flags); + } + + if (service) { + return getservicenameinfo(sa, service, servicelen, flags); + } + return 0; +} -- cgit From 88f6c5a1d2c337ffe7505e20b96a6b47dab1c063 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 25 Oct 2007 06:53:38 +0200 Subject: r25724: - include getaddrinfo.h after we have defined struct addrinfo - use rep_ instead of pg_ as prefix in getaddrinfo.[ch] - define HAVE_ macros when we replace functions metze (This used to be commit 57d5cf4b5fe8885b1375059aa143c9c71d2503b4) --- source4/lib/replace/getaddrinfo.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source4/lib/replace/getaddrinfo.c') diff --git a/source4/lib/replace/getaddrinfo.c b/source4/lib/replace/getaddrinfo.c index 519c30066b..3cc1214b0e 100644 --- a/source4/lib/replace/getaddrinfo.c +++ b/source4/lib/replace/getaddrinfo.c @@ -253,7 +253,7 @@ static int getaddr_info_name(const char *node, * Bugs: - servname can only be a number, not text. */ -int getaddrinfo(const char *node, +int rep_getaddrinfo(const char *node, const char *service, const struct addrinfo * hintp, struct addrinfo ** res) @@ -315,7 +315,7 @@ int getaddrinfo(const char *node, } -void freeaddrinfo(struct addrinfo *res) +void rep_freeaddrinfo(struct addrinfo *res) { struct addrinfo *next = NULL; @@ -332,7 +332,7 @@ void freeaddrinfo(struct addrinfo *res) } -const char *gai_strerror(int errcode) +const char *rep_gai_strerror(int errcode) { #ifdef HAVE_HSTRERROR int hcode; @@ -468,7 +468,7 @@ static int getservicenameinfo(const struct sockaddr *sa, * * Bugs: - No IPv6 support. */ -int getnameinfo(const struct sockaddr *sa, socklen_t salen, +int rep_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *node, size_t nodelen, char *service, size_t servicelen, int flags) { -- cgit From 79affaf37a29d6c9c30cc7674cfad97e67bc1867 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 25 Oct 2007 06:56:27 +0200 Subject: r25725: merge commit bc9008aa1dcb66890795f0ff2d3046da7df867d9 from v3-2-test: Author: Jeremy Allison AuthorDate: Wed Oct 24 14:40:24 2007 -0700 We do support name lookups for host and service in our replacement code - remove the restrictions from the original Postgres code. Jeremy. (This used to be commit 25a892f2ad1b281869779686ca23f2ed29b46a5c) --- source4/lib/replace/getaddrinfo.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'source4/lib/replace/getaddrinfo.c') diff --git a/source4/lib/replace/getaddrinfo.c b/source4/lib/replace/getaddrinfo.c index 3cc1214b0e..063bacd026 100644 --- a/source4/lib/replace/getaddrinfo.c +++ b/source4/lib/replace/getaddrinfo.c @@ -486,11 +486,6 @@ int rep_getnameinfo(const struct sockaddr *sa, socklen_t salen, return EAI_FAIL; } - /* We don't support those. */ - if ((node && !(flags & NI_NUMERICHOST)) - || (service && !(flags & NI_NUMERICSERV))) - return EAI_FAIL; - if (node) { return gethostnameinfo(sa, node, nodelen, flags); } -- cgit From a4a7447f130d144317e9b7d110ea20f046cd708f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 9 Nov 2007 08:22:21 +0100 Subject: r25909: Fix the snprintf checks, and fix a typo in pointer indirection. These fixes are needed for a working getaddrinfo etc. replacement. Fixes from Wayne Davison from rsync. Jeremy. from v3-2-test commit 494bf6293bedbda4b10aa2eae452377b8130cd01 (This used to be commit e562832ad19e8c3a0380759a22b0267e365ecc2e) --- source4/lib/replace/getaddrinfo.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'source4/lib/replace/getaddrinfo.c') diff --git a/source4/lib/replace/getaddrinfo.c b/source4/lib/replace/getaddrinfo.c index 063bacd026..c5cd52be93 100644 --- a/source4/lib/replace/getaddrinfo.c +++ b/source4/lib/replace/getaddrinfo.c @@ -222,7 +222,7 @@ static int getaddr_info_name(const char *node, } for(pptr = hp->h_addr_list; *pptr; pptr++) { - struct in_addr ip = *(struct in_addr *)pptr; + struct in_addr ip = *(struct in_addr *)*pptr; struct addrinfo *ai = alloc_entry(hints, ip, port); if (!ai) { @@ -407,7 +407,7 @@ static int gethostnameinfo(const struct sockaddr *sa, if (ret == 0) { /* Name looked up successfully. */ ret = snprintf(node, nodelen, "%s", hp->h_name); - if (ret == -1 || ret > nodelen) { + if (ret < 0 || (size_t)ret >= nodelen) { return EAI_MEMORY; } if (flags & NI_NOFQDN) { @@ -428,7 +428,7 @@ static int gethostnameinfo(const struct sockaddr *sa, } p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr); ret = snprintf(node, nodelen, "%s", p); - if (ret == -1 || ret > nodelen) { + if (ret < 0 || (size_t)ret >= nodelen) { return EAI_MEMORY; } return 0; @@ -449,7 +449,7 @@ static int getservicenameinfo(const struct sockaddr *sa, if (se && se->s_name) { /* Service name looked up successfully. */ ret = snprintf(service, servicelen, "%s", se->s_name); - if (ret == -1 || ret > servicelen) { + if (ret < 0 || (size_t)ret >= servicelen) { return EAI_MEMORY; } return 0; @@ -457,7 +457,7 @@ static int getservicenameinfo(const struct sockaddr *sa, /* Otherwise just fall into the numeric service code... */ } ret = snprintf(service, servicelen, "%d", port); - if (ret == -1 || ret > servicelen) { + if (ret < 0 || (size_t)ret >= servicelen) { return EAI_MEMORY; } return 0; -- cgit