From 76ebf6c489825a572a436f9e3e051aafe78a0a61 Mon Sep 17 00:00:00 2001 From: William Pitcock Date: Sun, 20 Mar 2016 01:16:41 -0500 Subject: [PATCH] authd: initial pass at win32 porting --- authd/Makefile.am | 2 +- authd/getaddrinfo.c | 617 ++++++++++++++++++++++++++++++++++++++++++++ authd/getaddrinfo.h | 130 ++++++++++ authd/getnameinfo.c | 242 +++++++++++++++++ authd/getnameinfo.h | 41 +++ authd/reslib.c | 12 + authd/reslist.c | 276 ++++++++++++++++++++ include/stdinc.h | 2 - 8 files changed, 1319 insertions(+), 3 deletions(-) create mode 100644 authd/getaddrinfo.c create mode 100644 authd/getaddrinfo.h create mode 100644 authd/getnameinfo.c create mode 100644 authd/getnameinfo.h create mode 100644 authd/reslist.c diff --git a/authd/Makefile.am b/authd/Makefile.am index e1b705e14..1b8ebf710 100644 --- a/authd/Makefile.am +++ b/authd/Makefile.am @@ -3,5 +3,5 @@ AM_CFLAGS=$(WARNFLAGS) AM_CPPFLAGS = -I../include -I../librb/include -authd_SOURCES = authd.c res.c reslib.c dns.c +authd_SOURCES = authd.c res.c reslib.c reslist.c getnameinfo.c getaddrinfo.c dns.c authd_LDADD = ../librb/src/librb.la diff --git a/authd/getaddrinfo.c b/authd/getaddrinfo.c new file mode 100644 index 000000000..482e648bd --- /dev/null +++ b/authd/getaddrinfo.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef _WIN32 +#include +#include "getaddrinfo.h" + +/* $Id$ */ + +static const char in_addrany[] = { 0, 0, 0, 0 }; +static const char in_loopback[] = { 127, 0, 0, 1 }; +static const char in6_addrany[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; +static const char in6_loopback[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 +}; + +static const struct afd { + int a_af; + int a_addrlen; + int a_socklen; + int a_off; + const char *a_addrany; + const char *a_loopback; + int a_scoped; +} afdl [] = { +#define N_INET6 0 +#ifdef IPV6 + {PF_INET6, sizeof(struct in6_addr), + sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr), + in6_addrany, in6_loopback, 1}, +#endif +#define N_INET 1 + {PF_INET, sizeof(struct in_addr), + sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr), + in_addrany, in_loopback, 0}, + {0, 0, 0, 0, NULL, NULL, 0}, +}; + +struct explore { + int e_af; + int e_socktype; + int e_protocol; + const char *e_protostr; + int e_wild; +#define WILD_AF(ex) ((ex)->e_wild & 0x01) +#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02) +#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04) +}; + +static const struct explore explore[] = { +#ifdef IPV6 + { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 }, +#endif + { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_INET, SOCK_RAW, ANY, NULL, 0x05 }, + { PF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 }, + { PF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 }, + { PF_UNSPEC, SOCK_RAW, ANY, NULL, 0x05 }, + { -1, 0, 0, NULL, 0 }, +}; + +#define PTON_MAX 16 + +static int str_isnumber(const char *); +static int explore_null(const struct rb_addrinfo *, + const char *, struct rb_addrinfo **); +static int explore_numeric(const struct rb_addrinfo *, const char *, + const char *, struct rb_addrinfo **); +static struct rb_addrinfo *get_ai(const struct rb_addrinfo *, + const struct afd *, const char *); +static int get_portmatch(const struct rb_addrinfo *, const char *); +static int get_port(struct rb_addrinfo *, const char *, int); +static const struct afd *find_afd(int); +#if 0 +/* We will need this should we ever want gai_strerror() */ +static char *ai_errlist[] = { + "Success", + "Address family for hostname not supported", /* EAI_ADDRFAMILY */ + "Temporary failure in name resolution", /* EAI_AGAIN */ + "Invalid value for ai_flags", /* EAI_BADFLAGS */ + "Non-recoverable failure in name resolution", /* EAI_FAIL */ + "ai_family not supported", /* EAI_FAMILY */ + "Memory allocation failure", /* EAI_MEMORY */ + "No address associated with hostname", /* EAI_NODATA */ + "hostname nor servname provided, or not known", /* EAI_NONAME */ + "servname not supported for ai_socktype", /* EAI_SERVICE */ + "ai_socktype not supported", /* EAI_SOCKTYPE */ + "System error returned in errno", /* EAI_SYSTEM */ + "Invalid value for hints", /* EAI_BADHINTS */ + "Resolved protocol is unknown", /* EAI_PROTOCOL */ + "Unknown error", /* EAI_MAX */ +}; +#endif +/* XXX macros that make external reference is BAD. */ + +#define GET_AI(ai, afd, addr) \ +do { \ + /* external reference: pai, error, and label free */ \ + (ai) = get_ai(pai, (afd), (addr)); \ + if ((ai) == NULL) { \ + error = EAI_MEMORY; \ + goto free; \ + } \ +} while (/*CONSTCOND*/0) + +#define GET_PORT(ai, serv) \ +do { \ + /* external reference: error and label free */ \ + error = get_port((ai), (serv), 0); \ + if (error != 0) \ + goto free; \ +} while (/*CONSTCOND*/0) + +#define ERR(err) \ +do { \ + /* external reference: error, and label bad */ \ + error = (err); \ + goto bad; \ + /*NOTREACHED*/ \ +} while (/*CONSTCOND*/0) + +#define MATCH_FAMILY(x, y, w) \ + ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC))) +#define MATCH(x, y, w) \ + ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY))) + +#if 0 +/* We will need this should we ever want gai_strerror() */ +char * +gai_strerror(int ecode) +{ + if (ecode < 0 || ecode > EAI_MAX) + ecode = EAI_MAX; + return ai_errlist[ecode]; +} +#endif + +void +rb_freeaddrinfo(struct rb_addrinfo *ai) +{ + struct rb_addrinfo *next; + + do { + next = ai->ai_next; + if (ai->ai_canonname) + rb_free(ai->ai_canonname); + /* no need to free(ai->ai_addr) */ + rb_free(ai); + ai = next; + } while (ai); +} + +static int +str_isnumber(const char *p) +{ + char *ep; + + if (*p == '\0') + return NO; + ep = NULL; + errno = 0; + (void)strtoul(p, &ep, 10); + if (errno == 0 && ep && *ep == '\0') + return YES; + else + return NO; +} + +int +rb_getaddrinfo(const char *hostname, const char *servname, + const struct rb_addrinfo *hints, struct rb_addrinfo **res) +{ + struct rb_addrinfo sentinel; + struct rb_addrinfo *cur; + int error = 0; + struct rb_addrinfo ai; + struct rb_addrinfo ai0; + struct rb_addrinfo *pai; + const struct explore *ex; + + memset(&sentinel, 0, sizeof(sentinel)); + cur = &sentinel; + pai = &ai; + pai->ai_flags = 0; + pai->ai_family = PF_UNSPEC; + pai->ai_socktype = ANY; + pai->ai_protocol = ANY; + pai->ai_addrlen = 0; + pai->ai_canonname = NULL; + pai->ai_addr = NULL; + pai->ai_next = NULL; + + if (hostname == NULL && servname == NULL) + return EAI_NONAME; + if (hints) { + /* error check for hints */ + if (hints->ai_addrlen || hints->ai_canonname || + hints->ai_addr || hints->ai_next) + ERR(EAI_BADHINTS); /* xxx */ + if (hints->ai_flags & ~AI_MASK) + ERR(EAI_BADFLAGS); + switch (hints->ai_family) { + case PF_UNSPEC: + case PF_INET: +#ifdef IPV6 + case PF_INET6: +#endif + break; + default: + ERR(EAI_FAMILY); + } + memcpy(pai, hints, sizeof(*pai)); + + /* + * if both socktype/protocol are specified, check if they + * are meaningful combination. + */ + if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) { + for (ex = explore; ex->e_af >= 0; ex++) { + if (pai->ai_family != ex->e_af) + continue; + if (ex->e_socktype == ANY) + continue; + if (ex->e_protocol == ANY) + continue; + if (pai->ai_socktype == ex->e_socktype && + pai->ai_protocol != ex->e_protocol) { + ERR(EAI_BADHINTS); + } + } + } + } + + /* + * check for special cases. (1) numeric servname is disallowed if + * socktype/protocol are left unspecified. (2) servname is disallowed + * for raw and other inet{,6} sockets. + */ + if (MATCH_FAMILY(pai->ai_family, PF_INET, 1) +#ifdef IPV6 + || MATCH_FAMILY(pai->ai_family, PF_INET6, 1) +#endif + ) { + ai0 = *pai; /* backup *pai */ + + if (pai->ai_family == PF_UNSPEC) { +#ifdef IPV6 + pai->ai_family = PF_INET6; +#else + pai->ai_family = PF_INET; +#endif + } + error = get_portmatch(pai, servname); + if (error) + ERR(error); + + *pai = ai0; + } + + ai0 = *pai; + + /* NULL hostname, or numeric hostname */ + for (ex = explore; ex->e_af >= 0; ex++) { + *pai = ai0; + + /* PF_UNSPEC entries are prepared for DNS queries only */ + if (ex->e_af == PF_UNSPEC) + continue; + + if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex))) + continue; + if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex))) + continue; + if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex))) + continue; + + if (pai->ai_family == PF_UNSPEC) + pai->ai_family = ex->e_af; + if (pai->ai_socktype == ANY && ex->e_socktype != ANY) + pai->ai_socktype = ex->e_socktype; + if (pai->ai_protocol == ANY && ex->e_protocol != ANY) + pai->ai_protocol = ex->e_protocol; + + if (hostname == NULL) + error = explore_null(pai, servname, &cur->ai_next); + else + error = explore_numeric(pai, hostname, servname, &cur->ai_next); + + if (error) + goto free; + + while (cur && cur->ai_next) + cur = cur->ai_next; + } + + /* + * XXX + * If numreic representation of AF1 can be interpreted as FQDN + * representation of AF2, we need to think again about the code below. + */ + if (sentinel.ai_next) + goto good; + + if (pai->ai_flags & AI_NUMERICHOST) + ERR(EAI_NONAME); + if (hostname == NULL) + ERR(EAI_NODATA); + + /* XXX */ + if (sentinel.ai_next) + error = 0; + + if (error) + goto free; + if (error == 0) { + if (sentinel.ai_next) { + good: + *res = sentinel.ai_next; + return SUCCESS; + } else + error = EAI_FAIL; + } + free: + bad: + if (sentinel.ai_next) + rb_freeaddrinfo(sentinel.ai_next); + *res = NULL; + return error; +} + +/* + * hostname == NULL. + * passive socket -> anyaddr (0.0.0.0 or ::) + * non-passive socket -> localhost (127.0.0.1 or ::1) + */ +static int +explore_null(const struct rb_addrinfo *pai, const char *servname, struct rb_addrinfo **res) +{ + int s; + const struct afd *afd; + struct rb_addrinfo *cur; + struct rb_addrinfo sentinel; + int error; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * filter out AFs that are not supported by the kernel + * XXX errno? + */ + s = socket(pai->ai_family, SOCK_DGRAM, 0); + if (s < 0) { +#ifdef _WIN32 + errno = WSAGetLastError(); +#endif + if (errno != EMFILE) + return 0; + } else +#ifdef _WIN32 + closesocket(s); +#else + close(s); +#endif + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + + if (pai->ai_flags & AI_PASSIVE) { + GET_AI(cur->ai_next, afd, afd->a_addrany); + GET_PORT(cur->ai_next, servname); + } else { + GET_AI(cur->ai_next, afd, afd->a_loopback); + GET_PORT(cur->ai_next, servname); + } + cur = cur->ai_next; + + *res = sentinel.ai_next; + return 0; + +free: + if (sentinel.ai_next) + rb_freeaddrinfo(sentinel.ai_next); + return error; +} + +/* + * numeric hostname + */ +static int +explore_numeric(const struct rb_addrinfo *pai, const char *hostname, + const char *servname, struct rb_addrinfo **res) +{ + const struct afd *afd; + struct rb_addrinfo *cur; + struct rb_addrinfo sentinel; + int error; + char pton[PTON_MAX]; + + *res = NULL; + sentinel.ai_next = NULL; + cur = &sentinel; + + /* + * if the servname does not match socktype/protocol, ignore it. + */ + if (get_portmatch(pai, servname) != 0) + return 0; + + afd = find_afd(pai->ai_family); + if (afd == NULL) + return 0; + + switch (afd->a_af) { +#if 0 /*X/Open spec*/ + case AF_INET: + if (rb_inet_pton + if (inet_aton(hostname, (struct in_addr *)pton) == 1) { + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + while (cur && cur->ai_next) + cur = cur->ai_next; + } else + ERR(EAI_FAMILY); /*xxx*/ + } + break; +#endif + default: + if (rb_inet_pton(afd->a_af, hostname, pton) == 1) { + if (pai->ai_family == afd->a_af || + pai->ai_family == PF_UNSPEC /*?*/) { + GET_AI(cur->ai_next, afd, pton); + GET_PORT(cur->ai_next, servname); + while (cur && cur->ai_next) + cur = cur->ai_next; + } else + ERR(EAI_FAMILY); /* XXX */ + } + break; + } + + *res = sentinel.ai_next; + return 0; + +free: +bad: + if (sentinel.ai_next) + rb_freeaddrinfo(sentinel.ai_next); + return error; +} + +static struct rb_addrinfo * +get_ai(const struct rb_addrinfo *pai, const struct afd *afd, const char *addr) +{ + char *p; + struct rb_addrinfo *ai; + + ai = (struct rb_addrinfo *)rb_malloc(sizeof(struct rb_addrinfo) + + (afd->a_socklen)); + if (ai == NULL) + return NULL; + + memcpy(ai, pai, sizeof(struct rb_addrinfo)); + ai->ai_addr = (struct sockaddr *)(void *)(ai + 1); + memset(ai->ai_addr, 0, (size_t)afd->a_socklen); + ai->ai_addrlen = afd->a_socklen; + ai->ai_addr->sa_family = ai->ai_family = afd->a_af; + p = (char *)(void *)(ai->ai_addr); + memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen); + return ai; +} + +static int +get_portmatch(const struct rb_addrinfo *ai, const char *servname) +{ + struct rb_addrinfo xai; + memcpy(&xai, ai, sizeof(struct rb_addrinfo)); + return(get_port(&xai, servname, 1)); +} + +static int +get_port(struct rb_addrinfo *ai, const char *servname, int matchonly) +{ + const char *proto; + struct servent *sp; + int port; + int allownumeric; + + if (servname == NULL) + return 0; + switch (ai->ai_family) { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif + break; + default: + return 0; + } + + switch (ai->ai_socktype) { + case SOCK_RAW: + return EAI_SERVICE; + case SOCK_DGRAM: + case SOCK_STREAM: + allownumeric = 1; + break; + case ANY: + allownumeric = 0; + break; + default: + return EAI_SOCKTYPE; + } + + if (str_isnumber(servname)) { + if (!allownumeric) + return EAI_SERVICE; + port = atoi(servname); + if (port < 0 || port > 65535) + return EAI_SERVICE; + port = htons(port); + } else { + switch (ai->ai_socktype) { + case SOCK_DGRAM: + proto = "udp"; + break; + case SOCK_STREAM: + proto = "tcp"; + break; + default: + proto = NULL; + break; + } + + if ((sp = getservbyname(servname, proto)) == NULL) + return EAI_SERVICE; + port = sp->s_port; + } + + if (!matchonly) { + switch (ai->ai_family) { + case AF_INET: + ((struct sockaddr_in *)(void *) + ai->ai_addr)->sin_port = port; + break; +#ifdef IPV6 + case AF_INET6: + ((struct sockaddr_in6 *)(void *) + ai->ai_addr)->sin6_port = port; + break; +#endif + } + } + + return 0; +} + +static const struct afd * +find_afd(int af) +{ + const struct afd *afd; + + if (af == PF_UNSPEC) + return(NULL); + + for (afd = afdl; afd->a_af; afd++) + { + if (afd->a_af == af) + return(afd); + } + + return(NULL); +} +#endif diff --git a/authd/getaddrinfo.h b/authd/getaddrinfo.h new file mode 100644 index 000000000..746db142a --- /dev/null +++ b/authd/getaddrinfo.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +struct rb_addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + size_t ai_addrlen; + char *ai_canonname; + struct sockaddr *ai_addr; + struct rb_addrinfo *ai_next; +}; + +#ifndef AI_PASSIVE +#define AI_PASSIVE 0x00000001 /* get address to use bind() */ +#endif /* AI_PASSIVE */ + +#ifndef AI_NUMERICHOST +#define AI_NUMERICHOST 0x00000004 /* prevent name resolution */ +#endif /* AI_NUMERICHOST */ + +#ifndef EAI_FAIL +#define EAI_FAIL 4 /* non-recoverable failure in name resolution */ +#endif /* EAI_FAIL */ + +#ifndef EAI_FAMILY +#define EAI_FAMILY 5 /* ai_family not supported */ +#endif /* EAI_FAMILY */ + +#ifndef EAI_MEMORY +#define EAI_MEMORY 6 /* memory allocation failure */ +#endif /* EAI_MEMORY */ + +#ifndef EAI_NONAME +#define EAI_NONAME 8 /* hostname nor servname provided, or not known */ +#endif /* EAI_NONAME */ + +#ifndef EAI_SYSTEM +#define EAI_SYSTEM 11 /* system error returned in errno */ +#endif /* EAI_SYSTEM */ + +#ifndef NI_NUMERICHOST +#define NI_NUMERICHOST 0x00000002 +#endif /* NI_NUMERICHOST */ + +#ifndef NI_NAMEREQD +#define NI_NAMEREQD 0x00000004 +#endif /* NI_NAMEREQD */ + +#ifndef NI_NUMERICSERV +#define NI_NUMERICSERV 0x00000008 +#endif /* NI_NUMERICSERV */ + +#ifndef NI_DGRAM +#define NI_DGRAM 0x00000010 +#endif /* NI_DGRAM */ + +#ifndef INADDR_NONE +#define INADDR_NONE ((unsigned int) 0xffffffff) +#endif /* INADDR_NONE */ + +int rb_getaddrinfo(const char *hostname, const char *servname, + const struct rb_addrinfo *hints, struct rb_addrinfo **res); +void rb_freeaddrinfo(struct rb_addrinfo *ai); + +#define SUCCESS 0 +#define ANY 0 +#define YES 1 +#define NO 0 + +#undef EAI_ADDRFAMILY +#undef EAI_AGAIN +#undef EAI_BADFLAGS +#undef EAI_FAIL +#undef EAI_FAMILY +#undef EAI_MEMORY +#undef EAI_NODATA +#undef EAI_NONAME +#undef EAI_SERVICE +#undef EAI_SOCKTYPE +#undef EAI_SYSTEM +#undef EAI_BADHINTS +#undef EAI_PROTOCOL +#undef EAI_MAX +#undef AI_MASK + +#define EAI_ADDRFAMILY 1 /* address family for hostname not supported */ +#define EAI_AGAIN 2 /* temporary failure in name resolution */ +#define EAI_BADFLAGS 3 /* invalid value for ai_flags */ +#define EAI_FAIL 4 /* non-recoverable failure in name resolution */ +#define EAI_FAMILY 5 /* ai_family not supported */ +#define EAI_MEMORY 6 /* memory allocation failure */ +#define EAI_NODATA 7 /* no address associated with hostname */ +#define EAI_NONAME 8 /* hostname nor servname provided, or not known */ +#define EAI_SERVICE 9 /* servname not supported for ai_socktype */ +#define EAI_SOCKTYPE 10 /* ai_socktype not supported */ +#define EAI_SYSTEM 11 /* system error returned in errno */ +#define EAI_BADHINTS 12 +#define EAI_PROTOCOL 13 +#define EAI_MAX 14 +#define AI_MASK (AI_PASSIVE | AI_NUMERICHOST) diff --git a/authd/getnameinfo.c b/authd/getnameinfo.c new file mode 100644 index 000000000..eba0181ad --- /dev/null +++ b/authd/getnameinfo.c @@ -0,0 +1,242 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Issues to be discussed: + * - Thread safe-ness must be checked + * - RFC2553 says that we should raise error on short buffer. X/Open says + * we need to truncate the result. We obey RFC2553 (and X/Open should be + * modified). ipngwg rough consensus seems to follow RFC2553. + * - What is "local" in NI_FQDN? + * - NI_NAMEREQD and NI_NUMERICHOST conflict with each other. + * - (KAME extension) always attach textual scopeid (fe80::1%lo0), if + * sin6_scope_id is filled - standardization status? + * XXX breaks backward compat for code that expects no scopeid. + * beware on merge. + */ + +#ifdef _WIN32 +#include +#include "getaddrinfo.h" +#include "getnameinfo.h" + +/* $Id$ */ + +static const struct afd { + int a_af; + int a_addrlen; + rb_socklen_t a_socklen; + int a_off; +} afdl [] = { +#ifdef IPV6 + {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6), + offsetof(struct sockaddr_in6, sin6_addr)}, +#endif + {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in), + offsetof(struct sockaddr_in, sin_addr)}, + {0, 0, 0, 0}, +}; + +struct sockinet +{ + unsigned char si_len; + unsigned char si_family; + unsigned short si_port; +}; + +#ifdef IPV6 +static int ip6_parsenumeric(const struct sockaddr *, const char *, char *, + size_t, int); +#endif + +int +rb_getnameinfo(const struct sockaddr *sa, rb_socklen_t salen, char *host, + size_t hostlen, char *serv, size_t servlen, int flags) +{ + const struct afd *afd; + struct servent *sp; + unsigned short port; + int family, i; + const char *addr; + uint32_t v4a; + char numserv[512]; + char numaddr[512]; + + if (sa == NULL) + return EAI_FAIL; + +/* if (sa->sa_len != salen) + return EAI_FAIL; +*/ + family = sa->sa_family; + for (i = 0; afdl[i].a_af; i++) + if (afdl[i].a_af == family) { + afd = &afdl[i]; + goto found; + } + return EAI_FAMILY; + + found: + if (salen != afd->a_socklen) + return EAI_FAIL; + + /* network byte order */ + port = ((const struct sockinet *)sa)->si_port; + addr = (const char *)sa + afd->a_off; + + if (serv == NULL || servlen == 0) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: rfc2553bis-03 says that serv == NULL OR + * servlen == 0 means that the caller does not want the result. + */ + } else { + if (flags & NI_NUMERICSERV) + sp = NULL; + else { + sp = getservbyport(port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + } + if (sp) { + if (strlen(sp->s_name) + 1 > servlen) + return EAI_MEMORY; + rb_strlcpy(serv, sp->s_name, servlen); + } else { + snprintf(numserv, sizeof(numserv), "%u", ntohs(port)); + if (strlen(numserv) + 1 > servlen) + return EAI_MEMORY; + rb_strlcpy(serv, numserv, servlen); + } + } + + switch (sa->sa_family) { + case AF_INET: + v4a = (uint32_t) + ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr); + if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) + flags |= NI_NUMERICHOST; + v4a >>= IN_CLASSA_NSHIFT; + if (v4a == 0) + flags |= NI_NUMERICHOST; + break; +#ifdef IPV6 + case AF_INET6: + { + const struct sockaddr_in6 *sin6; + sin6 = (const struct sockaddr_in6 *)sa; + switch (sin6->sin6_addr.s6_addr[0]) { + case 0x00: + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) + ; + else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr)) + ; + else + flags |= NI_NUMERICHOST; + break; + default: + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + flags |= NI_NUMERICHOST; + } + else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) + flags |= NI_NUMERICHOST; + break; + } + } + break; +#endif + } + if (host == NULL || hostlen == 0) { + /* + * do nothing in this case. + * in case you are wondering if "&&" is more correct than + * "||" here: rfc2553bis-03 says that host == NULL or + * hostlen == 0 means that the caller does not want the result. + */ + } else if (flags & NI_NUMERICHOST) { + size_t numaddrlen; + + /* NUMERICHOST and NAMEREQD conflicts with each other */ + if (flags & NI_NAMEREQD) + return EAI_NONAME; + + switch(afd->a_af) { +#ifdef IPV6 + case AF_INET6: + { + int error; + + if ((error = ip6_parsenumeric(sa, addr, host, + hostlen, flags)) != 0) + return(error); + break; + } +#endif + default: + if (rb_inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr)) + == NULL) + return EAI_SYSTEM; + numaddrlen = strlen(numaddr); + if (numaddrlen + 1 > hostlen) /* don't forget terminator */ + return EAI_MEMORY; + rb_strlcpy(host, numaddr, hostlen); + break; + } + } + return(0); +} + +#ifdef IPV6 +static int +ip6_parsenumeric(const struct sockaddr *sa, const char *addr, + char *host, size_t hostlen, int flags) +{ + size_t numaddrlen; + char numaddr[512]; + + if (rb_inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL) + return(EAI_SYSTEM); + + numaddrlen = strlen(numaddr); + + if (numaddrlen + 1 > hostlen) /* don't forget terminator */ + return(EAI_MEMORY); + + if (*numaddr == ':') + { + *host = '0'; + rb_strlcpy(host+1, numaddr, hostlen-1); + } + else + rb_strlcpy(host, numaddr, hostlen); + + return(0); +} +#endif +#endif diff --git a/authd/getnameinfo.h b/authd/getnameinfo.h new file mode 100644 index 000000000..26b965ab4 --- /dev/null +++ b/authd/getnameinfo.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +int rb_getnameinfo(const struct sockaddr *sa, rb_socklen_t salen, char *host, + size_t hostlen, char *serv, size_t servlen, int flags); + +#ifndef IN_MULTICAST +#define IN_MULTICAST(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) +#endif + +#ifndef IN_EXPERIMENTAL +#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xe0000000) == 0xe0000000) +#endif diff --git a/authd/reslib.c b/authd/reslib.c index 6f0180db4..963679dbe 100644 --- a/authd/reslib.c +++ b/authd/reslib.c @@ -76,6 +76,18 @@ * - Dianora */ +#ifndef _WIN32 +#include +#else +#include "getaddrinfo.h" +#include "getnameinfo.h" +#define getaddrinfo rb_getaddrinfo +#define getnameinfo rb_getnameinfo +#define freeaddrinfo rb_freeaddrinfo + +extern const char * get_windows_nameservers(void); +#endif + #include "stdinc.h" #include "ircd_defs.h" #include "common.h" diff --git a/authd/reslist.c b/authd/reslist.c new file mode 100644 index 000000000..d18a06991 --- /dev/null +++ b/authd/reslist.c @@ -0,0 +1,276 @@ +/* + * reslist.c - get nameservers from windows * + * + * ircd-ratbox related changes are as follows + * + * Copyright (C) 2008 Aaron Sethman + * Copyright (C) 2008-2012 ircd-ratbox development team + * + * pretty much all of this was yanked from c-ares ares_init.c here is the original + * header from there -- + * + * Id: ares_init.c,v 1.72 2008-05-15 00:00:19 yangtse Exp $ + * Copyright 1998 by the Massachusetts Institute of Technology. + * Copyright (C) 2007-2008 by Daniel Stenberg + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * + */ + +#ifdef _WIN32 +#include + +#include +#include + +const char *get_windows_nameservers(void); + + +#define IS_NT() ((int)GetVersion() > 0) +#define WIN_NS_9X "System\\CurrentControlSet\\Services\\VxD\\MSTCP" +#define WIN_NS_NT_KEY "System\\CurrentControlSet\\Services\\Tcpip\\Parameters" +#define NAMESERVER "NameServer" +#define DHCPNAMESERVER "DhcpNameServer" +#define DATABASEPATH "DatabasePath" +#define WIN_PATH_HOSTS "\\hosts" + +static int +get_iphlpapi_dns_info(char *ret_buf, size_t ret_size) +{ + FIXED_INFO *fi = alloca(sizeof(*fi)); + DWORD size = sizeof(*fi); + typedef DWORD(WINAPI * get_net_param_func) (FIXED_INFO *, DWORD *); + get_net_param_func xxGetNetworkParams; /* available only on Win-98/2000+ */ + HMODULE handle; + IP_ADDR_STRING *ipAddr; + int i, count = 0; + int debug = 0; + size_t ip_size = sizeof("255.255.255.255,") - 1; + size_t left = ret_size; + char *ret = ret_buf; + HRESULT res; + + if(!fi) + return (0); + + handle = LoadLibrary("iphlpapi.dll"); + if(!handle) + return (0); + + xxGetNetworkParams = (get_net_param_func) GetProcAddress(handle, "GetNetworkParams"); + if(!xxGetNetworkParams) + goto quit; + + res = (*xxGetNetworkParams) (fi, &size); + if((res != ERROR_BUFFER_OVERFLOW) && (res != ERROR_SUCCESS)) + goto quit; + + fi = alloca(size); + if(!fi || (*xxGetNetworkParams) (fi, &size) != ERROR_SUCCESS) + goto quit; + + if(debug) + { + printf("Host Name: %s\n", fi->HostName); + printf("Domain Name: %s\n", fi->DomainName); + printf("DNS Servers:\n" " %s (primary)\n", fi->DnsServerList.IpAddress.String); + } + if(strlen(fi->DnsServerList.IpAddress.String) > 0 && + inet_addr(fi->DnsServerList.IpAddress.String) != INADDR_NONE && left > ip_size) + { + ret += sprintf(ret, "%s,", fi->DnsServerList.IpAddress.String); + left -= ret - ret_buf; + count++; + } + + for(i = 0, ipAddr = fi->DnsServerList.Next; ipAddr && left > ip_size; + ipAddr = ipAddr->Next, i++) + { + if(inet_addr(ipAddr->IpAddress.String) != INADDR_NONE) + { + ret += sprintf(ret, "%s,", ipAddr->IpAddress.String); + left -= ret - ret_buf; + count++; + } + if(debug) + printf(" %s (secondary %d)\n", ipAddr->IpAddress.String, i + 1); + } + + quit: + if(handle) + FreeLibrary(handle); + + if(debug && left <= ip_size) + printf("Too many nameservers. Truncating to %d addressess", count); + if(ret > ret_buf) + ret[-1] = '\0'; + return (count); +} + +/* + * Warning: returns a dynamically allocated buffer, the user MUST + * use free() / rb_free() if the function returns 1 + */ +static int +get_res_nt(HKEY hKey, const char *subkey, char **obuf) +{ + /* Test for the size we need */ + DWORD size = 0; + int result; + + result = RegQueryValueEx(hKey, subkey, 0, NULL, NULL, &size); + if((result != ERROR_SUCCESS && result != ERROR_MORE_DATA) || !size) + return 0; + *obuf = rb_malloc(size + 1); + if(!*obuf) + return 0; + + if(RegQueryValueEx(hKey, subkey, 0, NULL, (LPBYTE) * obuf, &size) != ERROR_SUCCESS) + { + rb_free(*obuf); + return 0; + } + if(size == 1) + { + rb_free(*obuf); + return 0; + } + return 1; +} + +static int +get_res_interfaces_nt(HKEY hKey, const char *subkey, char **obuf) +{ + char enumbuf[39]; /* GUIDs are 38 chars + 1 for NULL */ + DWORD enum_size = 39; + int idx = 0; + HKEY hVal; + + while(RegEnumKeyEx(hKey, idx++, enumbuf, &enum_size, 0, + NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS) + { + int rc; + + enum_size = 39; + if(RegOpenKeyEx(hKey, enumbuf, 0, KEY_QUERY_VALUE, &hVal) != ERROR_SUCCESS) + continue; + rc = get_res_nt(hVal, subkey, obuf); + RegCloseKey(hVal); + if(rc) + return 1; + } + return 0; +} + +const char * +get_windows_nameservers(void) +{ + /* + NameServer info via IPHLPAPI (IP helper API): + GetNetworkParams() should be the trusted source for this. + Available in Win-98/2000 and later. If that fail, fall-back to + registry information. + + NameServer Registry: + + On Windows 9X, the DNS server can be found in: + HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\VxD\MSTCP\NameServer + + On Windows NT/2000/XP/2003: + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\NameServer + or + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DhcpNameServer + or + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\ + NameServer + or + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\{AdapterID}\ + DhcpNameServer + */ + static char namelist[512]; + HKEY mykey; + HKEY subkey; + DWORD data_type; + DWORD bytes; + DWORD result; + char *line = NULL; + memset(&namelist, 0, sizeof(namelist)); + if(get_iphlpapi_dns_info(namelist, sizeof(namelist)) > 0) + { + return namelist; + } + + if(IS_NT()) + { + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_NT_KEY, 0, + KEY_READ, &mykey) == ERROR_SUCCESS) + { + RegOpenKeyEx(mykey, "Interfaces", 0, + KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &subkey); + if(get_res_nt(mykey, NAMESERVER, &line)) + { + rb_strlcpy(namelist, line, sizeof(namelist)); + return namelist; + } + else if(get_res_nt(mykey, DHCPNAMESERVER, &line)) + { + rb_strlcpy(namelist, line, sizeof(namelist)); + rb_free(line); + } + /* Try the interfaces */ + else if(get_res_interfaces_nt(subkey, NAMESERVER, &line)) + { + rb_strlcpy(namelist, line, sizeof(namelist)); + rb_free(line); + } + else if(get_res_interfaces_nt(subkey, DHCPNAMESERVER, &line)) + { + rb_strlcpy(namelist, line, sizeof(namelist)); + rb_free(line); + } + RegCloseKey(subkey); + RegCloseKey(mykey); + } + } + else + { + if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_NS_9X, 0, + KEY_READ, &mykey) == ERROR_SUCCESS) + { + if((result = RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type, + NULL, &bytes)) == ERROR_SUCCESS || + result == ERROR_MORE_DATA) + { + if(bytes) + { + line = (char *)rb_malloc(bytes + 1); + if(RegQueryValueEx(mykey, NAMESERVER, NULL, &data_type, + (unsigned char *)line, &bytes) == + ERROR_SUCCESS) + { + rb_strlcpy(namelist, line, sizeof(namelist)); + } + free(line); + } + } + } + RegCloseKey(mykey); + } + if(strlen(namelist) > 0) + return namelist; + return NULL; +} + + +#endif diff --git a/include/stdinc.h b/include/stdinc.h index 0712e6219..eb321edb6 100644 --- a/include/stdinc.h +++ b/include/stdinc.h @@ -92,7 +92,6 @@ typedef bool _Bool; #include #include #include -#include #include #include #include @@ -112,7 +111,6 @@ typedef bool _Bool; #endif -#include #include #include