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