Home | History | Annotate | Download | only in inet
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 /*
     31  * University Copyright- Copyright (c) 1982, 1986, 1988
     32  * The Regents of the University of California
     33  * All Rights Reserved
     34  *
     35  * University Acknowledgment- Portions of this document are derived from
     36  * software developed by the University of California, Berkeley, and its
     37  * contributors.
     38  */
     39 
     40 #include <limits.h>
     41 #include <stdio.h>
     42 #include <ctype.h>
     43 #include <pwd.h>
     44 #include <sys/types.h>
     45 #include <sys/param.h>
     46 #include <sys/file.h>
     47 #include <signal.h>
     48 #include <libintl.h>
     49 #include <sys/socket.h>
     50 #include <sys/stat.h>
     51 
     52 #include <netinet/in.h>
     53 #include <netinet/tcp.h>
     54 #include <inet/common.h>
     55 
     56 #include <netdb.h>
     57 #include <errno.h>
     58 #include <fcntl.h>
     59 #include <unistd.h>
     60 #include <string.h>
     61 #include <stdlib.h>
     62 #include <grp.h>
     63 #include <alloca.h>
     64 #include <arpa/inet.h>
     65 
     66 #include <priv_utils.h>
     67 
     68 #ifdef SYSV
     69 #define	bcopy(s1, s2, len)	(void) memcpy(s2, s1, len)
     70 #define	bzero(s, len)		(void) memset(s, 0, len)
     71 #define	index(s, c)		strchr(s, c)
     72 char	*strchr();
     73 #else
     74 char	*index();
     75 #endif /* SYSV */
     76 
     77 extern int  usingypmap();
     78 
     79 static int _validuser(FILE *hostf, char *rhost, const char *luser,
     80 			const char *ruser, int baselen);
     81 static int _checkhost(char *rhost, char *lhost, int len);
     82 
     83 
     84 #ifdef NIS
     85 static char *domain;
     86 #endif
     87 
     88 int rcmd(char **ahost, unsigned short rport, const char *locuser,
     89     const char *remuser, const char *cmd, int *fd2p)
     90 {
     91 	int rcmd_ret;
     92 
     93 	rcmd_ret = rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p,
     94 	    AF_INET);
     95 	return (rcmd_ret);
     96 }
     97 
     98 int rcmd_af(char **ahost, unsigned short rport, const char *locuser,
     99     const char *remuser, const char *cmd, int *fd2p, int af)
    100 {
    101 	int s, timo = 1;
    102 	ssize_t retval;
    103 	pid_t pid;
    104 	struct sockaddr_storage caddr, faddr;
    105 	struct sockaddr_in *sin;
    106 	struct sockaddr_in6 *sin6;
    107 	struct addrinfo hints;
    108 	struct addrinfo *res, *resp;
    109 	size_t addrlen;
    110 	int rc;
    111 #define	MAX_SHORTSTRLEN 6
    112 	char aport[MAX_SHORTSTRLEN];
    113 	char c;
    114 	int lport = 0;
    115 #ifdef SYSV
    116 	sigset_t oldmask;
    117 	sigset_t newmask;
    118 	struct sigaction oldaction;
    119 	struct sigaction newaction;
    120 #else
    121 	int oldmask;
    122 #endif /* SYSV */
    123 	fd_set fdset;
    124 	int selret;
    125 	char *addr;
    126 	static char hostname[MAXHOSTNAMELEN];
    127 	socklen_t len;
    128 	char abuf[INET6_ADDRSTRLEN];
    129 
    130 	if (!(af == AF_INET || af == AF_INET6 || af == AF_UNSPEC)) {
    131 		errno = EAFNOSUPPORT;
    132 		return (-1);
    133 	}
    134 
    135 	pid = getpid();
    136 	memset(&hints, 0, sizeof (hints));
    137 	hints.ai_socktype = SOCK_STREAM;
    138 	hints.ai_flags = AI_CANONNAME;
    139 	if (af == AF_INET6) {
    140 		hints.ai_flags |= AI_V4MAPPED;
    141 		hints.ai_family = AF_UNSPEC;
    142 	} else {
    143 		hints.ai_family = af;
    144 	}
    145 	(void) snprintf(aport, MAX_SHORTSTRLEN, "%u", ntohs(rport));
    146 	rc = getaddrinfo(*ahost, aport, &hints, &res);
    147 	if (rc != 0) {
    148 		(void) fprintf(stderr,
    149 		    dgettext(TEXT_DOMAIN, "%s: unknown host%s\n"),
    150 		    *ahost, rc == EAI_AGAIN ? " (try again later)" : "");
    151 		return (-1);
    152 	}
    153 	resp = res;
    154 	(void) strlcpy(hostname, res->ai_canonname, MAXHOSTNAMELEN);
    155 	*ahost = hostname;
    156 #ifdef SYSV
    157 	/* ignore SIGPIPE */
    158 	bzero((char *)&newaction, sizeof (newaction));
    159 	newaction.sa_handler = SIG_IGN;
    160 	(void) sigaction(SIGPIPE, &newaction, &oldaction);
    161 
    162 	/* block SIGURG */
    163 	bzero((char *)&newmask, sizeof (newmask));
    164 	(void) sigaddset(&newmask, SIGURG);
    165 	(void) sigprocmask(SIG_BLOCK, &newmask, &oldmask);
    166 #else
    167 	oldmask = _sigblock(sigmask(SIGURG));
    168 #endif /* SYSV */
    169 	for (;;) {
    170 		s = rresvport_af(&lport, res->ai_family);
    171 		if (s < 0) {
    172 			int af = res->ai_family;
    173 
    174 			/*
    175 			 * See if we have any addresses of a different type
    176 			 * to try.
    177 			 */
    178 			while (res != NULL && res->ai_family == af)
    179 				res = res->ai_next;
    180 
    181 			if (res != NULL)
    182 				continue;
    183 
    184 			if (errno == EAGAIN)
    185 				(void) fprintf(stderr,
    186 				    dgettext(TEXT_DOMAIN,
    187 				    "socket: All ports in use\n"));
    188 			else
    189 				perror("rcmd: socket");
    190 #ifdef SYSV
    191 			/* restore original SIGPIPE handler */
    192 			(void) sigaction(SIGPIPE, &oldaction,
    193 			    (struct sigaction *)0);
    194 
    195 			/* restore original signal mask */
    196 			(void) sigprocmask(SIG_SETMASK, &oldmask,
    197 			    (sigset_t *)0);
    198 #else
    199 			sigsetmask(oldmask);
    200 #endif /* SYSV */
    201 			freeaddrinfo(resp);
    202 			return (-1);
    203 		}
    204 		bzero((char *)&caddr, sizeof (caddr));
    205 		bcopy(res->ai_addr, &caddr, res->ai_addrlen);
    206 		addrlen = res->ai_addrlen;
    207 		if (af == AF_INET6 && res->ai_addr->sa_family == AF_INET) {
    208 			struct in6_addr ia6;
    209 			struct sockaddr_in6 *in6addr;
    210 			IN6_INADDR_TO_V4MAPPED(&((struct sockaddr_in *)
    211 			    res->ai_addr)->sin_addr, &ia6);
    212 			in6addr = (struct sockaddr_in6 *)&caddr;
    213 			in6addr->sin6_addr = ia6;
    214 			in6addr->sin6_family = AF_INET6;
    215 			addrlen = sizeof (struct sockaddr_in6);
    216 		}
    217 		(void) fcntl(s, F_SETOWN, pid);
    218 		if (connect(s, (struct sockaddr *)&caddr, addrlen) >= 0)
    219 			break;
    220 		(void) close(s);
    221 		if (errno == EADDRINUSE) {
    222 			lport = 0;
    223 			continue;
    224 		}
    225 		if (errno == ECONNREFUSED && timo <= 16) {
    226 			(void) sleep(timo);
    227 			timo *= 2;
    228 			continue;
    229 		}
    230 		if (res->ai_next != NULL) {
    231 			int oerrno = errno;
    232 			if (res->ai_addr->sa_family == AF_INET6)
    233 				addr = (char *)&((struct sockaddr_in6 *)
    234 				    res->ai_addr)->sin6_addr;
    235 			else
    236 				addr = (char *)&((struct sockaddr_in *)
    237 				    res->ai_addr)->sin_addr;
    238 			(void) fprintf(stderr,
    239 			    dgettext(TEXT_DOMAIN, "connect to address %s: "),
    240 			    inet_ntop(res->ai_addr->sa_family, addr,
    241 			    abuf, sizeof (abuf)));
    242 			errno = oerrno;
    243 			perror(0);
    244 			res = res->ai_next;
    245 			if (res->ai_addr->sa_family == AF_INET6)
    246 				addr = (char *)&((struct sockaddr_in6 *)
    247 				    res->ai_addr)->sin6_addr;
    248 			else
    249 				addr = (char *)&((struct sockaddr_in *)
    250 				    res->ai_addr)->sin_addr;
    251 			(void) fprintf(stderr,
    252 			    dgettext(TEXT_DOMAIN, "Trying %s...\n"),
    253 			    inet_ntop(res->ai_addr->sa_family, addr,
    254 			    abuf, sizeof (abuf)));
    255 			continue;
    256 		}
    257 		perror(*ahost);
    258 		freeaddrinfo(resp);
    259 #ifdef SYSV
    260 		/* restore original SIGPIPE handler */
    261 		(void) sigaction(SIGPIPE, &oldaction,
    262 		    (struct sigaction *)0);
    263 
    264 		/* restore original signal mask */
    265 		(void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
    266 #else
    267 		sigsetmask(oldmask);
    268 #endif /* SYSV */
    269 		return (-1);
    270 	}
    271 	lport = 0;
    272 	if (fd2p == 0) {
    273 		(void) write(s, "", 1);
    274 	} else {
    275 		int s2 = rresvport_af(&lport, res->ai_family), s3;
    276 
    277 		len = (socklen_t)sizeof (faddr);
    278 
    279 		if (s2 < 0)
    280 			goto bad;
    281 		(void) listen(s2, 1);
    282 		(void) snprintf(aport, MAX_SHORTSTRLEN, "%d", lport);
    283 		if (write(s, aport, strlen(aport)+1) != strlen(aport)+1) {
    284 			perror(dgettext(TEXT_DOMAIN,
    285 			    "write: setting up stderr"));
    286 			(void) close(s2);
    287 			goto bad;
    288 		}
    289 		FD_ZERO(&fdset);
    290 		FD_SET(s, &fdset);
    291 		FD_SET(s2, &fdset);
    292 		while ((selret = select(FD_SETSIZE, &fdset, (fd_set *)0,
    293 		    (fd_set *)0, (struct timeval *)0)) > 0) {
    294 			if (FD_ISSET(s, &fdset)) {
    295 				/*
    296 				 *	Something's wrong:  we should get no
    297 				 *	data on this connection at this point,
    298 				 *	so we assume that the connection has
    299 				 *	gone away.
    300 				 */
    301 				(void) close(s2);
    302 				goto bad;
    303 			}
    304 			if (FD_ISSET(s2, &fdset)) {
    305 				/*
    306 				 *	We assume this is an incoming connect
    307 				 *	request and proceed normally.
    308 				 */
    309 				s3 = accept(s2, (struct sockaddr *)&faddr,
    310 				    &len);
    311 				FD_CLR(s2, &fdset);
    312 				(void) close(s2);
    313 				if (s3 < 0) {
    314 					perror("accept");
    315 					lport = 0;
    316 					goto bad;
    317 				}
    318 				else
    319 					break;
    320 			}
    321 		}
    322 		if (selret == -1) {
    323 			/*
    324 			 *	This should not happen, and we treat it as
    325 			 *	a fatal error.
    326 			 */
    327 			(void) close(s2);
    328 			goto bad;
    329 		}
    330 
    331 		*fd2p = s3;
    332 		switch (faddr.ss_family) {
    333 		case AF_INET:
    334 			sin = (struct sockaddr_in *)&faddr;
    335 			if (ntohs(sin->sin_port) >= IPPORT_RESERVED) {
    336 				(void) fprintf(stderr,
    337 				    dgettext(TEXT_DOMAIN,
    338 				    "socket: protocol failure in circuit "
    339 				    "setup.\n"));
    340 				goto bad2;
    341 			}
    342 			break;
    343 		case AF_INET6:
    344 			sin6 = (struct sockaddr_in6 *)&faddr;
    345 			if (ntohs(sin6->sin6_port) >= IPPORT_RESERVED) {
    346 				(void) fprintf(stderr,
    347 				    dgettext(TEXT_DOMAIN,
    348 				    "socket: protocol failure in circuit "
    349 				    "setup.\n"));
    350 				goto bad2;
    351 			}
    352 			break;
    353 		default:
    354 			(void) fprintf(stderr,
    355 			    dgettext(TEXT_DOMAIN,
    356 			    "socket: protocol failure in circuit setup.\n"));
    357 			goto bad2;
    358 		}
    359 	}
    360 	(void) write(s, locuser, strlen(locuser)+1);
    361 	(void) write(s, remuser, strlen(remuser)+1);
    362 	(void) write(s, cmd, strlen(cmd)+1);
    363 	retval = read(s, &c, 1);
    364 	if (retval != 1) {
    365 		if (retval == 0) {
    366 			(void) fprintf(stderr,
    367 			    dgettext(TEXT_DOMAIN,
    368 			    "Protocol error, %s closed connection\n"),
    369 			    *ahost);
    370 		} else if (retval < 0) {
    371 			perror(*ahost);
    372 		} else {
    373 			(void) fprintf(stderr,
    374 			    dgettext(TEXT_DOMAIN,
    375 			    "Protocol error, %s sent %d bytes\n"),
    376 			    *ahost, retval);
    377 		}
    378 		goto bad2;
    379 	}
    380 	if (c != 0) {
    381 		while (read(s, &c, 1) == 1) {
    382 			(void) write(2, &c, 1);
    383 			if (c == '\n')
    384 				break;
    385 		}
    386 		goto bad2;
    387 	}
    388 #ifdef SYSV
    389 	/* restore original SIGPIPE handler */
    390 	(void) sigaction(SIGPIPE, &oldaction, (struct sigaction *)0);
    391 
    392 	/* restore original signal mask */
    393 	(void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
    394 #else
    395 	sigsetmask(oldmask);
    396 #endif /* SYSV */
    397 	freeaddrinfo(resp);
    398 	return (s);
    399 bad2:
    400 	if (lport)
    401 		(void) close(*fd2p);
    402 bad:
    403 	(void) close(s);
    404 #ifdef SYSV
    405 	/* restore original SIGPIPE handler */
    406 	(void) sigaction(SIGPIPE, &oldaction, (struct sigaction *)0);
    407 
    408 	/* restore original signal mask */
    409 	(void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
    410 #else
    411 	sigsetmask(oldmask);
    412 #endif /* SYSV */
    413 	freeaddrinfo(resp);
    414 	return (-1);
    415 }
    416 
    417 static int
    418 _rresvport_addr(int *alport, struct sockaddr_storage *addr)
    419 {
    420 	struct sockaddr_in *sin;
    421 	struct sockaddr_in6 *sin6;
    422 	int s;
    423 	socklen_t len;
    424 	int on = 1;
    425 	int off = 0;
    426 
    427 	if (addr->ss_family == AF_INET) {
    428 		sin = (struct sockaddr_in *)addr;
    429 		len = sizeof (struct sockaddr_in);
    430 	} else if (addr->ss_family == AF_INET6) {
    431 		sin6 = (struct sockaddr_in6 *)addr;
    432 		len = sizeof (struct sockaddr_in6);
    433 	} else {
    434 		errno = EAFNOSUPPORT;
    435 		return (-1);
    436 	}
    437 	s = socket(addr->ss_family, SOCK_STREAM, 0);
    438 	if (s < 0)
    439 		return (-1);
    440 
    441 	/*
    442 	 * Set SO_EXCLBIND to get a "unique" port, which is not bound
    443 	 * to any other sockets.
    444 	 */
    445 	if (setsockopt(s, SOL_SOCKET, SO_EXCLBIND, &on, sizeof (on)) < 0) {
    446 		(void) close(s);
    447 		return (-1);
    448 	}
    449 
    450 	/* Try to bind() to the given port first. */
    451 	if (*alport != 0) {
    452 		if (addr->ss_family == AF_INET) {
    453 			sin->sin_port = htons((ushort_t)*alport);
    454 		} else {
    455 			sin6->sin6_port = htons((ushort_t)*alport);
    456 		}
    457 		if (bind(s, (struct sockaddr *)addr, len) >= 0) {
    458 			/* To be safe, need to turn off SO_EXCLBIND. */
    459 			(void) setsockopt(s, SOL_SOCKET, SO_EXCLBIND, &off,
    460 			    sizeof (off));
    461 			return (s);
    462 		}
    463 		if (errno != EADDRINUSE) {
    464 			(void) close(s);
    465 			return (-1);
    466 		}
    467 	}
    468 
    469 	/*
    470 	 * If no port is given or the above bind() does not succeed, set
    471 	 * TCP_ANONPRIVBIND option to ask the kernel to pick a port in the
    472 	 * priviledged range for us.
    473 	 */
    474 	if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on,
    475 	    sizeof (on)) < 0) {
    476 		(void) close(s);
    477 		return (-1);
    478 	}
    479 	if (addr->ss_family == AF_INET) {
    480 		sin->sin_port = 0;
    481 	} else {
    482 		sin6->sin6_port = 0;
    483 	}
    484 	if (bind(s, (struct sockaddr *)addr, len) >= 0) {
    485 		/*
    486 		 * We need to tell the caller what the port is.
    487 		 */
    488 		if (getsockname(s, (struct sockaddr *)addr, &len) < 0) {
    489 			(void) close(s);
    490 			return (-1);
    491 		}
    492 		switch (addr->ss_family) {
    493 		case AF_INET6:
    494 			sin6 = (struct sockaddr_in6 *)addr;
    495 			*alport = ntohs(sin6->sin6_port);
    496 			break;
    497 		case AF_INET:
    498 			sin = (struct sockaddr_in *)addr;
    499 			*alport = ntohs(sin->sin_port);
    500 			break;
    501 		}
    502 
    503 		/*
    504 		 * To be safe, always turn off these options when we are done.
    505 		 */
    506 		(void) setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &off,
    507 		    sizeof (off));
    508 		(void) setsockopt(s, SOL_SOCKET, SO_EXCLBIND, &off,
    509 		    sizeof (off));
    510 		return (s);
    511 	}
    512 	(void) close(s);
    513 	return (-1);
    514 }
    515 
    516 int
    517 rresvport_addr(int *alport, struct sockaddr_storage *addr)
    518 {
    519 	int res, err;
    520 
    521 	(void) __priv_bracket(PRIV_ON);
    522 
    523 	res = _rresvport_addr(alport, addr);
    524 
    525 	err = errno;
    526 	(void) __priv_bracket(PRIV_OFF);
    527 	errno = err;
    528 
    529 	return (res);
    530 }
    531 
    532 int
    533 rresvport_af(int *alport, int af)
    534 {
    535 	struct sockaddr_storage laddr;
    536 
    537 	bzero(&laddr, sizeof (laddr));
    538 	if (af == AF_INET || af == AF_INET6) {
    539 		laddr.ss_family = (sa_family_t)af;
    540 	} else {
    541 		errno = EAFNOSUPPORT;
    542 		return (-1);
    543 	}
    544 	return (rresvport_addr(alport, &laddr));
    545 }
    546 
    547 int
    548 rresvport(int *alport)
    549 {
    550 	return (rresvport_af(alport, AF_INET));
    551 }
    552 
    553 int
    554 ruserok(const char *rhost, int superuser, const char *ruser, const char *luser)
    555 {
    556 	FILE *hostf;
    557 	char fhost[MAXHOSTNAMELEN];
    558 	const char *sp;
    559 	char *p;
    560 	int baselen = -1;
    561 
    562 	struct stat64 sbuf;
    563 	struct passwd *pwd;
    564 	char pbuf[MAXPATHLEN];
    565 	uid_t uid = (uid_t)-1;
    566 	gid_t gid = (gid_t)-1;
    567 	int maxgrp = getgroups(0, NULL);
    568 	gid_t *grouplist = alloca(maxgrp * sizeof (gid_t));
    569 	int ngroups;
    570 
    571 	sp = rhost;
    572 	p = fhost;
    573 	while (*sp) {
    574 		if (*sp == '.') {
    575 			if (baselen == -1)
    576 				baselen = (int)(sp - rhost);
    577 			*p++ = *sp++;
    578 		} else {
    579 			*p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
    580 		}
    581 	}
    582 	*p = '\0';
    583 
    584 	/* check /etc/hosts.equiv */
    585 	if (!superuser) {
    586 		if ((hostf = fopen("/etc/hosts.equiv", "rF")) != NULL) {
    587 			if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
    588 				(void) fclose(hostf);
    589 				return (0);
    590 			}
    591 			(void) fclose(hostf);
    592 		}
    593 	}
    594 
    595 	/* check ~/.rhosts */
    596 
    597 	if ((pwd = getpwnam(luser)) == NULL)
    598 		return (-1);
    599 	(void) strcpy(pbuf, pwd->pw_dir);
    600 	(void) strcat(pbuf, "/.rhosts");
    601 
    602 	/*
    603 	 * Read .rhosts as the local user to avoid NFS mapping the root uid
    604 	 * to something that can't read .rhosts.
    605 	 */
    606 	gid = getegid();
    607 	uid = geteuid();
    608 	if ((ngroups = getgroups(maxgrp, grouplist)) == -1)
    609 		return (-1);
    610 
    611 	(void) setegid(pwd->pw_gid);
    612 	initgroups(pwd->pw_name, pwd->pw_gid);
    613 	(void) seteuid(pwd->pw_uid);
    614 	if ((hostf = fopen(pbuf, "rF")) == NULL) {
    615 		if (gid != (gid_t)-1)
    616 			(void) setegid(gid);
    617 		if (uid != (uid_t)-1)
    618 			(void) seteuid(uid);
    619 		setgroups(ngroups, grouplist);
    620 		return (-1);
    621 	}
    622 	(void) fstat64(fileno(hostf), &sbuf);
    623 	if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) {
    624 		(void) fclose(hostf);
    625 		if (gid != (gid_t)-1)
    626 			(void) setegid(gid);
    627 		if (uid != (uid_t)-1)
    628 			(void) seteuid(uid);
    629 		setgroups(ngroups, grouplist);
    630 		return (-1);
    631 	}
    632 
    633 	if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
    634 		(void) fclose(hostf);
    635 		if (gid != (gid_t)-1)
    636 			(void) setegid(gid);
    637 		if (uid != (uid_t)-1)
    638 			(void) seteuid(uid);
    639 		setgroups(ngroups, grouplist);
    640 		return (0);
    641 	}
    642 
    643 	(void) fclose(hostf);
    644 	if (gid != (gid_t)-1)
    645 		(void) setegid(gid);
    646 	if (uid != (uid_t)-1)
    647 		(void) seteuid(uid);
    648 	setgroups(ngroups, grouplist);
    649 	return (-1);
    650 }
    651 
    652 static int
    653 _validuser(FILE *hostf, char *rhost, const char *luser,
    654     const char *ruser, int baselen)
    655 {
    656 	char *user;
    657 	char ahost[BUFSIZ];
    658 	char *uchost = (char *)NULL;
    659 	int hostmatch, usermatch;
    660 	char *p;
    661 
    662 #ifdef NIS
    663 	if (domain == NULL) {
    664 		(void) usingypmap(&domain, NULL);
    665 	}
    666 #endif /* NIS */
    667 
    668 	while (fgets(ahost, (int)sizeof (ahost), hostf)) {
    669 		uchost = (char *)NULL;
    670 		hostmatch = usermatch = 0;
    671 		p = ahost;
    672 		/*
    673 		 * We can get a line bigger than our buffer.  If so we skip
    674 		 * the offending line.
    675 		 */
    676 		if (strchr(p, '\n') == NULL) {
    677 			while (fgets(ahost, (int)sizeof (ahost), hostf) &&
    678 			    strchr(ahost, '\n') == NULL)
    679 				;
    680 			continue;
    681 		}
    682 		while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
    683 			/*
    684 			 *	Both host and user ``names'' can be netgroups,
    685 			 *	and must have their case preserved.  Case is
    686 			 *	preserved for user names because we break out
    687 			 *	of this loop when finding a field separator.
    688 			 *	To do so for host names, we must make a copy of
    689 			 *	the host name field.
    690 			 */
    691 			if (isupper(*p)) {
    692 				if (uchost == (char *)NULL)
    693 					uchost = strdup(ahost);
    694 				*p = tolower(*p);
    695 			}
    696 			p++;
    697 		}
    698 		if (*p != '\0' && uchost != (char *)NULL)
    699 			uchost[p - ahost] = '\0';
    700 		if (*p == ' ' || *p == '\t') {
    701 			*p++ = '\0';
    702 			while (*p == ' ' || *p == '\t')
    703 				p++;
    704 			user = p;
    705 			while (*p != '\n' && *p != ' ' && *p != '\t' &&
    706 			    *p != '\0')
    707 				p++;
    708 		} else
    709 			user = p;
    710 		*p = '\0';
    711 		if (ahost[0] == '+' && ahost[1] == 0)
    712 			hostmatch = 1;
    713 #ifdef NIS
    714 		else if (ahost[0] == '+' && ahost[1] == '@')
    715 			if (uchost != (char *)NULL)
    716 				hostmatch = innetgr(uchost + 2, rhost,
    717 				    NULL, domain);
    718 			else
    719 				hostmatch = innetgr(ahost + 2, rhost,
    720 				    NULL, domain);
    721 		else if (ahost[0] == '-' && ahost[1] == '@') {
    722 			if (uchost != (char *)NULL) {
    723 				if (innetgr(uchost + 2, rhost, NULL, domain))
    724 					break;
    725 			} else {
    726 				if (innetgr(ahost + 2, rhost, NULL, domain))
    727 					break;
    728 			}
    729 		}
    730 #endif /* NIS */
    731 		else if (ahost[0] == '-') {
    732 			if (_checkhost(rhost, ahost+1, baselen))
    733 				break;
    734 		}
    735 		else
    736 			hostmatch = _checkhost(rhost, ahost, baselen);
    737 		if (user[0]) {
    738 			if (user[0] == '+' && user[1] == 0)
    739 				usermatch = 1;
    740 #ifdef NIS
    741 			else if (user[0] == '+' && user[1] == '@')
    742 				usermatch = innetgr(user+2, NULL,
    743 				    ruser, domain);
    744 			else if (user[0] == '-' && user[1] == '@') {
    745 				if (hostmatch &&
    746 				    innetgr(user+2, NULL, ruser, domain))
    747 					break;
    748 			}
    749 #endif /* NIS */
    750 			else if (user[0] == '-') {
    751 				if (hostmatch && (strcmp(user+1, ruser) == 0))
    752 					break;
    753 			}
    754 			else
    755 				usermatch = (strcmp(user, ruser) == 0);
    756 		}
    757 		else
    758 			usermatch = (strcmp(ruser, luser) == 0);
    759 		if (uchost != (char *)NULL)
    760 			free(uchost);
    761 		if (hostmatch && usermatch)
    762 			return (0);
    763 	}
    764 
    765 	if (uchost != (char *)NULL)
    766 		free(uchost);
    767 	return (-1);
    768 }
    769 
    770 static int
    771 _checkhost(char *rhost, char *lhost, int len)
    772 {
    773 	static char *ldomain;
    774 	static char *domainp;
    775 	static int nodomain;
    776 	char *cp;
    777 
    778 	if (ldomain == NULL) {
    779 		ldomain = (char *)malloc(MAXHOSTNAMELEN+1);
    780 		if (ldomain == 0)
    781 			return (0);
    782 	}
    783 
    784 	if (len == -1)
    785 		return (strcmp(rhost, lhost) == 0);
    786 	if (strncmp(rhost, lhost, len))
    787 		return (0);
    788 	if (strcmp(rhost, lhost) == 0)
    789 		return (1);
    790 	if (*(lhost + len) != '\0')
    791 		return (0);
    792 	if (nodomain)
    793 		return (0);
    794 	if (!domainp) {
    795 		/*
    796 		 * "domainp" points after the first dot in the host name
    797 		 */
    798 		if (gethostname(ldomain, MAXHOSTNAMELEN) == -1) {
    799 			nodomain = 1;
    800 			return (0);
    801 		}
    802 		ldomain[MAXHOSTNAMELEN] = NULL;
    803 		if ((domainp = index(ldomain, '.')) == (char *)NULL) {
    804 			nodomain = 1;
    805 			return (0);
    806 		}
    807 		domainp++;
    808 		cp = domainp;
    809 		while (*cp) {
    810 			*cp = isupper(*cp) ? tolower(*cp) : *cp;
    811 			cp++;
    812 		}
    813 	}
    814 	return (strcmp(domainp, rhost + len + 1) == 0);
    815 }
    816