rcmd.c revision 17543
11573Srgrimes/*
21573Srgrimes * Copyright (c) 1983, 1993, 1994
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes * 3. All advertising materials mentioning features or use of this software
141573Srgrimes *    must display the following acknowledgement:
151573Srgrimes *	This product includes software developed by the University of
161573Srgrimes *	California, Berkeley and its contributors.
171573Srgrimes * 4. Neither the name of the University nor the names of its contributors
181573Srgrimes *    may be used to endorse or promote products derived from this software
191573Srgrimes *    without specific prior written permission.
201573Srgrimes *
211573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311573Srgrimes * SUCH DAMAGE.
321573Srgrimes */
331573Srgrimes
341573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
351573Srgrimesstatic char sccsid[] = "@(#)rcmd.c	8.3 (Berkeley) 3/26/94";
361573Srgrimes#endif /* LIBC_SCCS and not lint */
371573Srgrimes
381573Srgrimes#include <sys/param.h>
391573Srgrimes#include <sys/socket.h>
401573Srgrimes#include <sys/stat.h>
411573Srgrimes
421573Srgrimes#include <netinet/in.h>
431573Srgrimes#include <arpa/inet.h>
441573Srgrimes
451573Srgrimes#include <signal.h>
461573Srgrimes#include <fcntl.h>
471573Srgrimes#include <netdb.h>
481573Srgrimes#include <unistd.h>
491573Srgrimes#include <pwd.h>
501573Srgrimes#include <errno.h>
511573Srgrimes#include <stdio.h>
521573Srgrimes#include <ctype.h>
531573Srgrimes#include <string.h>
549978Swpaul#ifdef YP
559978Swpaul#include <rpc/rpc.h>
569978Swpaul#include <rpcsvc/yp_prot.h>
579978Swpaul#include <rpcsvc/ypclnt.h>
589978Swpaul#endif
591573Srgrimes
6017141Sjkhextern int innetgr __P(( const char *, const char *, const char *, const char * ));
6117141Sjkh
622592Scsgr#define max(a, b)	((a > b) ? a : b)
632592Scsgr
641573Srgrimesint	__ivaliduser __P((FILE *, u_long, const char *, const char *));
651573Srgrimesstatic int __icheckhost __P((u_long, char *));
661573Srgrimes
671573Srgrimesint
681573Srgrimesrcmd(ahost, rport, locuser, remuser, cmd, fd2p)
691573Srgrimes	char **ahost;
701573Srgrimes	u_short rport;
711573Srgrimes	const char *locuser, *remuser, *cmd;
721573Srgrimes	int *fd2p;
731573Srgrimes{
741573Srgrimes	struct hostent *hp;
751573Srgrimes	struct sockaddr_in sin, from;
761573Srgrimes	fd_set reads;
771573Srgrimes	long oldmask;
781573Srgrimes	pid_t pid;
791573Srgrimes	int s, lport, timo;
801573Srgrimes	char c;
811573Srgrimes
821573Srgrimes	pid = getpid();
831573Srgrimes	hp = gethostbyname(*ahost);
841573Srgrimes	if (hp == NULL) {
851573Srgrimes		herror(*ahost);
861573Srgrimes		return (-1);
871573Srgrimes	}
881573Srgrimes	*ahost = hp->h_name;
891573Srgrimes	oldmask = sigblock(sigmask(SIGURG));
901573Srgrimes	for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
911573Srgrimes		s = rresvport(&lport);
921573Srgrimes		if (s < 0) {
931573Srgrimes			if (errno == EAGAIN)
941573Srgrimes				(void)fprintf(stderr,
951573Srgrimes				    "rcmd: socket: All ports in use\n");
961573Srgrimes			else
971573Srgrimes				(void)fprintf(stderr, "rcmd: socket: %s\n",
981573Srgrimes				    strerror(errno));
991573Srgrimes			sigsetmask(oldmask);
1001573Srgrimes			return (-1);
1011573Srgrimes		}
1021573Srgrimes		fcntl(s, F_SETOWN, pid);
10317543Speter		bzero(&sin, sizeof sin);
10417543Speter		sin.sin_len = sizeof(struct sockaddr_in);
1051573Srgrimes		sin.sin_family = hp->h_addrtype;
10617543Speter		sin.sin_port = rport;
1071573Srgrimes		bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
1081573Srgrimes		if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
1091573Srgrimes			break;
1101573Srgrimes		(void)close(s);
1111573Srgrimes		if (errno == EADDRINUSE) {
1121573Srgrimes			lport--;
1131573Srgrimes			continue;
1141573Srgrimes		}
1151573Srgrimes		if (errno == ECONNREFUSED && timo <= 16) {
1161573Srgrimes			(void)sleep(timo);
1171573Srgrimes			timo *= 2;
1181573Srgrimes			continue;
1191573Srgrimes		}
1201573Srgrimes		if (hp->h_addr_list[1] != NULL) {
1211573Srgrimes			int oerrno = errno;
1221573Srgrimes
1231573Srgrimes			(void)fprintf(stderr, "connect to address %s: ",
1241573Srgrimes			    inet_ntoa(sin.sin_addr));
1251573Srgrimes			errno = oerrno;
1261573Srgrimes			perror(0);
1271573Srgrimes			hp->h_addr_list++;
1281573Srgrimes			bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
1291573Srgrimes			(void)fprintf(stderr, "Trying %s...\n",
1301573Srgrimes			    inet_ntoa(sin.sin_addr));
1311573Srgrimes			continue;
1321573Srgrimes		}
1331573Srgrimes		(void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno));
1341573Srgrimes		sigsetmask(oldmask);
1351573Srgrimes		return (-1);
1361573Srgrimes	}
1371573Srgrimes	lport--;
1381573Srgrimes	if (fd2p == 0) {
1391573Srgrimes		write(s, "", 1);
1401573Srgrimes		lport = 0;
1411573Srgrimes	} else {
1421573Srgrimes		char num[8];
1431573Srgrimes		int s2 = rresvport(&lport), s3;
1441573Srgrimes		int len = sizeof(from);
1452592Scsgr		int nfds;
1461573Srgrimes
1471573Srgrimes		if (s2 < 0)
1481573Srgrimes			goto bad;
1491573Srgrimes		listen(s2, 1);
1501573Srgrimes		(void)snprintf(num, sizeof(num), "%d", lport);
1511573Srgrimes		if (write(s, num, strlen(num)+1) != strlen(num)+1) {
1521573Srgrimes			(void)fprintf(stderr,
1531573Srgrimes			    "rcmd: write (setting up stderr): %s\n",
1541573Srgrimes			    strerror(errno));
1551573Srgrimes			(void)close(s2);
1561573Srgrimes			goto bad;
1571573Srgrimes		}
1582592Scsgr		nfds = max(s, s2)+1;
1592592Scsgr		if(nfds > FD_SETSIZE) {
1602592Scsgr			fprintf(stderr, "rcmd: too many files\n");
1612592Scsgr			(void)close(s2);
1622592Scsgr			goto bad;
1632592Scsgr		}
16417543Speteragain:
1651573Srgrimes		FD_ZERO(&reads);
1661573Srgrimes		FD_SET(s, &reads);
1671573Srgrimes		FD_SET(s2, &reads);
1681573Srgrimes		errno = 0;
1692592Scsgr		if (select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){
1701573Srgrimes			if (errno != 0)
1711573Srgrimes				(void)fprintf(stderr,
1721573Srgrimes				    "rcmd: select (setting up stderr): %s\n",
1731573Srgrimes				    strerror(errno));
1741573Srgrimes			else
1751573Srgrimes				(void)fprintf(stderr,
1761573Srgrimes				"select: protocol failure in circuit setup\n");
1771573Srgrimes			(void)close(s2);
1781573Srgrimes			goto bad;
1791573Srgrimes		}
1801573Srgrimes		s3 = accept(s2, (struct sockaddr *)&from, &len);
18117543Speter		/*
18217543Speter		 * XXX careful for ftp bounce attacks. If discovered, shut them
18317543Speter		 * down and check for the real auxiliary channel to connect.
18417543Speter		 */
18517543Speter		if (from.sin_family == AF_INET && from.sin_port == htons(20)) {
18617543Speter			close(s3);
18717543Speter			goto again;
18817543Speter		}
1891573Srgrimes		(void)close(s2);
1901573Srgrimes		if (s3 < 0) {
1911573Srgrimes			(void)fprintf(stderr,
1921573Srgrimes			    "rcmd: accept: %s\n", strerror(errno));
1931573Srgrimes			lport = 0;
1941573Srgrimes			goto bad;
1951573Srgrimes		}
1961573Srgrimes		*fd2p = s3;
1971573Srgrimes		from.sin_port = ntohs((u_short)from.sin_port);
1981573Srgrimes		if (from.sin_family != AF_INET ||
1991573Srgrimes		    from.sin_port >= IPPORT_RESERVED ||
2001573Srgrimes		    from.sin_port < IPPORT_RESERVED / 2) {
2011573Srgrimes			(void)fprintf(stderr,
2021573Srgrimes			    "socket: protocol failure in circuit setup.\n");
2031573Srgrimes			goto bad2;
2041573Srgrimes		}
2051573Srgrimes	}
2061573Srgrimes	(void)write(s, locuser, strlen(locuser)+1);
2071573Srgrimes	(void)write(s, remuser, strlen(remuser)+1);
2081573Srgrimes	(void)write(s, cmd, strlen(cmd)+1);
2091573Srgrimes	if (read(s, &c, 1) != 1) {
2101573Srgrimes		(void)fprintf(stderr,
2111573Srgrimes		    "rcmd: %s: %s\n", *ahost, strerror(errno));
2121573Srgrimes		goto bad2;
2131573Srgrimes	}
2141573Srgrimes	if (c != 0) {
2151573Srgrimes		while (read(s, &c, 1) == 1) {
2161573Srgrimes			(void)write(STDERR_FILENO, &c, 1);
2171573Srgrimes			if (c == '\n')
2181573Srgrimes				break;
2191573Srgrimes		}
2201573Srgrimes		goto bad2;
2211573Srgrimes	}
2221573Srgrimes	sigsetmask(oldmask);
2231573Srgrimes	return (s);
2241573Srgrimesbad2:
2251573Srgrimes	if (lport)
2261573Srgrimes		(void)close(*fd2p);
2271573Srgrimesbad:
2281573Srgrimes	(void)close(s);
2291573Srgrimes	sigsetmask(oldmask);
2301573Srgrimes	return (-1);
2311573Srgrimes}
2321573Srgrimes
2331573Srgrimesint
2341573Srgrimesrresvport(alport)
2351573Srgrimes	int *alport;
2361573Srgrimes{
2371573Srgrimes	struct sockaddr_in sin;
23817543Speter	int s;
2391573Srgrimes
24017543Speter	bzero(&sin, sizeof sin);
24117543Speter	sin.sin_len = sizeof(struct sockaddr_in);
2421573Srgrimes	sin.sin_family = AF_INET;
2431573Srgrimes	sin.sin_addr.s_addr = INADDR_ANY;
2441573Srgrimes	s = socket(AF_INET, SOCK_STREAM, 0);
2451573Srgrimes	if (s < 0)
2461573Srgrimes		return (-1);
24717543Speter#if 0 /* compat_exact_traditional_rresvport_semantics */
24817543Speter	sin.sin_port = htons((u_short)*alport);
24917543Speter	if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
25017543Speter		return (s);
25117543Speter	if (errno != EADDRINUSE) {
25216034Speter		(void)close(s);
25317543Speter		return (-1);
25416034Speter	}
25517543Speter#endif
25617543Speter	sin.sin_port = 0;
25717543Speter	if (bindresvport(s, &sin) == -1) {
25817543Speter		(void)close(s);
25917543Speter		return (-1);
2601573Srgrimes	}
26117543Speter	*alport = (int)ntohs(sin.sin_port);
26217543Speter	return (s);
2631573Srgrimes}
2641573Srgrimes
2651573Srgrimesint	__check_rhosts_file = 1;
2661573Srgrimeschar	*__rcmd_errstr;
2671573Srgrimes
2681573Srgrimesint
2691573Srgrimesruserok(rhost, superuser, ruser, luser)
2701573Srgrimes	const char *rhost, *ruser, *luser;
2711573Srgrimes	int superuser;
2721573Srgrimes{
2731573Srgrimes	struct hostent *hp;
2741573Srgrimes	u_long addr;
2751573Srgrimes	char **ap;
2761573Srgrimes
2771573Srgrimes	if ((hp = gethostbyname(rhost)) == NULL)
2781573Srgrimes		return (-1);
2791573Srgrimes	for (ap = hp->h_addr_list; *ap; ++ap) {
2801573Srgrimes		bcopy(*ap, &addr, sizeof(addr));
2811573Srgrimes		if (iruserok(addr, superuser, ruser, luser) == 0)
2821573Srgrimes			return (0);
2831573Srgrimes	}
2841573Srgrimes	return (-1);
2851573Srgrimes}
2861573Srgrimes
2871573Srgrimes/*
2881573Srgrimes * New .rhosts strategy: We are passed an ip address. We spin through
2891573Srgrimes * hosts.equiv and .rhosts looking for a match. When the .rhosts only
2901573Srgrimes * has ip addresses, we don't have to trust a nameserver.  When it
2911573Srgrimes * contains hostnames, we spin through the list of addresses the nameserver
2921573Srgrimes * gives us and look for a match.
2931573Srgrimes *
2941573Srgrimes * Returns 0 if ok, -1 if not ok.
2951573Srgrimes */
2961573Srgrimesint
2971573Srgrimesiruserok(raddr, superuser, ruser, luser)
2981573Srgrimes	u_long raddr;
2991573Srgrimes	int superuser;
3001573Srgrimes	const char *ruser, *luser;
3011573Srgrimes{
3021573Srgrimes	register char *cp;
3031573Srgrimes	struct stat sbuf;
3041573Srgrimes	struct passwd *pwd;
3051573Srgrimes	FILE *hostf;
3061573Srgrimes	uid_t uid;
3071573Srgrimes	int first;
3081573Srgrimes	char pbuf[MAXPATHLEN];
3091573Srgrimes
3101573Srgrimes	first = 1;
3111573Srgrimes	hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
3121573Srgrimesagain:
3131573Srgrimes	if (hostf) {
3141573Srgrimes		if (__ivaliduser(hostf, raddr, luser, ruser) == 0) {
3151573Srgrimes			(void)fclose(hostf);
3161573Srgrimes			return (0);
3171573Srgrimes		}
3181573Srgrimes		(void)fclose(hostf);
3191573Srgrimes	}
3201573Srgrimes	if (first == 1 && (__check_rhosts_file || superuser)) {
3211573Srgrimes		first = 0;
3221573Srgrimes		if ((pwd = getpwnam(luser)) == NULL)
3231573Srgrimes			return (-1);
3241573Srgrimes		(void)strcpy(pbuf, pwd->pw_dir);
3251573Srgrimes		(void)strcat(pbuf, "/.rhosts");
3261573Srgrimes
3271573Srgrimes		/*
3281573Srgrimes		 * Change effective uid while opening .rhosts.  If root and
3291573Srgrimes		 * reading an NFS mounted file system, can't read files that
3301573Srgrimes		 * are protected read/write owner only.
3311573Srgrimes		 */
3321573Srgrimes		uid = geteuid();
3331573Srgrimes		(void)seteuid(pwd->pw_uid);
3341573Srgrimes		hostf = fopen(pbuf, "r");
3351573Srgrimes		(void)seteuid(uid);
3361573Srgrimes
3371573Srgrimes		if (hostf == NULL)
3381573Srgrimes			return (-1);
3391573Srgrimes		/*
3401573Srgrimes		 * If not a regular file, or is owned by someone other than
3411573Srgrimes		 * user or root or if writeable by anyone but the owner, quit.
3421573Srgrimes		 */
3431573Srgrimes		cp = NULL;
3441573Srgrimes		if (lstat(pbuf, &sbuf) < 0)
3451573Srgrimes			cp = ".rhosts lstat failed";
3461573Srgrimes		else if (!S_ISREG(sbuf.st_mode))
3471573Srgrimes			cp = ".rhosts not regular file";
3481573Srgrimes		else if (fstat(fileno(hostf), &sbuf) < 0)
3491573Srgrimes			cp = ".rhosts fstat failed";
3501573Srgrimes		else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
3511573Srgrimes			cp = "bad .rhosts owner";
3521573Srgrimes		else if (sbuf.st_mode & (S_IWGRP|S_IWOTH))
3531573Srgrimes			cp = ".rhosts writeable by other than owner";
3541573Srgrimes		/* If there were any problems, quit. */
3551573Srgrimes		if (cp) {
3561573Srgrimes			__rcmd_errstr = cp;
3571573Srgrimes			(void)fclose(hostf);
3581573Srgrimes			return (-1);
3591573Srgrimes		}
3601573Srgrimes		goto again;
3611573Srgrimes	}
3621573Srgrimes	return (-1);
3631573Srgrimes}
3641573Srgrimes
3651573Srgrimes/*
3661573Srgrimes * XXX
3671573Srgrimes * Don't make static, used by lpd(8).
3681573Srgrimes *
3691573Srgrimes * Returns 0 if ok, -1 if not ok.
3701573Srgrimes */
3711573Srgrimesint
3721573Srgrimes__ivaliduser(hostf, raddr, luser, ruser)
3731573Srgrimes	FILE *hostf;
3741573Srgrimes	u_long raddr;
3751573Srgrimes	const char *luser, *ruser;
3761573Srgrimes{
3771573Srgrimes	register char *user, *p;
3781573Srgrimes	int ch;
3791573Srgrimes	char buf[MAXHOSTNAMELEN + 128];		/* host + login */
38010059Swpaul	char hname[MAXHOSTNAMELEN];
3817183Swpaul	struct hostent *hp;
3827183Swpaul	/* Presumed guilty until proven innocent. */
3837183Swpaul	int userok = 0, hostok = 0;
3849978Swpaul#ifdef YP
3859978Swpaul	char *ypdomain;
3861573Srgrimes
3879978Swpaul	if (yp_get_default_domain(&ypdomain))
3889978Swpaul		ypdomain = NULL;
3899978Swpaul#else
3909978Swpaul#define	ypdomain NULL
3919978Swpaul#endif
3927183Swpaul	/* We need to get the damn hostname back for netgroup matching. */
3937183Swpaul	if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long),
3947183Swpaul							AF_INET)) == NULL)
3957183Swpaul		return (-1);
39610059Swpaul	strcpy(hname, hp->h_name);
3977183Swpaul
3981573Srgrimes	while (fgets(buf, sizeof(buf), hostf)) {
3991573Srgrimes		p = buf;
4001573Srgrimes		/* Skip lines that are too long. */
4011573Srgrimes		if (strchr(p, '\n') == NULL) {
4021573Srgrimes			while ((ch = getc(hostf)) != '\n' && ch != EOF);
4031573Srgrimes			continue;
4041573Srgrimes		}
4059552Speter		if (*p == '\n' || *p == '#') {
4069552Speter			/* comment... */
4079552Speter			continue;
4089552Speter		}
4091573Srgrimes		while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
4101573Srgrimes			*p = isupper(*p) ? tolower(*p) : *p;
4111573Srgrimes			p++;
4121573Srgrimes		}
4131573Srgrimes		if (*p == ' ' || *p == '\t') {
4141573Srgrimes			*p++ = '\0';
4151573Srgrimes			while (*p == ' ' || *p == '\t')
4161573Srgrimes				p++;
4171573Srgrimes			user = p;
4181573Srgrimes			while (*p != '\n' && *p != ' ' &&
4191573Srgrimes			    *p != '\t' && *p != '\0')
4201573Srgrimes				p++;
4211573Srgrimes		} else
4221573Srgrimes			user = p;
4231573Srgrimes		*p = '\0';
4247183Swpaul		/*
4257183Swpaul		 * Do +/- and +@/-@ checking. This looks really nasty,
4267183Swpaul		 * but it matches SunOS's behavior so far as I can tell.
4277183Swpaul		 */
4287183Swpaul		switch(buf[0]) {
4297183Swpaul		case '+':
4307183Swpaul			if (!buf[1]) {     /* '+' matches all hosts */
4317183Swpaul				hostok = 1;
4327183Swpaul				break;
4337183Swpaul			}
4347183Swpaul			if (buf[1] == '@')  /* match a host by netgroup */
43510059Swpaul				hostok = innetgr((char *)&buf[2],
43610059Swpaul					(char *)&hname, NULL, ypdomain);
4377183Swpaul			else		/* match a host by addr */
4387183Swpaul				hostok = __icheckhost(raddr,(char *)&buf[1]);
4397183Swpaul			break;
4407183Swpaul		case '-':     /* reject '-' hosts and all their users */
4417183Swpaul			if (buf[1] == '@') {
4427183Swpaul				if (innetgr((char *)&buf[2],
44310059Swpaul					      (char *)&hname, NULL, ypdomain))
4447183Swpaul					return(-1);
4457183Swpaul			} else {
4467183Swpaul				if (__icheckhost(raddr,(char *)&buf[1]))
4477183Swpaul					return(-1);
4487183Swpaul			}
4497183Swpaul			break;
4507183Swpaul		default:  /* if no '+' or '-', do a simple match */
4517183Swpaul			hostok = __icheckhost(raddr, buf);
4527183Swpaul			break;
4531573Srgrimes		}
4547183Swpaul		switch(*user) {
4557183Swpaul		case '+':
4567183Swpaul			if (!*(user+1)) {      /* '+' matches all users */
4577183Swpaul				userok = 1;
4587183Swpaul				break;
4597183Swpaul			}
4607183Swpaul			if (*(user+1) == '@')  /* match a user by netgroup */
4619978Swpaul				userok = innetgr(user+2, NULL, ruser, ypdomain);
4627183Swpaul			else	   /* match a user by direct specification */
4637183Swpaul				userok = !(strcmp(ruser, user+1));
4647183Swpaul			break;
4657183Swpaul		case '-': 		/* if we matched a hostname, */
4667183Swpaul			if (hostok) {   /* check for user field rejections */
4677183Swpaul				if (!*(user+1))
4687183Swpaul					return(-1);
4697183Swpaul				if (*(user+1) == '@') {
4707183Swpaul					if (innetgr(user+2, NULL,
4719978Swpaul							ruser, ypdomain))
4727183Swpaul						return(-1);
4737183Swpaul				} else {
4747183Swpaul					if (!strcmp(ruser, user+1))
4757183Swpaul						return(-1);
4767183Swpaul				}
4777183Swpaul			}
4787183Swpaul			break;
4797183Swpaul		default:	/* no rejections: try to match the user */
4807183Swpaul			if (hostok)
4817183Swpaul				userok = !(strcmp(ruser,*user ? user : luser));
4827183Swpaul			break;
4837183Swpaul		}
4847183Swpaul		if (hostok && userok)
4857183Swpaul			return(0);
4861573Srgrimes	}
4871573Srgrimes	return (-1);
4881573Srgrimes}
4891573Srgrimes
4901573Srgrimes/*
4911573Srgrimes * Returns "true" if match, 0 if no match.
4921573Srgrimes */
4931573Srgrimesstatic int
4941573Srgrimes__icheckhost(raddr, lhost)
4951573Srgrimes	u_long raddr;
4961573Srgrimes	register char *lhost;
4971573Srgrimes{
4981573Srgrimes	register struct hostent *hp;
4991573Srgrimes	register u_long laddr;
5001573Srgrimes	register char **pp;
5011573Srgrimes
5021573Srgrimes	/* Try for raw ip address first. */
5031573Srgrimes	if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1)
5041573Srgrimes		return (raddr == laddr);
5051573Srgrimes
5061573Srgrimes	/* Better be a hostname. */
5071573Srgrimes	if ((hp = gethostbyname(lhost)) == NULL)
5081573Srgrimes		return (0);
5091573Srgrimes
5101573Srgrimes	/* Spin through ip addresses. */
5111573Srgrimes	for (pp = hp->h_addr_list; *pp; ++pp)
5121573Srgrimes		if (!bcmp(&raddr, *pp, sizeof(u_long)))
5131573Srgrimes			return (1);
5141573Srgrimes
5151573Srgrimes	/* No match. */
5161573Srgrimes	return (0);
5171573Srgrimes}
518