From e9648d2ce662fb0d79072496682efb0718c01e66 Mon Sep 17 00:00:00 2001 From: guenther <> Date: Wed, 18 Nov 2009 07:43:22 +0000 Subject: More shrinkage, a bit for ramdisks but mostly for static binaries: - wrap with #ifndef NO_LOG_BAD_DNS_RESPONSES libc code that uses p_class() and p_type() for diagnostics, then add that define to libstub to avoid pulling in res_debug_syms.o - split rcmd() and ruserok() into separate files, as nothing uses both - split readdir_r() to its own file - split syslog_r() from syslog(), as the latter needs localtime(); many binaries no longer need to pull in all the time code after this; switch from usleep() to nanosleep() while we're at it (The profit of analysis of -Wl,-M,--cref output) Chops 888kB from /bin and /sbin on i386 ok deraadt@, miod@ --- src/lib/libc/net/Makefile.inc | 4 +- src/lib/libc/net/getaddrinfo.c | 4 +- src/lib/libc/net/gethostnamadr.c | 4 +- src/lib/libc/net/rcmd.c | 388 ---------------------------------- src/lib/libc/net/ruserok.c | 437 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 445 insertions(+), 392 deletions(-) create mode 100644 src/lib/libc/net/ruserok.c (limited to 'src') diff --git a/src/lib/libc/net/Makefile.inc b/src/lib/libc/net/Makefile.inc index 244c266536..50924ec135 100644 --- a/src/lib/libc/net/Makefile.inc +++ b/src/lib/libc/net/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.45 2009/08/13 19:54:58 jmc Exp $ +# $OpenBSD: Makefile.inc,v 1.46 2009/11/18 07:43:22 guenther Exp $ # net sources .PATH: ${LIBCSRCDIR}/arch/${MACHINE_ARCH}/net ${LIBCSRCDIR}/net @@ -13,7 +13,7 @@ SRCS+= base64.c freeaddrinfo.c gai_strerror.c getaddrinfo.c gethostnamadr.c \ inet_lnaof.c inet_makeaddr.c inet_neta.c inet_netof.c inet_network.c \ inet_net_ntop.c inet_net_pton.c inet_ntoa.c inet_ntop.c inet_pton.c \ linkaddr.c net_addrcmp.c nsap_addr.c \ - rcmd.c rresvport.c recv.c res_comp.c res_data.c res_debug.c \ + rcmd.c ruserok.c rresvport.c recv.c res_comp.c res_data.c res_debug.c \ res_debug_syms.c \ res_init.c res_mkquery.c res_query.c res_random.c res_send.c send.c \ sethostent.c ethers.c rcmdsh.c diff --git a/src/lib/libc/net/getaddrinfo.c b/src/lib/libc/net/getaddrinfo.c index 98e247bc44..7040fa7c37 100644 --- a/src/lib/libc/net/getaddrinfo.c +++ b/src/lib/libc/net/getaddrinfo.c @@ -1,4 +1,4 @@ -/* $OpenBSD: getaddrinfo.c,v 1.70 2009/09/02 19:07:12 fgsch Exp $ */ +/* $OpenBSD: getaddrinfo.c,v 1.71 2009/11/18 07:43:22 guenther Exp $ */ /* $KAME: getaddrinfo.c,v 1.31 2000/08/31 17:36:43 itojun Exp $ */ /* @@ -1062,6 +1062,7 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, continue; } } else if (type != qtype) { +#ifndef NO_LOG_BAD_DNS_RESPONSES if (type != T_KEY && type != T_SIG) { struct syslog_data sdata = SYSLOG_DATA_INIT; @@ -1070,6 +1071,7 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype, qname, p_class(C_IN), p_type(qtype), p_type(type)); } +#endif /* NO_LOG_BAD_DNS_RESPONSES */ cp += n; continue; /* XXX - had_error++ ? */ } diff --git a/src/lib/libc/net/gethostnamadr.c b/src/lib/libc/net/gethostnamadr.c index d49b9cdd7d..f4e655eeaf 100644 --- a/src/lib/libc/net/gethostnamadr.c +++ b/src/lib/libc/net/gethostnamadr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: gethostnamadr.c,v 1.72 2007/10/11 18:36:41 jakob Exp $ */ +/* $OpenBSD: gethostnamadr.c,v 1.73 2009/11/18 07:43:22 guenther Exp $ */ /*- * Copyright (c) 1985, 1988, 1993 * The Regents of the University of California. All rights reserved. @@ -294,10 +294,12 @@ getanswer(const querybuf *answer, int anslen, const char *qname, int qtype) continue; } if (type != qtype) { +#ifndef NO_LOG_BAD_DNS_RESPONSES syslog(LOG_NOTICE|LOG_AUTH, "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"", qname, p_class(C_IN), p_type(qtype), p_type(type)); +#endif /* NO_LOG_BAD_DNS_RESPONSES */ cp += n; continue; /* XXX - had_error++ ? */ } diff --git a/src/lib/libc/net/rcmd.c b/src/lib/libc/net/rcmd.c index 30ca6710c4..d566e0ca4c 100644 --- a/src/lib/libc/net/rcmd.c +++ b/src/lib/libc/net/rcmd.c @@ -46,13 +46,6 @@ #include #include #include -#include - -int __ivaliduser(FILE *, in_addr_t, const char *, const char *); -int __ivaliduser_sa(FILE *, struct sockaddr *, socklen_t, - const char *, const char *); -static int __icheckhost(struct sockaddr *, socklen_t, const char *); -static char *__gethostloop(struct sockaddr *, socklen_t); int rcmd(char **ahost, int rport, const char *locuser, const char *remuser, @@ -308,384 +301,3 @@ bad: return (-1); } -int __check_rhosts_file = 1; -char *__rcmd_errstr; - -int -ruserok(const char *rhost, int superuser, const char *ruser, const char *luser) -{ - struct addrinfo hints, *res, *r; - int error; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - error = getaddrinfo(rhost, "0", &hints, &res); - if (error) - return (-1); - - for (r = res; r; r = r->ai_next) { - if (iruserok_sa(r->ai_addr, r->ai_addrlen, superuser, ruser, - luser) == 0) { - freeaddrinfo(res); - return (0); - } - } - freeaddrinfo(res); - return (-1); -} - -/* - * New .rhosts strategy: We are passed an ip address. We spin through - * hosts.equiv and .rhosts looking for a match. When the .rhosts only - * has ip addresses, we don't have to trust a nameserver. When it - * contains hostnames, we spin through the list of addresses the nameserver - * gives us and look for a match. - * - * Returns 0 if ok, -1 if not ok. - */ -int -iruserok(u_int32_t raddr, int superuser, const char *ruser, const char *luser) -{ - struct sockaddr_in sin; - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(struct sockaddr_in); - memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr)); - return iruserok_sa(&sin, sizeof(struct sockaddr_in), superuser, ruser, - luser); -} - -int -iruserok_sa(const void *raddr, int rlen, int superuser, const char *ruser, - const char *luser) -{ - struct sockaddr *sa; - char *cp; - struct stat sbuf; - struct passwd *pwd; - FILE *hostf; - uid_t uid; - int first; - char pbuf[MAXPATHLEN]; - - sa = (struct sockaddr *)raddr; - first = 1; - hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); -again: - if (hostf) { - if (__ivaliduser_sa(hostf, sa, rlen, luser, ruser) == 0) { - (void)fclose(hostf); - return (0); - } - (void)fclose(hostf); - } - if (first == 1 && (__check_rhosts_file || superuser)) { - int len; - - first = 0; - if ((pwd = getpwnam(luser)) == NULL) - return (-1); - len = snprintf(pbuf, sizeof pbuf, "%s/.rhosts", pwd->pw_dir); - if (len < 0 || len >= sizeof pbuf) - return (-1); - - /* - * Change effective uid while opening .rhosts. If root and - * reading an NFS mounted file system, can't read files that - * are protected read/write owner only. - */ - uid = geteuid(); - (void)seteuid(pwd->pw_uid); - hostf = fopen(pbuf, "r"); - (void)seteuid(uid); - - if (hostf == NULL) - return (-1); - /* - * If not a regular file, or is owned by someone other than - * user or root or if writeable by anyone but the owner, quit. - */ - cp = NULL; - if (lstat(pbuf, &sbuf) < 0) - cp = ".rhosts lstat failed"; - else if (!S_ISREG(sbuf.st_mode)) - cp = ".rhosts not regular file"; - else if (fstat(fileno(hostf), &sbuf) < 0) - cp = ".rhosts fstat failed"; - else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) - cp = "bad .rhosts owner"; - else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) - cp = ".rhosts writable by other than owner"; - /* If there were any problems, quit. */ - if (cp) { - __rcmd_errstr = cp; - (void)fclose(hostf); - return (-1); - } - goto again; - } - return (-1); -} - -/* - * XXX - * Don't make static, used by lpd(8). - * - * Returns 0 if ok, -1 if not ok. - */ -int -__ivaliduser(FILE *hostf, in_addr_t raddrl, const char *luser, - const char *ruser) -{ - struct sockaddr_in sin; - - memset(&sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(struct sockaddr_in); - memcpy(&sin.sin_addr, &raddrl, sizeof(sin.sin_addr)); - return __ivaliduser_sa(hostf, (struct sockaddr *)&sin, sin.sin_len, - luser, ruser); -} - -int -__ivaliduser_sa(FILE *hostf, struct sockaddr *raddr, socklen_t salen, - const char *luser, const char *ruser) -{ - char *user, *p; - char *buf; - const char *auser, *ahost; - int hostok, userok; - char *rhost = (char *)-1; - char domain[MAXHOSTNAMELEN]; - size_t buflen; - - getdomainname(domain, sizeof(domain)); - - while ((buf = fgetln(hostf, &buflen))) { - p = buf; - if (*p == '#') - continue; - while (p < buf + buflen && *p != '\n' && *p != ' ' && *p != '\t') { - if (!isprint(*p)) - goto bail; - *p = isupper(*p) ? tolower(*p) : *p; - p++; - } - if (p >= buf + buflen) - continue; - if (*p == ' ' || *p == '\t') { - *p++ = '\0'; - while (p < buf + buflen && (*p == ' ' || *p == '\t')) - p++; - if (p >= buf + buflen) - continue; - user = p; - while (p < buf + buflen && *p != '\n' && *p != ' ' && - *p != '\t') { - if (!isprint(*p)) - goto bail; - p++; - } - } else - user = p; - *p = '\0'; - - if (p == buf) - continue; - - auser = *user ? user : luser; - ahost = buf; - - if (strlen(ahost) >= MAXHOSTNAMELEN) - continue; - - /* - * innetgr() must lookup a hostname (we do not attempt - * to change the semantics so that netgroups may have - * #.#.#.# addresses in the list.) - */ - if (ahost[0] == '+') - switch (ahost[1]) { - case '\0': - hostok = 1; - break; - case '@': - if (rhost == (char *)-1) - rhost = __gethostloop(raddr, salen); - hostok = 0; - if (rhost) - hostok = innetgr(&ahost[2], rhost, - NULL, domain); - break; - default: - hostok = __icheckhost(raddr, salen, &ahost[1]); - break; - } - else if (ahost[0] == '-') - switch (ahost[1]) { - case '\0': - hostok = -1; - break; - case '@': - if (rhost == (char *)-1) - rhost = __gethostloop(raddr, salen); - hostok = 0; - if (rhost) - hostok = -innetgr(&ahost[2], rhost, - NULL, domain); - break; - default: - hostok = -__icheckhost(raddr, salen, &ahost[1]); - break; - } - else - hostok = __icheckhost(raddr, salen, ahost); - - - if (auser[0] == '+') - switch (auser[1]) { - case '\0': - userok = 1; - break; - case '@': - userok = innetgr(&auser[2], NULL, ruser, - domain); - break; - default: - userok = strcmp(ruser, &auser[1]) ? 0 : 1; - break; - } - else if (auser[0] == '-') - switch (auser[1]) { - case '\0': - userok = -1; - break; - case '@': - userok = -innetgr(&auser[2], NULL, ruser, - domain); - break; - default: - userok = strcmp(ruser, &auser[1]) ? 0 : -1; - break; - } - else - userok = strcmp(ruser, auser) ? 0 : 1; - - /* Check if one component did not match */ - if (hostok == 0 || userok == 0) - continue; - - /* Check if we got a forbidden pair */ - if (userok <= -1 || hostok <= -1) - return (-1); - - /* Check if we got a valid pair */ - if (hostok >= 1 && userok >= 1) - return (0); - } -bail: - return (-1); -} - -/* - * Returns "true" if match, 0 if no match. If we do not find any - * semblance of an A->PTR->A loop, allow a simple #.#.#.# match to work. - */ -static int -__icheckhost(struct sockaddr *raddr, socklen_t salen, const char *lhost) -{ - struct addrinfo hints, *res, *r; - char h1[NI_MAXHOST], h2[NI_MAXHOST]; - int error; - const int niflags = NI_NUMERICHOST; - - h1[0] = '\0'; - if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0, - niflags) != 0) - return (0); - - /* Resolve laddr into sockaddr */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = raddr->sa_family; - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - res = NULL; - error = getaddrinfo(lhost, "0", &hints, &res); - if (error) - return (0); - - /* - * Try string comparisons between raddr and laddr. - */ - for (r = res; r; r = r->ai_next) { - h2[0] = '\0'; - if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2), - NULL, 0, niflags) != 0) - continue; - if (strcmp(h1, h2) == 0) { - freeaddrinfo(res); - return (1); - } - } - - /* No match. */ - freeaddrinfo(res); - return (0); -} - -/* - * Return the hostname associated with the supplied address. - * Do a reverse lookup as well for security. If a loop cannot - * be found, pack the result of inet_ntoa() into the string. - */ -static char * -__gethostloop(struct sockaddr *raddr, socklen_t salen) -{ - static char remotehost[NI_MAXHOST]; - char h1[NI_MAXHOST], h2[NI_MAXHOST]; - struct addrinfo hints, *res, *r; - int error; - const int niflags = NI_NUMERICHOST; - - h1[0] = remotehost[0] = '\0'; - if (getnameinfo(raddr, salen, remotehost, sizeof(remotehost), - NULL, 0, NI_NAMEREQD) != 0) - return (NULL); - if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0, - niflags) != 0) - return (NULL); - - /* - * Look up the name and check that the supplied - * address is in the list - */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = raddr->sa_family; - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - hints.ai_flags = AI_CANONNAME; - res = NULL; - error = getaddrinfo(remotehost, "0", &hints, &res); - if (error) - return (NULL); - - for (r = res; r; r = r->ai_next) { - h2[0] = '\0'; - if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2), - NULL, 0, niflags) != 0) - continue; - if (strcmp(h1, h2) == 0) { - freeaddrinfo(res); - return (remotehost); - } - } - - /* - * either the DNS adminstrator has made a configuration - * mistake, or someone has attempted to spoof us - */ - syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s", - h1, res->ai_canonname ? res->ai_canonname : remotehost); - freeaddrinfo(res); - return (NULL); -} diff --git a/src/lib/libc/net/ruserok.c b/src/lib/libc/net/ruserok.c new file mode 100644 index 0000000000..5ef078ac95 --- /dev/null +++ b/src/lib/libc/net/ruserok.c @@ -0,0 +1,437 @@ +/* + * Copyright (c) 1995, 1996, 1998 Theo de Raadt. All rights reserved. + * Copyright (c) 1983, 1993, 1994 + * The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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. + */ + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int __ivaliduser(FILE *, in_addr_t, const char *, const char *); +int __ivaliduser_sa(FILE *, struct sockaddr *, socklen_t, + const char *, const char *); +static int __icheckhost(struct sockaddr *, socklen_t, const char *); +static char *__gethostloop(struct sockaddr *, socklen_t); + +int __check_rhosts_file = 1; +char *__rcmd_errstr; + +int +ruserok(const char *rhost, int superuser, const char *ruser, const char *luser) +{ + struct addrinfo hints, *res, *r; + int error; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + error = getaddrinfo(rhost, "0", &hints, &res); + if (error) + return (-1); + + for (r = res; r; r = r->ai_next) { + if (iruserok_sa(r->ai_addr, r->ai_addrlen, superuser, ruser, + luser) == 0) { + freeaddrinfo(res); + return (0); + } + } + freeaddrinfo(res); + return (-1); +} + +/* + * New .rhosts strategy: We are passed an ip address. We spin through + * hosts.equiv and .rhosts looking for a match. When the .rhosts only + * has ip addresses, we don't have to trust a nameserver. When it + * contains hostnames, we spin through the list of addresses the nameserver + * gives us and look for a match. + * + * Returns 0 if ok, -1 if not ok. + */ +int +iruserok(u_int32_t raddr, int superuser, const char *ruser, const char *luser) +{ + struct sockaddr_in sin; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(struct sockaddr_in); + memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr)); + return iruserok_sa(&sin, sizeof(struct sockaddr_in), superuser, ruser, + luser); +} + +int +iruserok_sa(const void *raddr, int rlen, int superuser, const char *ruser, + const char *luser) +{ + struct sockaddr *sa; + char *cp; + struct stat sbuf; + struct passwd *pwd; + FILE *hostf; + uid_t uid; + int first; + char pbuf[MAXPATHLEN]; + + sa = (struct sockaddr *)raddr; + first = 1; + hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); +again: + if (hostf) { + if (__ivaliduser_sa(hostf, sa, rlen, luser, ruser) == 0) { + (void)fclose(hostf); + return (0); + } + (void)fclose(hostf); + } + if (first == 1 && (__check_rhosts_file || superuser)) { + int len; + + first = 0; + if ((pwd = getpwnam(luser)) == NULL) + return (-1); + len = snprintf(pbuf, sizeof pbuf, "%s/.rhosts", pwd->pw_dir); + if (len < 0 || len >= sizeof pbuf) + return (-1); + + /* + * Change effective uid while opening .rhosts. If root and + * reading an NFS mounted file system, can't read files that + * are protected read/write owner only. + */ + uid = geteuid(); + (void)seteuid(pwd->pw_uid); + hostf = fopen(pbuf, "r"); + (void)seteuid(uid); + + if (hostf == NULL) + return (-1); + /* + * If not a regular file, or is owned by someone other than + * user or root or if writeable by anyone but the owner, quit. + */ + cp = NULL; + if (lstat(pbuf, &sbuf) < 0) + cp = ".rhosts lstat failed"; + else if (!S_ISREG(sbuf.st_mode)) + cp = ".rhosts not regular file"; + else if (fstat(fileno(hostf), &sbuf) < 0) + cp = ".rhosts fstat failed"; + else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) + cp = "bad .rhosts owner"; + else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) + cp = ".rhosts writable by other than owner"; + /* If there were any problems, quit. */ + if (cp) { + __rcmd_errstr = cp; + (void)fclose(hostf); + return (-1); + } + goto again; + } + return (-1); +} + +/* + * XXX + * Don't make static, used by lpd(8). + * + * Returns 0 if ok, -1 if not ok. + */ +int +__ivaliduser(FILE *hostf, in_addr_t raddrl, const char *luser, + const char *ruser) +{ + struct sockaddr_in sin; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_len = sizeof(struct sockaddr_in); + memcpy(&sin.sin_addr, &raddrl, sizeof(sin.sin_addr)); + return __ivaliduser_sa(hostf, (struct sockaddr *)&sin, sin.sin_len, + luser, ruser); +} + +int +__ivaliduser_sa(FILE *hostf, struct sockaddr *raddr, socklen_t salen, + const char *luser, const char *ruser) +{ + char *user, *p; + char *buf; + const char *auser, *ahost; + int hostok, userok; + char *rhost = (char *)-1; + char domain[MAXHOSTNAMELEN]; + size_t buflen; + + getdomainname(domain, sizeof(domain)); + + while ((buf = fgetln(hostf, &buflen))) { + p = buf; + if (*p == '#') + continue; + while (p < buf + buflen && *p != '\n' && *p != ' ' && *p != '\t') { + if (!isprint(*p)) + goto bail; + *p = isupper(*p) ? tolower(*p) : *p; + p++; + } + if (p >= buf + buflen) + continue; + if (*p == ' ' || *p == '\t') { + *p++ = '\0'; + while (p < buf + buflen && (*p == ' ' || *p == '\t')) + p++; + if (p >= buf + buflen) + continue; + user = p; + while (p < buf + buflen && *p != '\n' && *p != ' ' && + *p != '\t') { + if (!isprint(*p)) + goto bail; + p++; + } + } else + user = p; + *p = '\0'; + + if (p == buf) + continue; + + auser = *user ? user : luser; + ahost = buf; + + if (strlen(ahost) >= MAXHOSTNAMELEN) + continue; + + /* + * innetgr() must lookup a hostname (we do not attempt + * to change the semantics so that netgroups may have + * #.#.#.# addresses in the list.) + */ + if (ahost[0] == '+') + switch (ahost[1]) { + case '\0': + hostok = 1; + break; + case '@': + if (rhost == (char *)-1) + rhost = __gethostloop(raddr, salen); + hostok = 0; + if (rhost) + hostok = innetgr(&ahost[2], rhost, + NULL, domain); + break; + default: + hostok = __icheckhost(raddr, salen, &ahost[1]); + break; + } + else if (ahost[0] == '-') + switch (ahost[1]) { + case '\0': + hostok = -1; + break; + case '@': + if (rhost == (char *)-1) + rhost = __gethostloop(raddr, salen); + hostok = 0; + if (rhost) + hostok = -innetgr(&ahost[2], rhost, + NULL, domain); + break; + default: + hostok = -__icheckhost(raddr, salen, &ahost[1]); + break; + } + else + hostok = __icheckhost(raddr, salen, ahost); + + + if (auser[0] == '+') + switch (auser[1]) { + case '\0': + userok = 1; + break; + case '@': + userok = innetgr(&auser[2], NULL, ruser, + domain); + break; + default: + userok = strcmp(ruser, &auser[1]) ? 0 : 1; + break; + } + else if (auser[0] == '-') + switch (auser[1]) { + case '\0': + userok = -1; + break; + case '@': + userok = -innetgr(&auser[2], NULL, ruser, + domain); + break; + default: + userok = strcmp(ruser, &auser[1]) ? 0 : -1; + break; + } + else + userok = strcmp(ruser, auser) ? 0 : 1; + + /* Check if one component did not match */ + if (hostok == 0 || userok == 0) + continue; + + /* Check if we got a forbidden pair */ + if (userok <= -1 || hostok <= -1) + return (-1); + + /* Check if we got a valid pair */ + if (hostok >= 1 && userok >= 1) + return (0); + } +bail: + return (-1); +} + +/* + * Returns "true" if match, 0 if no match. If we do not find any + * semblance of an A->PTR->A loop, allow a simple #.#.#.# match to work. + */ +static int +__icheckhost(struct sockaddr *raddr, socklen_t salen, const char *lhost) +{ + struct addrinfo hints, *res, *r; + char h1[NI_MAXHOST], h2[NI_MAXHOST]; + int error; + const int niflags = NI_NUMERICHOST; + + h1[0] = '\0'; + if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0, + niflags) != 0) + return (0); + + /* Resolve laddr into sockaddr */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = raddr->sa_family; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + res = NULL; + error = getaddrinfo(lhost, "0", &hints, &res); + if (error) + return (0); + + /* + * Try string comparisons between raddr and laddr. + */ + for (r = res; r; r = r->ai_next) { + h2[0] = '\0'; + if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2), + NULL, 0, niflags) != 0) + continue; + if (strcmp(h1, h2) == 0) { + freeaddrinfo(res); + return (1); + } + } + + /* No match. */ + freeaddrinfo(res); + return (0); +} + +/* + * Return the hostname associated with the supplied address. + * Do a reverse lookup as well for security. If a loop cannot + * be found, pack the result of inet_ntoa() into the string. + */ +static char * +__gethostloop(struct sockaddr *raddr, socklen_t salen) +{ + static char remotehost[NI_MAXHOST]; + char h1[NI_MAXHOST], h2[NI_MAXHOST]; + struct addrinfo hints, *res, *r; + int error; + const int niflags = NI_NUMERICHOST; + + h1[0] = remotehost[0] = '\0'; + if (getnameinfo(raddr, salen, remotehost, sizeof(remotehost), + NULL, 0, NI_NAMEREQD) != 0) + return (NULL); + if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0, + niflags) != 0) + return (NULL); + + /* + * Look up the name and check that the supplied + * address is in the list + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = raddr->sa_family; + hints.ai_socktype = SOCK_DGRAM; /*dummy*/ + hints.ai_flags = AI_CANONNAME; + res = NULL; + error = getaddrinfo(remotehost, "0", &hints, &res); + if (error) + return (NULL); + + for (r = res; r; r = r->ai_next) { + h2[0] = '\0'; + if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2), + NULL, 0, niflags) != 0) + continue; + if (strcmp(h1, h2) == 0) { + freeaddrinfo(res); + return (remotehost); + } + } + + /* + * either the DNS adminstrator has made a configuration + * mistake, or someone has attempted to spoof us + */ + syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s", + h1, res->ai_canonname ? res->ai_canonname : remotehost); + freeaddrinfo(res); + return (NULL); +} -- cgit v1.2.3-55-g6feb