diff options
Diffstat (limited to 'lib/libc/net/rcmd.c')
-rw-r--r-- | lib/libc/net/rcmd.c | 150 |
1 files changed, 130 insertions, 20 deletions
diff --git a/lib/libc/net/rcmd.c b/lib/libc/net/rcmd.c index 279b9bd..ff108d9 100644 --- a/lib/libc/net/rcmd.c +++ b/lib/libc/net/rcmd.c @@ -51,6 +51,15 @@ static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; #include <stdio.h> #include <ctype.h> #include <string.h> +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif + +extern int innetgr __P(( const char *, const char *, const char *, const char * )); + +#define max(a, b) ((a > b) ? a : b) int __ivaliduser __P((FILE *, u_long, const char *, const char *)); static int __icheckhost __P((u_long, char *)); @@ -91,9 +100,11 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) return (-1); } fcntl(s, F_SETOWN, pid); + bzero(&sin, sizeof sin); + sin.sin_len = sizeof(struct sockaddr_in); sin.sin_family = hp->h_addrtype; - bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); sin.sin_port = rport; + bcopy(hp->h_addr_list[0], &sin.sin_addr, MIN(hp->h_length, sizeof sin.sin_addr)); if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) break; (void)close(s); @@ -114,7 +125,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) errno = oerrno; perror(0); hp->h_addr_list++; - bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); + bcopy(hp->h_addr_list[0], &sin.sin_addr, MIN(hp->h_length, sizeof sin.sin_addr)); (void)fprintf(stderr, "Trying %s...\n", inet_ntoa(sin.sin_addr)); continue; @@ -131,6 +142,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) char num[8]; int s2 = rresvport(&lport), s3; int len = sizeof(from); + int nfds; if (s2 < 0) goto bad; @@ -143,11 +155,18 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) (void)close(s2); goto bad; } + nfds = max(s, s2)+1; + if(nfds > FD_SETSIZE) { + fprintf(stderr, "rcmd: too many files\n"); + (void)close(s2); + goto bad; + } +again: FD_ZERO(&reads); FD_SET(s, &reads); FD_SET(s2, &reads); errno = 0; - if (select(32, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)) { + if (select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){ if (errno != 0) (void)fprintf(stderr, "rcmd: select (setting up stderr): %s\n", @@ -159,6 +178,14 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p) goto bad; } s3 = accept(s2, (struct sockaddr *)&from, &len); + /* + * 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)) { + close(s3); + goto again; + } (void)close(s2); if (s3 < 0) { (void)fprintf(stderr, @@ -210,26 +237,29 @@ rresvport(alport) struct sockaddr_in sin; int s; + bzero(&sin, sizeof sin); + sin.sin_len = sizeof(struct sockaddr_in); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) return (-1); - for (;;) { - sin.sin_port = htons((u_short)*alport); - if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) - return (s); - if (errno != EADDRINUSE) { - (void)close(s); - return (-1); - } - (*alport)--; - if (*alport == IPPORT_RESERVED/2) { - (void)close(s); - errno = EAGAIN; /* close */ - return (-1); - } +#if 0 /* compat_exact_traditional_rresvport_semantics */ + sin.sin_port = htons((u_short)*alport); + if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) + return (s); + if (errno != EADDRINUSE) { + (void)close(s); + return (-1); + } +#endif + sin.sin_port = 0; + if (bindresvport(s, &sin) == -1) { + (void)close(s); + return (-1); } + *alport = (int)ntohs(sin.sin_port); + return (s); } int __check_rhosts_file = 1; @@ -347,6 +377,24 @@ __ivaliduser(hostf, raddr, luser, ruser) register char *user, *p; int ch; char buf[MAXHOSTNAMELEN + 128]; /* host + login */ + char hname[MAXHOSTNAMELEN]; + struct hostent *hp; + /* Presumed guilty until proven innocent. */ + int userok = 0, hostok = 0; +#ifdef YP + char *ypdomain; + + if (yp_get_default_domain(&ypdomain)) + ypdomain = NULL; +#else +#define ypdomain NULL +#endif + /* We need to get the damn hostname back for netgroup matching. */ + if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long), + AF_INET)) == NULL) + return (-1); + strncpy(hname, hp->h_name, sizeof(hname)); + hname[sizeof(hname) - 1] = '\0'; while (fgets(buf, sizeof(buf), hostf)) { p = buf; @@ -355,6 +403,10 @@ __ivaliduser(hostf, raddr, luser, ruser) while ((ch = getc(hostf)) != '\n' && ch != EOF); continue; } + if (*p == '\n' || *p == '#') { + /* comment... */ + continue; + } while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { *p = isupper(*p) ? tolower(*p) : *p; p++; @@ -370,10 +422,68 @@ __ivaliduser(hostf, raddr, luser, ruser) } else user = p; *p = '\0'; - if (__icheckhost(raddr, buf) && - strcmp(ruser, *user ? user : luser) == 0) { - return (0); + /* + * Do +/- and +@/-@ checking. This looks really nasty, + * but it matches SunOS's behavior so far as I can tell. + */ + switch(buf[0]) { + case '+': + if (!buf[1]) { /* '+' matches all hosts */ + hostok = 1; + break; + } + if (buf[1] == '@') /* match a host by netgroup */ + hostok = innetgr((char *)&buf[2], + (char *)&hname, NULL, ypdomain); + else /* match a host by addr */ + hostok = __icheckhost(raddr,(char *)&buf[1]); + break; + case '-': /* reject '-' hosts and all their users */ + if (buf[1] == '@') { + if (innetgr((char *)&buf[2], + (char *)&hname, NULL, ypdomain)) + return(-1); + } else { + if (__icheckhost(raddr,(char *)&buf[1])) + return(-1); + } + break; + default: /* if no '+' or '-', do a simple match */ + hostok = __icheckhost(raddr, buf); + break; + } + switch(*user) { + case '+': + if (!*(user+1)) { /* '+' matches all users */ + userok = 1; + break; + } + if (*(user+1) == '@') /* match a user by netgroup */ + userok = innetgr(user+2, NULL, ruser, ypdomain); + else /* match a user by direct specification */ + userok = !(strcmp(ruser, user+1)); + break; + case '-': /* if we matched a hostname, */ + if (hostok) { /* check for user field rejections */ + if (!*(user+1)) + return(-1); + if (*(user+1) == '@') { + if (innetgr(user+2, NULL, + ruser, ypdomain)) + return(-1); + } else { + if (!strcmp(ruser, user+1)) + return(-1); + } + } + break; + default: /* no rejections: try to match the user */ + if (hostok) + userok = !(strcmp(ruser,*user ? user : luser)); + break; } + if (hostok && userok) + return(0); } return (-1); } |