diff options
author | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2000-01-27 05:18:48 +0000 |
---|---|---|
committer | Jun-ichiro itojun Hagino <itojun@cvs.openbsd.org> | 2000-01-27 05:18:48 +0000 |
commit | 9fc658e7ba4e739dcdf418e0ecd9fc9be3025d47 (patch) | |
tree | 38fa5b2787f2a8f7bab62a53138ab610f20c120d /lib | |
parent | de62a1b03efc9264e5c66dffa8a8735c06790744 (diff) |
add IPv6-ready rcmd() friends.
rcmd(): IPv4 only
rcmd_af(): af independent
ruserok(): af independent
iruserok(): IPv4 only
iruserok_sa(): af independent
Diffstat (limited to 'lib')
-rw-r--r-- | lib/libc/net/Makefile.inc | 4 | ||||
-rw-r--r-- | lib/libc/net/rcmd.3 | 43 | ||||
-rw-r--r-- | lib/libc/net/rcmd.c | 297 |
3 files changed, 264 insertions, 80 deletions
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc index 447a96f1e19..7174d682205 100644 --- a/lib/libc/net/Makefile.inc +++ b/lib/libc/net/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.27 1999/12/16 21:30:34 deraadt Exp $ +# $OpenBSD: Makefile.inc,v 1.28 2000/01/27 05:18:46 itojun Exp $ # net sources .PATH: ${LIBCSRCDIR}/arch/${MACHINE_ARCH}/net ${LIBCSRCDIR}/net @@ -65,7 +65,7 @@ MLINKS+=link_addr.3 link_ntoa.3 MLINKS+=ipx.3 ipx_addr.3 ipx.3 ipx_ntoa.3 MLINKS+=ns.3 ns_addr.3 ns.3 ns_ntoa.3 MLINKS+=rcmd.3 iruserok.3 rcmd.3 rresvport.3 rcmd.3 ruserok.3 \ - rcmd.3 rresvport_af.3 + rcmd.3 rresvport_af.3 rcmd.3 rcmd_af.3 rcmd.3 iruserok_sa.3 MLINKS+=resolver.3 dn_comp.3 resolver.3 dn_expand.3 resolver.3 res_init.3 \ resolver.3 res_mkquery.3 resolver.3 res_send.3 resolver.3 res_query.3 \ resolver.3 res_search.3 diff --git a/lib/libc/net/rcmd.3 b/lib/libc/net/rcmd.3 index fa7be72c8d9..6df614b419b 100644 --- a/lib/libc/net/rcmd.3 +++ b/lib/libc/net/rcmd.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rcmd.3,v 1.16 2000/01/26 06:22:52 deraadt Exp $ +.\" $OpenBSD: rcmd.3,v 1.17 2000/01/27 05:18:47 itojun Exp $ .\" .\" Copyright (c) 1983, 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -36,16 +36,20 @@ .Os .Sh NAME .Nm rcmd , +.Nm rcmd_af , .Nm rresvport , .Nm rresvport_af , .Nm iruserok , -.Nm ruserok +.Nm ruserok , +.Nm iruserok_sa .Nd routines for returning a stream to a remote command .Sh SYNOPSIS .Fd #include <unistd.h> .Ft int .Fn rcmd "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p" .Ft int +.Fn rcmd_af "char **ahost" "int inport" "const char *locuser" "const char *remuser" "const char *cmd" "int *fd2p" "int af" +.Ft int .Fn rresvport "int *port" .Ft int .Fn rresvport_af "int *port" "int af" @@ -53,6 +57,8 @@ .Fn iruserok "u_int32_t raddr" "int superuser" "const char *ruser" "const char *luser" .Ft int .Fn ruserok "const char *rhost" "int superuser" "const char *ruser" "const char *luser" +.Ft int +.Fn iruserok_sa "const void *sa" "int salen" "int superuser" "const char *ruser" .Sh DESCRIPTION The .Fn rcmd @@ -74,6 +80,12 @@ will invoke .Xr rcmdsh 3 to run the command via .Xr rsh 1 . +While +.Fn rcmd +can handle IPv4 cases only, +the +.Fn rcmd_af +function can handle other cases as well. The .Fn rresvport and @@ -92,6 +104,9 @@ All four functions are present in the same file and are used by the .Xr rshd 8 server (among others). +.Fn iruserok_sa +is an address family independent variant of +.Fn iruserok . .Pp The .Fn rcmd @@ -142,6 +157,14 @@ Note that if the user is not the super-user, .Fa fd2p must be 0. .Pp +.Fn rcmd_af +takes address family in the last argument. +If the last argument is +.Dv PF_UNSPEC , +interpretation of +.Fa *ahost +will obey the underlying address resolution like DNS. +.Pp The protocol is described in detail in .Xr rshd 8 . .Pp @@ -200,6 +223,22 @@ If the IP address of the remote host is known, should be used in preference to .Fn ruserok , as it does not require trusting the DNS server for the remote host's domain. +.Pp +While +.Fn iruserok +can handle IPv4 addresses only, +.Fn iruserok_sa +and +.Fn ruserok +can handle other address families as well, like IPv6. +The first argument of +.Fn iruserok_sa +is typed as +.Fa "void *" +to avoid dependency between +.Aq Li unistd.h +and +.Aq Li sys/socket.h . .Sh DIAGNOSTICS The .Fn rcmd diff --git a/lib/libc/net/rcmd.c b/lib/libc/net/rcmd.c index bd920faadb5..79892bd5a1b 100644 --- a/lib/libc/net/rcmd.c +++ b/lib/libc/net/rcmd.c @@ -34,7 +34,7 @@ */ #if defined(LIBC_SCCS) && !defined(lint) -static char *rcsid = "$OpenBSD: rcmd.c,v 1.32 1999/12/16 21:30:34 deraadt Exp $"; +static char *rcsid = "$OpenBSD: rcmd.c,v 1.33 2000/01/27 05:18:47 itojun Exp $"; #endif /* LIBC_SCCS and not lint */ #include <sys/param.h> @@ -58,8 +58,9 @@ static char *rcsid = "$OpenBSD: rcmd.c,v 1.32 1999/12/16 21:30:34 deraadt Exp $" #include <netgroup.h> int __ivaliduser __P((FILE *, in_addr_t, const char *, const char *)); -static int __icheckhost __P((u_int32_t, const char *)); -static char *__gethostloop __P((u_int32_t)); +int __ivaliduser_sa __P((FILE *, struct sockaddr *, const char *, const char *)); +static int __icheckhost __P((struct sockaddr *, const char *)); +static char *__gethostloop __P((struct sockaddr *)); int rcmd(ahost, rport, locuser, remuser, cmd, fd2p) @@ -68,8 +69,22 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) const char *locuser, *remuser, *cmd; int *fd2p; { - struct hostent *hp; - struct sockaddr_in sin, from; + return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); +} + +int +rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af) + char **ahost; + in_port_t rport; + const char *locuser, *remuser, *cmd; + int *fd2p; + int af; +{ + static char hbuf[MAXHOSTNAMELEN]; + char pbuf[NI_MAXSERV]; + struct addrinfo hints, *res, *r; + int error; + struct sockaddr_storage from; fd_set *readsp = NULL; int oldmask; pid_t pid; @@ -95,16 +110,29 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) } pid = getpid(); - hp = gethostbyname(*ahost); - if (hp == NULL) { - herror(*ahost); + snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport)); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + error = getaddrinfo(*ahost, pbuf, &hints, &res); + if (error) { +#if 0 + warnx("%s: %s", *ahost, gai_strerror(error)); +#endif return (-1); } - *ahost = hp->h_name; - + if (res->ai_canonname) { + strncpy(hbuf, res->ai_canonname, sizeof(hbuf) - 1); + hbuf[sizeof(hbuf) - 1] = '\0'; + *ahost = hbuf; + } else + ; /*XXX*/ + + r = res; oldmask = sigblock(sigmask(SIGURG)); for (timo = 1, lport = IPPORT_RESERVED - 1;;) { - s = rresvport(&lport); + s = rresvport_af(&lport, r->ai_family); if (s < 0) { if (errno == EAGAIN) (void)fprintf(stderr, @@ -113,15 +141,11 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) (void)fprintf(stderr, "rcmd: socket: %s\n", strerror(errno)); sigsetmask(oldmask); + freeaddrinfo(res); return (-1); } fcntl(s, F_SETOWN, pid); - bzero(&sin, sizeof sin); - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_family = hp->h_addrtype; - sin.sin_port = rport; - bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); - if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) + if (connect(s, r->ai_addr, r->ai_addrlen) >= 0) break; (void)close(s); if (errno == EADDRINUSE) { @@ -133,23 +157,39 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) timo *= 2; continue; } - if (hp->h_addr_list[1] != NULL) { + if (r->ai_next) { int oerrno = errno; + char hbuf[NI_MAXHOST]; +#ifdef NI_WITHSCOPEID + const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflags = NI_NUMERICHOST; +#endif - (void)fprintf(stderr, "connect to address %s: ", - inet_ntoa(sin.sin_addr)); + hbuf[0] = '\0'; + if (getnameinfo(r->ai_addr, r->ai_addrlen, + hbuf, sizeof(hbuf), NULL, 0, niflags) != 0) + strcpy(hbuf, "(invalid)"); + (void)fprintf(stderr, "connect to address %s: ", hbuf); errno = oerrno; perror(0); - hp->h_addr_list++; - bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); - (void)fprintf(stderr, "Trying %s...\n", - inet_ntoa(sin.sin_addr)); + r = r->ai_next; + hbuf[0] = '\0'; + if (getnameinfo(r->ai_addr, r->ai_addrlen, + hbuf, sizeof(hbuf), NULL, 0, niflags) != 0) + strcpy(hbuf, "(invalid)"); + (void)fprintf(stderr, "Trying %s...\n", hbuf); continue; } - (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno)); + (void)fprintf(stderr, "%s: %s\n", res->ai_canonname, + strerror(errno)); sigsetmask(oldmask); + freeaddrinfo(res); return (-1); } + /* given "af" can be PF_UNSPEC, we need the real af for "s" */ + af = r->ai_family; + freeaddrinfo(res); #if 0 /* * try to rresvport() to the same port. This will make rresvport() @@ -162,7 +202,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) lport = 0; } else { char num[8]; - int s2 = rresvport(&lport), s3; + int s2 = rresvport_af(&lport, af), s3; int len = sizeof(from); int fdssize = howmany(MAX(s, s2)+1, NFDBITS) * sizeof(fd_mask); @@ -202,9 +242,18 @@ again: * XXX careful for ftp bounce attacks. If discovered, shut them * down and check for the real auxiliary channel to connect. */ - if (from.sin_family == AF_INET && from.sin_port == htons(20)) { + switch (from.ss_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo((struct sockaddr *)&from, len, + NULL, 0, num, sizeof(num), NI_NUMERICSERV) == 0 && + atoi(num) != 20) { + break; + } close(s3); goto again; + default: + break; } (void)close(s2); if (s3 < 0) { @@ -214,13 +263,20 @@ again: goto bad; } *fd2p = s3; - from.sin_port = ntohs(from.sin_port); - if (from.sin_family != AF_INET || - from.sin_port >= IPPORT_RESERVED || - from.sin_port < IPPORT_RESERVED / 2) { - (void)fprintf(stderr, - "socket: protocol failure in circuit setup.\n"); - goto bad2; + switch (from.ss_family) { + case AF_INET: + case AF_INET6: + if (getnameinfo((struct sockaddr *)&from, len, + NULL, 0, num, sizeof(num), NI_NUMERICSERV) != 0 || + (atoi(num) >= IPPORT_RESERVED || + atoi(num) < IPPORT_RESERVED / 2)) { + (void)fprintf(stderr, + "socket: protocol failure in circuit setup.\n"); + goto bad2; + } + break; + default: + break; } } (void)write(s, locuser, strlen(locuser)+1); @@ -261,21 +317,24 @@ ruserok(rhost, superuser, ruser, luser) const char *rhost, *ruser, *luser; int superuser; { - struct hostent *hp; - char **ap; - int i; -#define MAXADDRS 35 - u_int32_t addrs[MAXADDRS + 1]; - - if ((hp = gethostbyname(rhost)) == NULL) + 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 (i = 0, ap = hp->h_addr_list; *ap && i < MAXADDRS; ++ap, ++i) - bcopy(*ap, &addrs[i], sizeof(addrs[i])); - addrs[i] = 0; - for (i = 0; i < MAXADDRS && addrs[i]; i++) - if (iruserok((in_addr_t)addrs[i], superuser, ruser, luser) == 0) + 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); } @@ -294,6 +353,24 @@ iruserok(raddr, superuser, ruser, luser) int superuser; const char *ruser, *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(raddr, rlen, superuser, ruser, luser) + const void *raddr; + int rlen; + int superuser; + const char *ruser, *luser; +{ + struct sockaddr *sa; register char *cp; struct stat sbuf; struct passwd *pwd; @@ -302,11 +379,15 @@ iruserok(raddr, superuser, ruser, luser) int first; char pbuf[MAXPATHLEN]; + sa = (struct sockaddr *)raddr; +#ifdef lint + rlen = rlen; +#endif first = 1; hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); again: if (hostf) { - if (__ivaliduser(hostf, raddr, luser, ruser) == 0) { + if (__ivaliduser_sa(hostf, sa, luser, ruser) == 0) { (void)fclose(hostf); return (0); } @@ -369,13 +450,27 @@ __ivaliduser(hostf, raddrl, luser, ruser) in_addr_t raddrl; const char *luser, *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, luser, ruser); +} + +int +__ivaliduser_sa(hostf, raddr, luser, ruser) + FILE *hostf; + struct sockaddr *raddr; + const char *luser, *ruser; +{ register char *user, *p; char *buf; const char *auser, *ahost; int hostok, userok; char *rhost = (char *)-1; char domain[MAXHOSTNAMELEN]; - u_int32_t raddr = (u_int32_t)raddrl; size_t buflen; getdomainname(domain, sizeof(domain)); @@ -509,27 +604,54 @@ bail: /* * 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. + * + * NI_WITHSCOPEID is useful for comparing sin6_scope_id portion + * if af == AF_INET6. */ static int __icheckhost(raddr, lhost) - u_int32_t raddr; + struct sockaddr *raddr; const char *lhost; { - register struct hostent *hp; - register char **pp; - struct in_addr in; - - hp = gethostbyname(lhost); - if (hp != NULL) { - /* Spin through ip addresses. */ - for (pp = hp->h_addr_list; *pp; ++pp) - if (!bcmp(&raddr, *pp, sizeof(raddr))) - return (1); + struct addrinfo hints, *res, *r; + char h1[NI_MAXHOST], h2[NI_MAXHOST]; + int error; +#ifdef NI_WITHSCOPEID + const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflags = NI_NUMERICHOST; +#endif + + h1[0] = '\0'; + if (getnameinfo(raddr, raddr->sa_len, 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); + } } - in.s_addr = raddr; - if (strcmp(lhost, inet_ntoa(in)) == 0) - return (1); + /* No match. */ + freeaddrinfo(res); return (0); } @@ -537,39 +659,62 @@ __icheckhost(raddr, lhost) * 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. + * + * NI_WITHSCOPEID is useful for comparing sin6_scope_id portion + * if af == AF_INET6. */ static char * __gethostloop(raddr) - u_int32_t raddr; + struct sockaddr *raddr; { - static char remotehost[MAXHOSTNAMELEN]; - struct hostent *hp; - struct in_addr in; + static char remotehost[NI_MAXHOST]; + char h1[NI_MAXHOST], h2[NI_MAXHOST]; + struct addrinfo hints, *res, *r; + int error; +#ifdef NI_WITHSCOPEID + const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; +#else + const int niflags = NI_NUMERICHOST; +#endif - hp = gethostbyaddr((char *) &raddr, sizeof(raddr), AF_INET); - if (hp == NULL) + h1[0] = remotehost[0] = '\0'; + if (getnameinfo(raddr, raddr->sa_len, remotehost, sizeof(remotehost), + NULL, 0, NI_NAMEREQD) != 0) + return (NULL); + if (getnameinfo(raddr, raddr->sa_len, h1, sizeof(h1), NULL, 0, + niflags) != 0) return (NULL); /* * Look up the name and check that the supplied * address is in the list */ - strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); - remotehost[sizeof(remotehost) - 1] = '\0'; - hp = gethostbyname(remotehost); - if (hp == NULL) + 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 (; hp->h_addr_list[0] != NULL; hp->h_addr_list++) - if (!bcmp(hp->h_addr_list[0], (caddr_t)&raddr, sizeof(raddr))) + 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 */ - in.s_addr = raddr; syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s", - inet_ntoa(in), hp->h_name); + h1, res->ai_canonname ? res->ai_canonname : remotehost); + freeaddrinfo(res); return (NULL); } |