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