xref: /titanic_44/usr/src/lib/libbc/libc/net/rcmd.c (revision 5d54f3d8999eac1762fe0a8c7177d20f1f201fae)
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
rcmd(char ** ahost,unsigned short rport,const char * locuser,const char * remuser,const char * cmd,int * fd2p)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
rresvport(int * alport)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
ruserok(const char * rhost,int superuser,const char * ruser,const char * luser)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
_validuser(FILE * hostf,char * rhost,char * luser,char * ruser,int baselen)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
_checkhost(char * rhost,char * lhost,int len)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