xref: /titanic_44/usr/src/lib/libbc/libc/net/rcmd.c (revision 9dd0f810214fdc8e1af881a9a5c4b6927629ff9e)
1 /*
2  * Copyright 1995 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*
7  * Copyright (c) 1983 Regents of the University of California.
8  * All rights reserved.  The Berkeley software License Agreement
9  * specifies the terms and conditions for redistribution.
10  */
11 
12 #pragma ident	"%Z%%M%	%I%	%E% SMI"
13 
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <pwd.h>
17 #include <sys/param.h>
18 #include <sys/file.h>
19 #include <sys/signal.h>
20 #include <sys/socket.h>
21 #include <sys/stat.h>
22 
23 #include <netinet/in.h>
24 
25 #include <netdb.h>
26 #include <errno.h>
27 
28 #include <strings.h>
29 
30 static char *domain;
31 
32 int
33 rcmd(
34 	char **ahost,
35 	unsigned short rport,
36 	const char *locuser,
37 	const char *remuser,
38 	const char *cmd,
39 	int *fd2p)
40 {
41 	int s, timo = 1, pid, oldmask, retval;
42 	struct sockaddr_in sin, from;
43 	char c;
44 	int lport = IPPORT_RESERVED - 1;
45 	struct hostent *hp;
46 
47 	pid = getpid();
48 	hp = gethostbyname(*ahost);
49 	if (hp == 0) {
50 		fprintf(stderr, "%s: unknown host\n", *ahost);
51 		return (-1);
52 	}
53 	*ahost = hp->h_name;
54 	oldmask = sigblock(sigmask(SIGURG));
55 	for (;;) {
56 		s = rresvport(&lport);
57 		if (s < 0) {
58 			if (errno == EAGAIN)
59 				fprintf(stderr, "socket: All ports in use\n");
60 			else
61 				perror("rcmd: socket");
62 			sigsetmask(oldmask);
63 			return (-1);
64 		}
65 		fcntl(s, F_SETOWN, pid);
66 		sin.sin_family = hp->h_addrtype;
67 		bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
68 		sin.sin_port = rport;
69 		if (connect(s, &sin, sizeof (sin)) >= 0)
70 			break;
71 		(void) close(s);
72 		if (errno == EADDRINUSE) {
73 			lport--;
74 			continue;
75 		}
76 		if (errno == ECONNREFUSED && timo <= 16) {
77 			sleep(timo);
78 			timo *= 2;
79 			continue;
80 		}
81 		if (hp->h_addr_list[1] != NULL) {
82 			int oerrno = errno;
83 
84 			fprintf(stderr,
85 			    "connect to address %s: ", inet_ntoa(sin.sin_addr));
86 			errno = oerrno;
87 			perror(0);
88 			hp->h_addr_list++;
89 			bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
90 			    hp->h_length);
91 			fprintf(stderr, "Trying %s...\n",
92 				inet_ntoa(sin.sin_addr));
93 			continue;
94 		}
95 		perror(hp->h_name);
96 		sigsetmask(oldmask);
97 		return (-1);
98 	}
99 	lport--;
100 	if (fd2p == 0) {
101 		write(s, "", 1);
102 		lport = 0;
103 	} else {
104 		char num[8];
105 		int s2 = rresvport(&lport), s3;
106 		int len = sizeof (from);
107 
108 		if (s2 < 0)
109 			goto bad;
110 		listen(s2, 1);
111 		(void) sprintf(num, "%d", lport);
112 		if (write(s, num, strlen(num)+1) != strlen(num)+1) {
113 			perror("write: setting up stderr");
114 			(void) close(s2);
115 			goto bad;
116 		}
117 		s3 = accept(s2, &from, &len);
118 		(void) close(s2);
119 		if (s3 < 0) {
120 			perror("accept");
121 			lport = 0;
122 			goto bad;
123 		}
124 		*fd2p = s3;
125 		from.sin_port = ntohs((u_short)from.sin_port);
126 		if (from.sin_family != AF_INET ||
127 		    from.sin_port >= IPPORT_RESERVED) {
128 			fprintf(stderr,
129 			    "socket: protocol failure in circuit setup.\n");
130 			goto bad2;
131 		}
132 	}
133 	(void) write(s, locuser, strlen(locuser)+1);
134 	(void) write(s, remuser, strlen(remuser)+1);
135 	(void) write(s, cmd, strlen(cmd)+1);
136 	retval = read(s, &c, 1);
137 	if (retval != 1) {
138 		if (retval == 0) {
139 		    fprintf(stderr,
140 		      "Protocol error, %s closed connection\n", *ahost);
141 		} else if (retval < 0) {
142 		    perror(*ahost);
143 		} else {
144 		    fprintf(stderr,
145 		      "Protocol error, %s sent %d bytes\n", *ahost, retval);
146 		}
147 		goto bad2;
148 	}
149 	if (c != 0) {
150 		while (read(s, &c, 1) == 1) {
151 			(void) write(2, &c, 1);
152 			if (c == '\n')
153 				break;
154 		}
155 		goto bad2;
156 	}
157 	sigsetmask(oldmask);
158 	return (s);
159 bad2:
160 	if (lport)
161 		(void) close(*fd2p);
162 bad:
163 	(void) close(s);
164 	sigsetmask(oldmask);
165 	return (-1);
166 }
167 
168 int
169 rresvport(int *alport)
170 {
171 	struct sockaddr_in sin;
172 	int s;
173 
174 	sin.sin_family = AF_INET;
175 	sin.sin_addr.s_addr = INADDR_ANY;
176 	s = socket(AF_INET, SOCK_STREAM, 0);
177 	if (s < 0)
178 		return (-1);
179 	for (;;) {
180 		sin.sin_port = htons((u_short)*alport);
181 		if (bind(s, (caddr_t)&sin, sizeof (sin)) >= 0)
182 			return (s);
183 		if (errno != EADDRINUSE) {
184 			(void) close(s);
185 			return (-1);
186 		}
187 		(*alport)--;
188 		if (*alport == IPPORT_RESERVED/2) {
189 			(void) close(s);
190 			errno = EAGAIN;		/* close */
191 			return (-1);
192 		}
193 	}
194 }
195 
196 int
197 ruserok(
198 	const char *rhost,
199 	int superuser,
200 	const char *ruser,
201 	const char *luser)
202 {
203 	FILE *hostf;
204 	char fhost[MAXHOSTNAMELEN];
205 	const char *sp;
206 	char *p;
207 	int baselen = -1;
208 
209 	struct stat sbuf;
210 	struct passwd *pwd;
211 	char pbuf[MAXPATHLEN];
212 	int euid = -1;
213 
214 	sp = rhost;
215 	p = fhost;
216 	while (*sp) {
217 		if (*sp == '.') {
218 			if (baselen == -1)
219 				baselen = sp - rhost;
220 			*p++ = *sp++;
221 		} else {
222 			*p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
223 		}
224 	}
225 	*p = '\0';
226 
227 	/* check /etc/hosts.equiv */
228 	if (!superuser) {
229 		if ((hostf = fopen("/etc/hosts.equiv", "r")) != NULL) {
230 			if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
231 				(void) fclose(hostf);
232 				return(0);
233 		        }
234 			(void) fclose(hostf);
235 		}
236 	}
237 
238 	/* check ~/.rhosts */
239 
240 	if ((pwd = getpwnam(luser)) == NULL)
241        		return(-1);
242 	(void)strcpy(pbuf, pwd->pw_dir);
243 	(void)strcat(pbuf, "/.rhosts");
244 
245 	/*
246 	 * Read .rhosts as the local user to avoid NFS mapping the root uid
247 	 * to something that can't read .rhosts.
248 	 */
249 	euid = geteuid();
250 	(void) seteuid (pwd->pw_uid);
251 	if ((hostf = fopen(pbuf, "r")) == NULL) {
252 		if (euid != -1)
253 	    		(void) seteuid (euid);
254 	  	return(-1);
255 	}
256 	(void)fstat(fileno(hostf), &sbuf);
257 	if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) {
258 	  	fclose(hostf);
259 		if (euid != -1)
260 		  	(void) seteuid (euid);
261 		return(-1);
262 	}
263 
264 	if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
265 	  	(void) fclose(hostf);
266 		if (euid != -1)
267 			(void) seteuid (euid);
268 		return(0);
269 	}
270 
271 	(void) fclose(hostf);
272 	if (euid != -1)
273        		(void) seteuid (euid);
274 	return (-1);
275 }
276 
277 int
278 _validuser(FILE *hostf, char *rhost, char *luser, char *ruser, int baselen)
279 {
280 	char *user;
281 	char ahost[MAXHOSTNAMELEN];
282 	int hostmatch, usermatch;
283 	char *p;
284 
285 	if (domain == NULL) {
286                 (void) yp_get_default_domain(&domain);
287         }
288 	while (fgets(ahost, sizeof (ahost), hostf)) {
289 		hostmatch = usermatch = 0;	/* bugid fix 1033104 */
290 		p = ahost;
291 		while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
292 			*p = isupper(*p) ? tolower(*p) : *p;
293 			p++;
294 		}
295 		if (*p == ' ' || *p == '\t') {
296 			*p++ = '\0';
297 			while (*p == ' ' || *p == '\t')
298 				p++;
299 			user = p;
300 			while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
301 				p++;
302 		} else
303 			user = p;
304 		*p = '\0';
305 		if (ahost[0] == '+' && ahost[1] == 0)
306 			hostmatch = 1;
307 		else if (ahost[0] == '+' && ahost[1] == '@')
308 			hostmatch = innetgr(ahost + 2, rhost,
309 			    NULL, domain);
310 		else if (ahost[0] == '-' && ahost[1] == '@') {
311 			if (innetgr(ahost + 2, rhost, NULL, domain))
312 				break;
313 		}
314 		else if (ahost[0] == '-') {
315 			if (_checkhost(rhost, ahost+1, baselen))
316 				break;
317 		}
318 		else
319 			hostmatch = _checkhost(rhost, ahost, baselen);
320 		if (user[0]) {
321 			if (user[0] == '+' && user[1] == 0)
322 				usermatch = 1;
323 			else if (user[0] == '+' && user[1] == '@')
324 				usermatch = innetgr(user+2, NULL,
325 				    ruser, domain);
326 			else if (user[0] == '-' && user[1] == '@') {
327 				if (hostmatch && innetgr(user+2, NULL,
328 				    ruser, domain))
329 					break;
330 			}
331 			else if (user[0] == '-') {
332 				if (hostmatch && !strcmp(user+1, ruser))
333 					break;
334 			}
335 			else
336 				usermatch = !strcmp(user, ruser);
337 		}
338 		else
339 			usermatch = !strcmp(ruser, luser);
340 		if (hostmatch && usermatch)
341 			return (0);
342 	}
343 	return (-1);
344 }
345 
346 int
347 _checkhost(char *rhost, char *lhost, int len)
348 {
349 	static char *ldomain;
350 	static char *domainp;
351 	static int nodomain;
352 	char *cp;
353 
354 	if (ldomain == NULL) {
355 		ldomain = (char *)malloc(MAXHOSTNAMELEN+1);
356 		if (ldomain == 0)
357 			return (0);
358 	}
359 
360 	if (len == -1)
361 		return(!strcmp(rhost, lhost));
362 	if (strncmp(rhost, lhost, len))
363 		return(0);
364 	if (!strcmp(rhost, lhost))
365 		return(1);
366 	if (*(lhost + len) != '\0')
367 		return(0);
368 	if (nodomain)
369 		return(0);
370 	if (!domainp) {
371 		/*
372 		 * "domainp" points after the first dot in the host name
373 		 */
374 		if (gethostname(ldomain, MAXHOSTNAMELEN) == -1) {
375 			nodomain = 1;
376 			return(0);
377 		}
378 		ldomain[MAXHOSTNAMELEN] = NULL;
379 		if ((domainp = index(ldomain, '.')) == (char *)NULL) {
380 			nodomain = 1;
381 			return(0);
382 		}
383 		domainp++;
384 		cp = domainp;
385 		while (*cp) {
386 			*cp = isupper(*cp) ? tolower(*cp) : *cp;
387 			cp++;
388 		}
389 	}
390 	return(!strcmp(domainp, rhost + len +1));
391 }
392