xref: /csrg-svn/lib/libc/net/rcmd.c (revision 42626)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)rcmd.c	5.22 (Berkeley) 06/01/90";
10 #endif /* LIBC_SCCS and not lint */
11 
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <pwd.h>
15 #include <sys/param.h>
16 #include <sys/file.h>
17 #include <sys/signal.h>
18 #include <sys/socket.h>
19 #include <sys/stat.h>
20 
21 #include <netinet/in.h>
22 
23 #include <netdb.h>
24 #include <errno.h>
25 
26 extern	errno;
27 char	*index();
28 
29 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
30 	char **ahost;
31 	u_short rport;
32 	char *locuser, *remuser, *cmd;
33 	int *fd2p;
34 {
35 	int s, timo = 1, pid;
36 	long oldmask;
37 	struct sockaddr_in sin, sin2, from;
38 	char c;
39 	int lport = IPPORT_RESERVED - 1;
40 	struct hostent *hp;
41 	fd_set reads;
42 
43 	pid = getpid();
44 	hp = gethostbyname(*ahost);
45 	if (hp == 0) {
46 		herror(*ahost);
47 		return (-1);
48 	}
49 	*ahost = hp->h_name;
50 	oldmask = sigblock(sigmask(SIGURG));
51 	for (;;) {
52 		s = rresvport(&lport);
53 		if (s < 0) {
54 			if (errno == EAGAIN)
55 				fprintf(stderr, "socket: All ports in use\n");
56 			else
57 				perror("rcmd: socket");
58 			sigsetmask(oldmask);
59 			return (-1);
60 		}
61 		fcntl(s, F_SETOWN, pid);
62 		sin.sin_family = hp->h_addrtype;
63 		bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
64 		sin.sin_port = rport;
65 		if (connect(s, (caddr_t)&sin, sizeof (sin), 0) >= 0)
66 			break;
67 		(void) close(s);
68 		if (errno == EADDRINUSE) {
69 			lport--;
70 			continue;
71 		}
72 		if (errno == ECONNREFUSED && timo <= 16) {
73 			sleep(timo);
74 			timo *= 2;
75 			continue;
76 		}
77 		if (hp->h_addr_list[1] != NULL) {
78 			int oerrno = errno;
79 
80 			fprintf(stderr,
81 			    "connect to address %s: ", inet_ntoa(sin.sin_addr));
82 			errno = oerrno;
83 			perror(0);
84 			hp->h_addr_list++;
85 			bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
86 			    hp->h_length);
87 			fprintf(stderr, "Trying %s...\n",
88 				inet_ntoa(sin.sin_addr));
89 			continue;
90 		}
91 		perror(hp->h_name);
92 		sigsetmask(oldmask);
93 		return (-1);
94 	}
95 	lport--;
96 	if (fd2p == 0) {
97 		write(s, "", 1);
98 		lport = 0;
99 	} else {
100 		char num[8];
101 		int s2 = rresvport(&lport), s3;
102 		int len = sizeof (from);
103 
104 		if (s2 < 0)
105 			goto bad;
106 		listen(s2, 1);
107 		(void) sprintf(num, "%d", lport);
108 		if (write(s, num, strlen(num)+1) != strlen(num)+1) {
109 			perror("write: setting up stderr");
110 			(void) close(s2);
111 			goto bad;
112 		}
113 		FD_ZERO(&reads);
114 		FD_SET(s, &reads);
115 		FD_SET(s2, &reads);
116 		errno = 0;
117 		if (select(32, &reads, 0, 0, 0) < 1 ||
118 		    !FD_ISSET(s2, &reads)) {
119 			if (errno != 0)
120 				perror("select: setting up stderr");
121 			else
122 			    fprintf(stderr,
123 				"select: protocol failure in circuit setup.\n");
124 			(void) close(s2);
125 			goto bad;
126 		}
127 		s3 = accept(s2, &from, &len, 0);
128 		(void) close(s2);
129 		if (s3 < 0) {
130 			perror("accept");
131 			lport = 0;
132 			goto bad;
133 		}
134 		*fd2p = s3;
135 		from.sin_port = ntohs((u_short)from.sin_port);
136 		if (from.sin_family != AF_INET ||
137 		    from.sin_port >= IPPORT_RESERVED ||
138 		    from.sin_port < IPPORT_RESERVED / 2) {
139 			fprintf(stderr,
140 			    "socket: protocol failure in circuit setup.\n");
141 			goto bad2;
142 		}
143 	}
144 	(void) write(s, locuser, strlen(locuser)+1);
145 	(void) write(s, remuser, strlen(remuser)+1);
146 	(void) write(s, cmd, strlen(cmd)+1);
147 	if (read(s, &c, 1) != 1) {
148 		perror(*ahost);
149 		goto bad2;
150 	}
151 	if (c != 0) {
152 		while (read(s, &c, 1) == 1) {
153 			(void) write(2, &c, 1);
154 			if (c == '\n')
155 				break;
156 		}
157 		goto bad2;
158 	}
159 	sigsetmask(oldmask);
160 	return (s);
161 bad2:
162 	if (lport)
163 		(void) close(*fd2p);
164 bad:
165 	(void) close(s);
166 	sigsetmask(oldmask);
167 	return (-1);
168 }
169 
170 rresvport(alport)
171 	int *alport;
172 {
173 	struct sockaddr_in sin;
174 	int s;
175 
176 	sin.sin_family = AF_INET;
177 	sin.sin_addr.s_addr = INADDR_ANY;
178 	s = socket(AF_INET, SOCK_STREAM, 0);
179 	if (s < 0)
180 		return (-1);
181 	for (;;) {
182 		sin.sin_port = htons((u_short)*alport);
183 		if (bind(s, (caddr_t)&sin, sizeof (sin)) >= 0)
184 			return (s);
185 		if (errno != EADDRINUSE) {
186 			(void) close(s);
187 			return (-1);
188 		}
189 		(*alport)--;
190 		if (*alport == IPPORT_RESERVED/2) {
191 			(void) close(s);
192 			errno = EAGAIN;		/* close */
193 			return (-1);
194 		}
195 	}
196 }
197 
198 int	_check_rhosts_file = 1;
199 
200 ruserok(rhost, superuser, ruser, luser)
201 	char *rhost;
202 	int superuser;
203 	char *ruser, *luser;
204 {
205 	FILE *hostf;
206 	char fhost[MAXHOSTNAMELEN];
207 	int first = 1;
208 	register char *sp, *p;
209 	int baselen = -1;
210 
211 	sp = rhost;
212 	p = fhost;
213 	while (*sp) {
214 		if (*sp == '.') {
215 			if (baselen == -1)
216 				baselen = sp - rhost;
217 			*p++ = *sp++;
218 		} else {
219 			*p++ = isupper(*sp) ? tolower(*sp++) : *sp++;
220 		}
221 	}
222 	*p = '\0';
223 	hostf = superuser ? (FILE *)0 : fopen(_PATH_HEQUIV, "r");
224 again:
225 	if (hostf) {
226 		if (!_validuser(hostf, fhost, luser, ruser, baselen)) {
227 			(void) fclose(hostf);
228 			return(0);
229 		}
230 		(void) fclose(hostf);
231 	}
232 	if (first == 1 && (_check_rhosts_file || superuser)) {
233 		struct stat sbuf;
234 		struct passwd *pwd;
235 		char pbuf[MAXPATHLEN];
236 
237 		first = 0;
238 		if ((pwd = getpwnam(luser)) == NULL)
239 			return(-1);
240 		(void)strcpy(pbuf, pwd->pw_dir);
241 		(void)strcat(pbuf, "/.rhosts");
242 		if ((hostf = fopen(pbuf, "r")) == NULL)
243 			return(-1);
244 		/*
245 		 * if owned by someone other than user or root or if
246 		 * writeable by anyone but the owner, quit
247 		 */
248 		if (fstat(fileno(hostf), &sbuf) ||
249 		    sbuf.st_uid && sbuf.st_uid != pwd->pw_uid ||
250 		    sbuf.st_mode&022) {
251 			fclose(hostf);
252 			return(-1);
253 		}
254 		goto again;
255 	}
256 	return (-1);
257 }
258 
259 /* don't make static, used by lpd(8) */
260 _validuser(hostf, rhost, luser, ruser, baselen)
261 	char *rhost, *luser, *ruser;
262 	FILE *hostf;
263 	int baselen;
264 {
265 	char *user;
266 	char ahost[MAXHOSTNAMELEN];
267 	register char *p;
268 
269 	while (fgets(ahost, sizeof (ahost), hostf)) {
270 		p = ahost;
271 		while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
272 			*p = isupper(*p) ? tolower(*p) : *p;
273 			p++;
274 		}
275 		if (*p == ' ' || *p == '\t') {
276 			*p++ = '\0';
277 			while (*p == ' ' || *p == '\t')
278 				p++;
279 			user = p;
280 			while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0')
281 				p++;
282 		} else
283 			user = p;
284 		*p = '\0';
285 		if (_checkhost(rhost, ahost, baselen) &&
286 		    !strcmp(ruser, *user ? user : luser)) {
287 			return (0);
288 		}
289 	}
290 	return (-1);
291 }
292 
293 static
294 _checkhost(rhost, lhost, len)
295 	char *rhost, *lhost;
296 	int len;
297 {
298 	static char ldomain[MAXHOSTNAMELEN + 1];
299 	static char *domainp = NULL;
300 	static int nodomain = 0;
301 	register char *cp;
302 
303 	if (len == -1)
304 		return(!strcmp(rhost, lhost));
305 	if (strncmp(rhost, lhost, len))
306 		return(0);
307 	if (!strcmp(rhost, lhost))
308 		return(1);
309 	if (*(lhost + len) != '\0')
310 		return(0);
311 	if (nodomain)
312 		return(0);
313 	if (!domainp) {
314 		if (gethostname(ldomain, sizeof(ldomain)) == -1) {
315 			nodomain = 1;
316 			return(0);
317 		}
318 		ldomain[MAXHOSTNAMELEN] = NULL;
319 		if ((domainp = index(ldomain, '.')) == (char *)NULL) {
320 			nodomain = 1;
321 			return(0);
322 		}
323 		for (cp = ++domainp; *cp; ++cp)
324 			if (isupper(*cp))
325 				*cp = tolower(*cp);
326 	}
327 	return(!strcmp(domainp, rhost + len +1));
328 }
329