diff options
Diffstat (limited to 'inet/rcmd.c')
-rw-r--r-- | inet/rcmd.c | 419 |
1 files changed, 281 insertions, 138 deletions
diff --git a/inet/rcmd.c b/inet/rcmd.c index ace393fa5e..f3dc1bd4ab 100644 --- a/inet/rcmd.c +++ b/inet/rcmd.c @@ -1,4 +1,32 @@ /* + * Copyright (C) 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. + */ +/* * Copyright (c) 1983, 1993, 1994 * The Regents of the University of California. All rights reserved. * @@ -54,100 +82,124 @@ static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; int __ivaliduser __P ((FILE *, u_int32_t, const char *, const char *)); -static int __ivaliduser2 __P ((FILE *, u_int32_t, const char *, const char *, - const char *)); -static int iruserok2 (u_int32_t raddr, int superuser, const char *ruser, - const char *luser, const char *rhost); +static int __validuser2_sa __P ((FILE *, struct sockaddr *, size_t, + const char *, const char *, const char *)); +static int ruserok2_sa (struct sockaddr *ra, size_t ralen, + int superuser, const char *ruser, + const char *luser, const char *rhost); +static int ruserok_sa (struct sockaddr *ra, size_t ralen, + int superuser, const char *ruser, + const char *luser); +int iruserok_af (const void *raddr, int superuser, const char *ruser, + const char *luser, sa_family_t af); int iruserok (u_int32_t raddr, int superuser, const char *ruser, const char *luser); +static char ahostbuf[NI_MAXHOST]; int -rcmd(ahost, rport, locuser, remuser, cmd, fd2p) +rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af) char **ahost; u_short rport; const char *locuser, *remuser, *cmd; int *fd2p; + sa_family_t af; { - struct hostent hostbuf, *hp; + char paddr[INET6_ADDRSTRLEN]; size_t hstbuflen; char *tmphstbuf; - struct sockaddr_in sin, from; + struct addrinfo hints, *res, *ai; + struct sockaddr_storage from; struct pollfd pfd[2]; int32_t oldmask; pid_t pid; - int s, lport, timo; + int s, lport, timo, error; char c; - int herr; + int refused; + char num[8]; + + if (af != AF_INET && af != AF_INET6) + { + __set_errno (EAFNOSUPPORT); + return -1; + } pid = __getpid(); - hstbuflen = 1024; - tmphstbuf = __alloca (hstbuflen); - while (__gethostbyname_r (*ahost, &hostbuf, tmphstbuf, hstbuflen, - &hp, &herr) != 0 - || hp == NULL) - if (herr != NETDB_INTERNAL || errno != ERANGE) - { - __set_h_errno (herr); - herror(*ahost); - return -1; - } - else - { - /* Enlarge the buffer. */ - hstbuflen *= 2; - tmphstbuf = __alloca (hstbuflen); - } + memset(&hints, '\0', sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + (void)snprintf(num, sizeof(num), "%d", ntohs(rport)); + error = getaddrinfo(*ahost, num, &hints, &res); + if (error) { + fprintf(stderr, "rcmd: getaddrinfo: %s\n", + gai_strerror(error)); + return (-1); + } pfd[0].events = POLLIN; pfd[1].events = POLLIN; - *ahost = hp->h_name; + if (res->ai_canonname){ + strncpy(ahostbuf, res->ai_canonname, sizeof(ahostbuf)); + ahostbuf[sizeof(ahostbuf)-1] = '\0'; + *ahost = ahostbuf; + } + else + *ahost = NULL; + ai = res; + refused = 0; oldmask = __sigblock(sigmask(SIGURG)); for (timo = 1, lport = IPPORT_RESERVED - 1;;) { - s = rresvport(&lport); + s = rresvport_af(&lport, ai->ai_family); if (s < 0) { if (errno == EAGAIN) - (void)fprintf(stderr, - _("rcmd: socket: All ports in use\n")); + fprintf(stderr, + _("rcmd: socket: All ports in use\n")); else - (void)fprintf(stderr, "rcmd: socket: %m\n"); + fprintf(stderr, "rcmd: socket: %m\n"); __sigsetmask(oldmask); + freeaddrinfo(res); return -1; } __fcntl(s, F_SETOWN, pid); - sin.sin_family = hp->h_addrtype; - bcopy(hp->h_addr_list[0], &sin.sin_addr, - MIN (sizeof (sin.sin_addr), hp->h_length)); - sin.sin_port = rport; - if (__connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) + if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0) break; (void)__close(s); if (errno == EADDRINUSE) { lport--; continue; } - if (errno == ECONNREFUSED && timo <= 16) { - (void)__sleep(timo); - timo *= 2; - continue; - } - if (hp->h_addr_list[1] != NULL) { + if (errno == ECONNREFUSED) + refused = 1; + if (ai->ai_next != NULL) { int oerrno = errno; - (void)fprintf(stderr, _("connect to address %s: "), - inet_ntoa(sin.sin_addr)); + getnameinfo(ai->ai_addr, ai->ai_addrlen, + paddr, sizeof(paddr), + NULL, 0, + NI_NUMERICHOST); + fprintf(stderr, "connect to address %s: ", paddr); __set_errno (oerrno); perror(0); - hp->h_addr_list++; - bcopy(hp->h_addr_list[0], &sin.sin_addr, - MIN (sizeof (sin.sin_addr), hp->h_length)); - (void)fprintf(stderr, _("Trying %s...\n"), - inet_ntoa(sin.sin_addr)); + ai = ai->ai_next; + getnameinfo(ai->ai_addr, ai->ai_addrlen, + paddr, sizeof(paddr), + NULL, 0, + NI_NUMERICHOST); + fprintf(stderr, "Trying %s...\n", paddr); + continue; + } + if (refused && timo <= 16) { + (void)sleep(timo); + timo *= 2; + ai = res; + refused = 0; continue; } - (void)fprintf(stderr, "%s: %m\n", hp->h_name); + freeaddrinfo(res); + (void)fprintf(stderr, "%s: %s\n", *ahost, strerror(errno)); __sigsetmask(oldmask); return -1; } @@ -157,8 +209,8 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) lport = 0; } else { char num[8]; - int s2 = rresvport(&lport), s3; - size_t len = sizeof(from); + int s2 = rresvport_af(&lport, ai->ai_family), s3; + size_t len = ai->ai_addrlen; if (s2 < 0) goto bad; @@ -184,6 +236,17 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) goto bad; } s3 = accept(s2, (struct sockaddr *)&from, &len); + switch (from.__ss_family) { + case AF_INET: + rport = ntohs(((struct sockaddr_in *)&from)->sin_port); + break; + case AF_INET6: + rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port); + break; + default: + rport = 0; + break; + } (void)__close(s2); if (s3 < 0) { (void)fprintf(stderr, @@ -192,12 +255,10 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) goto bad; } *fd2p = s3; - from.sin_port = ntohs((u_short)from.sin_port); - if (from.sin_family != AF_INET || - from.sin_port >= IPPORT_RESERVED || - from.sin_port < IPPORT_RESERVED / 2) { + + if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){ (void)fprintf(stderr, - _("socket: protocol failure in circuit setup\n")); + _("socket: protocol failure in circuit setup\n")); goto bad2; } } @@ -218,6 +279,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) goto bad2; } __sigsetmask(oldmask); + freeaddrinfo(res); return s; bad2: if (lport) @@ -225,74 +287,113 @@ bad2: bad: (void)__close(s); __sigsetmask(oldmask); + freeaddrinfo(res); return -1; } int -rresvport(alport) +rcmd(ahost, rport, locuser, remuser, cmd, fd2p) + char **ahost; + u_short rport; + const char *locuser, *remuser, *cmd; + int *fd2p; +{ + return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); +} + +int +rresvport_af(alport, family) int *alport; + sa_family_t family; { - struct sockaddr_in sin; + struct sockaddr_storage ss; int s; + size_t len; + uint16_t *sport, i; - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = INADDR_ANY; - s = __socket(AF_INET, SOCK_STREAM, 0); + switch(family){ + case AF_INET: + len = sizeof(struct sockaddr_in); + sport = &((struct sockaddr_in *)&ss)->sin_port; + break; + case AF_INET6: + len = sizeof(struct sockaddr_in6); + sport = &((struct sockaddr_in6 *)&ss)->sin6_port; + break; + default: + __set_errno (EAFNOSUPPORT); + return -1; + } + s = socket(family, SOCK_STREAM, 0); if (s < 0) return -1; + + memset (&ss, '\0', sizeof(ss)); +#ifdef SALEN + ss.__ss_len = len; +#endif + ss.__ss_family = family; + for (;;) { - sin.sin_port = htons((u_short)*alport); - if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) + *sport = htons(i); + if (bind(s, (struct sockaddr *)&ss, len) >= 0){ + *alport = i; return s; + } if (errno != EADDRINUSE) { (void)__close(s); return -1; } (*alport)--; - if (*alport == IPPORT_RESERVED/2) { - (void)__close(s); - __set_errno (EAGAIN); /* close */ - return -1; - } + if (*alport == IPPORT_RESERVED/2) + break; } + (void)__close(s); + __set_errno (EAGAIN); + return -1; +} + +int +rresvport(alport) + int *alport; +{ + return rresvport_af(alport, AF_INET); } int __check_rhosts_file = 1; char *__rcmd_errstr; int +ruserok_af(rhost, superuser, ruser, luser, af) + const char *rhost, *ruser, *luser; + int superuser; + sa_family_t af; +{ + struct addrinfo hints, *res, *res0; + int gai; + int ret; + + memset (&hints, '\0', sizeof(hints)); + hints.ai_family = af; + gai = getaddrinfo(rhost, NULL, &hints, &res0); + if (gai) + return -1; + ret = -1; + for (res=res0; res; res=res->ai_next) + if (ruserok2_sa(res->ai_addr, res->ai_addrlen, + superuser, ruser, luser, rhost) == 0){ + ret = 0; + break; + } + freeaddrinfo(res0); + return (ret); +} +int ruserok(rhost, superuser, ruser, luser) const char *rhost, *ruser, *luser; int superuser; { - struct hostent hostbuf, *hp; - size_t buflen; - char *buffer; - u_int32_t addr; - char **ap; - int herr; - - buflen = 1024; - buffer = __alloca (buflen); - - while (__gethostbyname_r (rhost, &hostbuf, buffer, buflen, &hp, &herr) - != 0 - || hp == NULL) - if (herr != NETDB_INTERNAL || errno != ERANGE) - return -1; - else - { - /* Enlarge the buffer. */ - buflen *= 2; - buffer = __alloca (buflen); - } - - for (ap = hp->h_addr_list; *ap; ++ap) { - bcopy(*ap, &addr, sizeof(addr)); - if (iruserok2(addr, superuser, ruser, luser, rhost) == 0) - return 0; - } - return -1; + return ruserok_af(rhost, superuser, ruser, luser, AF_INET); } /* Extremely paranoid file open function. */ @@ -348,8 +449,9 @@ iruserfopen (char *file, uid_t okuser) * Returns 0 if ok, -1 if not ok. */ static int -iruserok2 (raddr, superuser, ruser, luser, rhost) - u_int32_t raddr; +ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost) + struct sockaddr *ra; + size_t ralen; int superuser; const char *ruser, *luser, *rhost; { @@ -361,7 +463,7 @@ iruserok2 (raddr, superuser, ruser, luser, rhost) if (hostf) { - isbad = __ivaliduser2 (hostf, raddr, luser, ruser, rhost); + isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost); fclose (hostf); if (!isbad) @@ -395,7 +497,7 @@ iruserok2 (raddr, superuser, ruser, luser, rhost) if (hostf != NULL) { - isbad = __ivaliduser2 (hostf, raddr, luser, ruser, rhost); + isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost); fclose (hostf); } @@ -404,15 +506,56 @@ iruserok2 (raddr, superuser, ruser, luser, rhost) } return -1; } +/* + * ruserok_sa() is now discussed on ipng, so + * currently disabled for external use + */ +static int ruserok_sa(ra, ralen, superuser, ruser, luser) + struct sockaddr *ra; + size_t ralen; + int superuser; + const char *ruser, *luser; +{ + ruserok2_sa(ra, ralen, superuser, ruser, luser, "-"); +} /* This is the exported version. */ int +iruserok_af (raddr, superuser, ruser, luser, af) + const void *raddr; + int superuser; + const char *ruser, *luser; + sa_family_t af; +{ + struct sockaddr_storage ra; + size_t ralen; + + memset (&ra, '\0', sizeof(ra)); + switch (af){ + case AF_INET: + ((struct sockaddr_in *)&ra)->sin_family = AF_INET; + memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr, + sizeof(struct in_addr)); + ralen = sizeof(struct sockaddr_in); + break; + case AF_INET6: + ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6; + memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr, + sizeof(struct in6_addr)); + ralen = sizeof(struct sockaddr_in6); + break; + default: + return 0; + } + return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser); +} +int iruserok (raddr, superuser, ruser, luser) u_int32_t raddr; int superuser; const char *ruser, *luser; { - return iruserok2 (raddr, superuser, ruser, luser, "-"); + return iruserok_af (&raddr, superuser, ruser, luser, AF_INET); } /* @@ -432,26 +575,31 @@ __ivaliduser(hostf, raddr, luser, ruser) u_int32_t raddr; const char *luser, *ruser; { - return __ivaliduser2(hostf, raddr, luser, ruser, "-"); + struct sockaddr_in ra; + memset(&ra, '\0', sizeof(ra)); + ra.sin_family = AF_INET; + ra.sin_addr.s_addr = raddr; + return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra), + luser, ruser, "-"); } /* Returns 1 on positive match, 0 on no match, -1 on negative match. */ static int internal_function -__icheckhost (raddr, lhost, rhost) - u_int32_t raddr; +__checkhost_sa (ra, ralen, lhost, rhost) + struct sockaddr *ra; + size_t ralen; char *lhost; const char *rhost; { - struct hostent hostbuf, *hp; - size_t buflen; - char *buffer; + struct addrinfo hints, *res0, *res; int herr; int save_errno; - u_int32_t laddr; + char raddr[INET6_ADDRSTRLEN]; + int match; int negate=1; /* Multiply return with this to get -1 instead of 1 */ - char **pp, *user; + char *user; /* Check nis netgroup. */ if (strncmp ("+@", lhost, 2) == 0) @@ -469,34 +617,28 @@ __icheckhost (raddr, lhost, rhost) } /* Try for raw ip address first. */ - if (isdigit (*lhost) && (long) (laddr = inet_addr (lhost)) != -1) - return negate * (! (raddr ^ laddr)); + /* XXX */ + if (getnameinfo(ra, ralen, + raddr, sizeof(raddr), NULL, 0, + NI_NUMERICHOST) == 0) + return negate * (strcmp(raddr, lhost) == 0); /* Better be a hostname. */ - buflen = 1024; - buffer = __alloca (buflen); - save_errno = errno; - while (__gethostbyname_r (lhost, &hostbuf, buffer, buflen, &hp, &herr) - != 0) - if (herr != NETDB_INTERNAL || errno != ERANGE) - return (0); - else { - /* Enlarge the buffer. */ - buflen *= 2; - buffer = __alloca (buflen); - __set_errno (0); + match = 0; + memset(&hints, '\0', sizeof(hints)); + hints.ai_family = ra->sa_family; + if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){ + /* Spin through ip addresses. */ + for (res=res0; res; res->ai_next){ + if (res->ai_family == ra->sa_family && + !memcmp(res->ai_addr, ra, res->ai_addrlen)){ + match = 1; + break; + } } - __set_errno (save_errno); - if (hp == NULL) - return 0; - - /* Spin through ip addresses. */ - for (pp = hp->h_addr_list; *pp; ++pp) - if (!memcmp (&raddr, *pp, sizeof (u_int32_t))) - return negate; - - /* No match. */ - return (0); + freeaddrinfo(res0); + } + return (negate * match); } /* Returns 1 on positive match, 0 on no match, -1 on negative match. */ @@ -548,9 +690,10 @@ __isempty(p) * Returns 0 if positive match, -1 if _not_ ok. */ static int -__ivaliduser2(hostf, raddr, luser, ruser, rhost) +__validuser2_sa(hostf, ra, ralen, luser, ruser, rhost) FILE *hostf; - u_int32_t raddr; + struct sockaddr *ra; + size_t ralen; const char *luser, *ruser, *rhost; { register const char *user; @@ -598,7 +741,7 @@ __ivaliduser2(hostf, raddr, luser, ruser, rhost) /* buf -> host(?) ; user -> username(?) */ /* First check host part */ - hcheck = __icheckhost (raddr, buf, rhost); + hcheck = __checkhost_sa (ra, ralen, buf, rhost); if (hcheck < 0) break; |