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