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