1 | /* |
---|
2 | * Copyright (C) 1998 WIDE Project. |
---|
3 | * All rights reserved. |
---|
4 | * |
---|
5 | * Redistribution and use in source and binary forms, with or without |
---|
6 | * modification, are permitted provided that the following conditions |
---|
7 | * are met: |
---|
8 | * 1. Redistributions of source code must retain the above copyright |
---|
9 | * notice, this list of conditions and the following disclaimer. |
---|
10 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
11 | * notice, this list of conditions and the following disclaimer in the |
---|
12 | * documentation and/or other materials provided with the distribution. |
---|
13 | * 3. Neither the name of the project nor the names of its contributors |
---|
14 | * may be used to endorse or promote products derived from this software |
---|
15 | * without specific prior written permission. |
---|
16 | * |
---|
17 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
---|
18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
---|
21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
27 | * SUCH DAMAGE. |
---|
28 | */ |
---|
29 | /* |
---|
30 | * Copyright (c) 1983, 1993, 1994 |
---|
31 | * The Regents of the University of California. All rights reserved. |
---|
32 | * |
---|
33 | * Redistribution and use in source and binary forms, with or without |
---|
34 | * modification, are permitted provided that the following conditions |
---|
35 | * are met: |
---|
36 | * 1. Redistributions of source code must retain the above copyright |
---|
37 | * notice, this list of conditions and the following disclaimer. |
---|
38 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
39 | * notice, this list of conditions and the following disclaimer in the |
---|
40 | * documentation and/or other materials provided with the distribution. |
---|
41 | * 4. Neither the name of the University nor the names of its contributors |
---|
42 | * may be used to endorse or promote products derived from this software |
---|
43 | * without specific prior written permission. |
---|
44 | * |
---|
45 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
46 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
47 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
48 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
49 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
50 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
51 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
52 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
53 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
54 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
55 | * SUCH DAMAGE. |
---|
56 | */ |
---|
57 | |
---|
58 | #if defined(LIBC_SCCS) && !defined(lint) |
---|
59 | static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; |
---|
60 | #endif /* LIBC_SCCS and not lint */ |
---|
61 | |
---|
62 | #include <sys/param.h> |
---|
63 | #include <sys/poll.h> |
---|
64 | #include <sys/socket.h> |
---|
65 | #include <sys/stat.h> |
---|
66 | |
---|
67 | #include <netinet/in.h> |
---|
68 | #include <arpa/inet.h> |
---|
69 | |
---|
70 | #include <alloca.h> |
---|
71 | #include <signal.h> |
---|
72 | #include <fcntl.h> |
---|
73 | #include <netdb.h> |
---|
74 | #include <unistd.h> |
---|
75 | #include <pwd.h> |
---|
76 | #include <errno.h> |
---|
77 | #include <stdio.h> |
---|
78 | #include <stdio_ext.h> |
---|
79 | #include <ctype.h> |
---|
80 | #include <string.h> |
---|
81 | #include <libintl.h> |
---|
82 | #include <stdlib.h> |
---|
83 | #include <wchar.h> |
---|
84 | #include <sys/uio.h> |
---|
85 | |
---|
86 | #include "local.h" |
---|
87 | |
---|
88 | |
---|
89 | int __ivaliduser (FILE *, u_int32_t, const char *, const char *); |
---|
90 | static int __validuser2_sa (FILE *, struct sockaddr *, size_t, |
---|
91 | const char *, const char *, const char *); |
---|
92 | static int ruserok2_sa (struct sockaddr *ra, size_t ralen, |
---|
93 | int superuser, const char *ruser, |
---|
94 | const char *luser, const char *rhost); |
---|
95 | static int ruserok_sa (struct sockaddr *ra, size_t ralen, |
---|
96 | int superuser, const char *ruser, |
---|
97 | const char *luser); |
---|
98 | int iruserok_af (const void *raddr, int superuser, const char *ruser, |
---|
99 | const char *luser, sa_family_t af); |
---|
100 | int iruserok (u_int32_t raddr, int superuser, const char *ruser, |
---|
101 | const char *luser); |
---|
102 | |
---|
103 | libc_hidden_proto (iruserok_af) |
---|
104 | |
---|
105 | libc_freeres_ptr(static char *ahostbuf); |
---|
106 | |
---|
107 | int |
---|
108 | rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af) |
---|
109 | char **ahost; |
---|
110 | u_short rport; |
---|
111 | const char *locuser, *remuser, *cmd; |
---|
112 | int *fd2p; |
---|
113 | sa_family_t af; |
---|
114 | { |
---|
115 | char paddr[INET6_ADDRSTRLEN]; |
---|
116 | struct addrinfo hints, *res, *ai; |
---|
117 | struct sockaddr_storage from; |
---|
118 | struct pollfd pfd[2]; |
---|
119 | int32_t oldmask; |
---|
120 | pid_t pid; |
---|
121 | int s, lport, timo, error; |
---|
122 | char c; |
---|
123 | int refused; |
---|
124 | char num[8]; |
---|
125 | ssize_t n; |
---|
126 | |
---|
127 | if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC) |
---|
128 | { |
---|
129 | __set_errno (EAFNOSUPPORT); |
---|
130 | return -1; |
---|
131 | } |
---|
132 | |
---|
133 | pid = __getpid(); |
---|
134 | |
---|
135 | memset(&hints, '\0', sizeof(hints)); |
---|
136 | hints.ai_flags = AI_CANONNAME; |
---|
137 | hints.ai_family = af; |
---|
138 | hints.ai_socktype = SOCK_STREAM; |
---|
139 | (void)snprintf(num, sizeof(num), "%d", ntohs(rport)); |
---|
140 | error = getaddrinfo(*ahost, num, &hints, &res); |
---|
141 | if (error) { |
---|
142 | if (error == EAI_NONAME && *ahost != NULL) { |
---|
143 | if (_IO_fwide (stderr, 0) > 0) |
---|
144 | __fwprintf(stderr, L"%s: Unknown host\n", |
---|
145 | *ahost); |
---|
146 | else |
---|
147 | fprintf(stderr, "%s: Unknown host\n", *ahost); |
---|
148 | } else { |
---|
149 | if (_IO_fwide (stderr, 0) > 0) |
---|
150 | __fwprintf(stderr, L"rcmd: getaddrinfo: %s\n", |
---|
151 | gai_strerror(error)); |
---|
152 | else |
---|
153 | fprintf(stderr, "rcmd: getaddrinfo: %s\n", |
---|
154 | gai_strerror(error)); |
---|
155 | } |
---|
156 | return (-1); |
---|
157 | } |
---|
158 | |
---|
159 | pfd[0].events = POLLIN; |
---|
160 | pfd[1].events = POLLIN; |
---|
161 | |
---|
162 | if (res->ai_canonname){ |
---|
163 | free (ahostbuf); |
---|
164 | ahostbuf = strdup (res->ai_canonname); |
---|
165 | if (ahostbuf == NULL) { |
---|
166 | if (_IO_fwide (stderr, 0) > 0) |
---|
167 | __fwprintf(stderr, L"%s", |
---|
168 | _("rcmd: Cannot allocate memory\n")); |
---|
169 | else |
---|
170 | fputs(_("rcmd: Cannot allocate memory\n"), |
---|
171 | stderr); |
---|
172 | return (-1); |
---|
173 | } |
---|
174 | *ahost = ahostbuf; |
---|
175 | } else |
---|
176 | *ahost = NULL; |
---|
177 | ai = res; |
---|
178 | refused = 0; |
---|
179 | oldmask = __sigblock(sigmask(SIGURG)); |
---|
180 | for (timo = 1, lport = IPPORT_RESERVED - 1;;) { |
---|
181 | char errbuf[200]; |
---|
182 | |
---|
183 | s = rresvport_af(&lport, ai->ai_family); |
---|
184 | if (s < 0) { |
---|
185 | if (errno == EAGAIN) { |
---|
186 | if (_IO_fwide (stderr, 0) > 0) |
---|
187 | __fwprintf(stderr, L"%s", |
---|
188 | _("rcmd: socket: All ports in use\n")); |
---|
189 | else |
---|
190 | fputs(_("rcmd: socket: All ports in use\n"), |
---|
191 | stderr); |
---|
192 | } else { |
---|
193 | if (_IO_fwide (stderr, 0) > 0) |
---|
194 | __fwprintf(stderr, |
---|
195 | L"rcmd: socket: %m\n"); |
---|
196 | else |
---|
197 | fprintf(stderr, "rcmd: socket: %m\n"); |
---|
198 | } |
---|
199 | __sigsetmask(oldmask); |
---|
200 | freeaddrinfo(res); |
---|
201 | return -1; |
---|
202 | } |
---|
203 | __fcntl(s, F_SETOWN, pid); |
---|
204 | if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0) |
---|
205 | break; |
---|
206 | (void)__close(s); |
---|
207 | if (errno == EADDRINUSE) { |
---|
208 | lport--; |
---|
209 | continue; |
---|
210 | } |
---|
211 | if (errno == ECONNREFUSED) |
---|
212 | refused = 1; |
---|
213 | if (ai->ai_next != NULL) { |
---|
214 | int oerrno = errno; |
---|
215 | char *buf = NULL; |
---|
216 | |
---|
217 | getnameinfo(ai->ai_addr, ai->ai_addrlen, |
---|
218 | paddr, sizeof(paddr), |
---|
219 | NULL, 0, |
---|
220 | NI_NUMERICHOST); |
---|
221 | |
---|
222 | if (__asprintf (&buf, _("connect to address %s: "), |
---|
223 | paddr) >= 0) |
---|
224 | { |
---|
225 | if (_IO_fwide (stderr, 0) > 0) |
---|
226 | __fwprintf(stderr, L"%s", buf); |
---|
227 | else |
---|
228 | fputs (buf, stderr); |
---|
229 | free (buf); |
---|
230 | } |
---|
231 | __set_errno (oerrno); |
---|
232 | perror(0); |
---|
233 | ai = ai->ai_next; |
---|
234 | getnameinfo(ai->ai_addr, ai->ai_addrlen, |
---|
235 | paddr, sizeof(paddr), |
---|
236 | NULL, 0, |
---|
237 | NI_NUMERICHOST); |
---|
238 | if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0) |
---|
239 | { |
---|
240 | if (_IO_fwide (stderr, 0) > 0) |
---|
241 | __fwprintf (stderr, L"%s", buf); |
---|
242 | else |
---|
243 | fputs (buf, stderr); |
---|
244 | free (buf); |
---|
245 | } |
---|
246 | continue; |
---|
247 | } |
---|
248 | if (refused && timo <= 16) { |
---|
249 | (void)sleep(timo); |
---|
250 | timo *= 2; |
---|
251 | ai = res; |
---|
252 | refused = 0; |
---|
253 | continue; |
---|
254 | } |
---|
255 | freeaddrinfo(res); |
---|
256 | if (_IO_fwide (stderr, 0) > 0) |
---|
257 | (void)__fwprintf(stderr, L"%s: %s\n", *ahost, |
---|
258 | strerror_r(errno, |
---|
259 | errbuf, sizeof (errbuf))); |
---|
260 | else |
---|
261 | (void)fprintf(stderr, "%s: %s\n", *ahost, |
---|
262 | strerror_r(errno, |
---|
263 | errbuf, sizeof (errbuf))); |
---|
264 | __sigsetmask(oldmask); |
---|
265 | return -1; |
---|
266 | } |
---|
267 | lport--; |
---|
268 | if (fd2p == 0) { |
---|
269 | __write(s, "", 1); |
---|
270 | lport = 0; |
---|
271 | } else { |
---|
272 | char num[8]; |
---|
273 | int s2 = rresvport_af(&lport, ai->ai_family), s3; |
---|
274 | socklen_t len = ai->ai_addrlen; |
---|
275 | |
---|
276 | if (s2 < 0) |
---|
277 | goto bad; |
---|
278 | listen(s2, 1); |
---|
279 | (void)snprintf(num, sizeof(num), "%d", lport); |
---|
280 | if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) { |
---|
281 | char *buf = NULL; |
---|
282 | |
---|
283 | if (__asprintf (&buf, _("\ |
---|
284 | rcmd: write (setting up stderr): %m\n")) >= 0) |
---|
285 | { |
---|
286 | if (_IO_fwide (stderr, 0) > 0) |
---|
287 | __fwprintf(stderr, L"%s", buf); |
---|
288 | else |
---|
289 | fputs (buf, stderr); |
---|
290 | free (buf); |
---|
291 | } |
---|
292 | (void)__close(s2); |
---|
293 | goto bad; |
---|
294 | } |
---|
295 | pfd[0].fd = s; |
---|
296 | pfd[1].fd = s2; |
---|
297 | __set_errno (0); |
---|
298 | if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){ |
---|
299 | char *buf = NULL; |
---|
300 | |
---|
301 | if ((errno != 0 |
---|
302 | && __asprintf(&buf, _("\ |
---|
303 | rcmd: poll (setting up stderr): %m\n")) >= 0) |
---|
304 | || (errno == 0 |
---|
305 | && __asprintf(&buf, _("\ |
---|
306 | poll: protocol failure in circuit setup\n")) >= 0)) |
---|
307 | { |
---|
308 | if (_IO_fwide (stderr, 0) > 0) |
---|
309 | __fwprintf (stderr, L"%s", buf); |
---|
310 | else |
---|
311 | fputs (buf, stderr); |
---|
312 | free (buf); |
---|
313 | } |
---|
314 | (void)__close(s2); |
---|
315 | goto bad; |
---|
316 | } |
---|
317 | s3 = TEMP_FAILURE_RETRY (accept(s2, (struct sockaddr *)&from, |
---|
318 | &len)); |
---|
319 | switch (from.ss_family) { |
---|
320 | case AF_INET: |
---|
321 | rport = ntohs(((struct sockaddr_in *)&from)->sin_port); |
---|
322 | break; |
---|
323 | case AF_INET6: |
---|
324 | rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port); |
---|
325 | break; |
---|
326 | default: |
---|
327 | rport = 0; |
---|
328 | break; |
---|
329 | } |
---|
330 | (void)__close(s2); |
---|
331 | if (s3 < 0) { |
---|
332 | if (_IO_fwide (stderr, 0) > 0) |
---|
333 | (void)__fwprintf(stderr, |
---|
334 | L"rcmd: accept: %m\n"); |
---|
335 | else |
---|
336 | (void)fprintf(stderr, |
---|
337 | "rcmd: accept: %m\n"); |
---|
338 | lport = 0; |
---|
339 | goto bad; |
---|
340 | } |
---|
341 | *fd2p = s3; |
---|
342 | |
---|
343 | if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){ |
---|
344 | char *buf = NULL; |
---|
345 | |
---|
346 | if (__asprintf(&buf, _("\ |
---|
347 | socket: protocol failure in circuit setup\n")) >= 0) |
---|
348 | { |
---|
349 | if (_IO_fwide (stderr, 0) > 0) |
---|
350 | __fwprintf (stderr, L"%s", buf); |
---|
351 | else |
---|
352 | fputs (buf, stderr); |
---|
353 | free (buf); |
---|
354 | } |
---|
355 | goto bad2; |
---|
356 | } |
---|
357 | } |
---|
358 | struct iovec iov[3] = |
---|
359 | { |
---|
360 | [0] = { .iov_base = (void *) locuser, |
---|
361 | .iov_len = strlen (locuser) + 1 }, |
---|
362 | [1] = { .iov_base = (void *) remuser, |
---|
363 | .iov_len = strlen (remuser) + 1 }, |
---|
364 | [2] = { .iov_base = (void *) cmd, |
---|
365 | .iov_len = strlen (cmd) + 1 } |
---|
366 | }; |
---|
367 | (void) TEMP_FAILURE_RETRY (writev (s, iov, 3)); |
---|
368 | n = TEMP_FAILURE_RETRY (read(s, &c, 1)); |
---|
369 | if (n != 1) { |
---|
370 | char *buf = NULL; |
---|
371 | |
---|
372 | if ((n == 0 |
---|
373 | && asprintf(&buf, _("rcmd: %s: short read"), |
---|
374 | *ahost) >= 0) |
---|
375 | || (n != 0 |
---|
376 | && asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0)) |
---|
377 | { |
---|
378 | if (_IO_fwide (stderr, 0) > 0) |
---|
379 | __fwprintf (stderr, L"%s", buf); |
---|
380 | else |
---|
381 | fputs (buf, stderr); |
---|
382 | free (buf); |
---|
383 | } |
---|
384 | goto bad2; |
---|
385 | } |
---|
386 | if (c != 0) { |
---|
387 | while (__read(s, &c, 1) == 1) { |
---|
388 | (void)__write(STDERR_FILENO, &c, 1); |
---|
389 | if (c == '\n') |
---|
390 | break; |
---|
391 | } |
---|
392 | goto bad2; |
---|
393 | } |
---|
394 | __sigsetmask(oldmask); |
---|
395 | freeaddrinfo(res); |
---|
396 | return s; |
---|
397 | bad2: |
---|
398 | if (lport) |
---|
399 | (void)__close(*fd2p); |
---|
400 | bad: |
---|
401 | (void)__close(s); |
---|
402 | __sigsetmask(oldmask); |
---|
403 | freeaddrinfo(res); |
---|
404 | return -1; |
---|
405 | } |
---|
406 | libc_hidden_def (rcmd_af) |
---|
407 | |
---|
408 | int |
---|
409 | rcmd(ahost, rport, locuser, remuser, cmd, fd2p) |
---|
410 | char **ahost; |
---|
411 | u_short rport; |
---|
412 | const char *locuser, *remuser, *cmd; |
---|
413 | int *fd2p; |
---|
414 | { |
---|
415 | return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); |
---|
416 | } |
---|
417 | |
---|
418 | int |
---|
419 | rresvport_af(alport, family) |
---|
420 | int *alport; |
---|
421 | sa_family_t family; |
---|
422 | { |
---|
423 | struct sockaddr_storage ss; |
---|
424 | int s; |
---|
425 | size_t len; |
---|
426 | uint16_t *sport; |
---|
427 | |
---|
428 | switch(family){ |
---|
429 | case AF_INET: |
---|
430 | len = sizeof(struct sockaddr_in); |
---|
431 | sport = &((struct sockaddr_in *)&ss)->sin_port; |
---|
432 | break; |
---|
433 | case AF_INET6: |
---|
434 | len = sizeof(struct sockaddr_in6); |
---|
435 | sport = &((struct sockaddr_in6 *)&ss)->sin6_port; |
---|
436 | break; |
---|
437 | default: |
---|
438 | __set_errno (EAFNOSUPPORT); |
---|
439 | return -1; |
---|
440 | } |
---|
441 | s = __socket(family, SOCK_STREAM, 0); |
---|
442 | if (s < 0) |
---|
443 | return -1; |
---|
444 | |
---|
445 | memset (&ss, '\0', sizeof(ss)); |
---|
446 | #ifdef SALEN |
---|
447 | ss.__ss_len = len; |
---|
448 | #endif |
---|
449 | ss.ss_family = family; |
---|
450 | |
---|
451 | /* Ignore invalid values. */ |
---|
452 | if (*alport < IPPORT_RESERVED / 2) |
---|
453 | *alport = IPPORT_RESERVED / 2; |
---|
454 | else if (*alport >= IPPORT_RESERVED) |
---|
455 | *alport = IPPORT_RESERVED - 1; |
---|
456 | |
---|
457 | int start = *alport; |
---|
458 | do { |
---|
459 | *sport = htons((uint16_t) *alport); |
---|
460 | if (__bind(s, (struct sockaddr *)&ss, len) >= 0) |
---|
461 | return s; |
---|
462 | if (errno != EADDRINUSE) { |
---|
463 | (void)__close(s); |
---|
464 | return -1; |
---|
465 | } |
---|
466 | if ((*alport)-- == IPPORT_RESERVED/2) |
---|
467 | *alport = IPPORT_RESERVED - 1; |
---|
468 | } while (*alport != start); |
---|
469 | (void)__close(s); |
---|
470 | __set_errno (EAGAIN); |
---|
471 | return -1; |
---|
472 | } |
---|
473 | libc_hidden_def (rresvport_af) |
---|
474 | |
---|
475 | int |
---|
476 | rresvport(alport) |
---|
477 | int *alport; |
---|
478 | { |
---|
479 | return rresvport_af(alport, AF_INET); |
---|
480 | } |
---|
481 | |
---|
482 | int __check_rhosts_file = 1; |
---|
483 | char *__rcmd_errstr; |
---|
484 | |
---|
485 | int |
---|
486 | ruserok_af(rhost, superuser, ruser, luser, af) |
---|
487 | const char *rhost, *ruser, *luser; |
---|
488 | int superuser; |
---|
489 | sa_family_t af; |
---|
490 | { |
---|
491 | struct addrinfo hints, *res, *res0; |
---|
492 | int gai; |
---|
493 | int ret; |
---|
494 | |
---|
495 | memset (&hints, '\0', sizeof(hints)); |
---|
496 | hints.ai_family = af; |
---|
497 | gai = getaddrinfo(rhost, NULL, &hints, &res0); |
---|
498 | if (gai) |
---|
499 | return -1; |
---|
500 | ret = -1; |
---|
501 | for (res=res0; res; res=res->ai_next) |
---|
502 | if (ruserok2_sa(res->ai_addr, res->ai_addrlen, |
---|
503 | superuser, ruser, luser, rhost) == 0){ |
---|
504 | ret = 0; |
---|
505 | break; |
---|
506 | } |
---|
507 | freeaddrinfo(res0); |
---|
508 | return (ret); |
---|
509 | } |
---|
510 | libc_hidden_def (ruserok_af) |
---|
511 | |
---|
512 | int |
---|
513 | ruserok(rhost, superuser, ruser, luser) |
---|
514 | const char *rhost, *ruser, *luser; |
---|
515 | int superuser; |
---|
516 | { |
---|
517 | return ruserok_af(rhost, superuser, ruser, luser, AF_INET); |
---|
518 | } |
---|
519 | |
---|
520 | /* Extremely paranoid file open function. */ |
---|
521 | static FILE * |
---|
522 | iruserfopen (const char *file, uid_t okuser) |
---|
523 | { |
---|
524 | struct stat64 st; |
---|
525 | char *cp = NULL; |
---|
526 | FILE *res = NULL; |
---|
527 | |
---|
528 | /* If not a regular file, if owned by someone other than user or |
---|
529 | root, if writeable by anyone but the owner, or if hardlinked |
---|
530 | anywhere, quit. */ |
---|
531 | cp = NULL; |
---|
532 | if (__lxstat64 (_STAT_VER, file, &st)) |
---|
533 | cp = _("lstat failed"); |
---|
534 | else if (!S_ISREG (st.st_mode)) |
---|
535 | cp = _("not regular file"); |
---|
536 | else |
---|
537 | { |
---|
538 | res = fopen (file, "rc"); |
---|
539 | if (!res) |
---|
540 | cp = _("cannot open"); |
---|
541 | else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0) |
---|
542 | cp = _("fstat failed"); |
---|
543 | else if (st.st_uid && st.st_uid != okuser) |
---|
544 | cp = _("bad owner"); |
---|
545 | else if (st.st_mode & (S_IWGRP|S_IWOTH)) |
---|
546 | cp = _("writeable by other than owner"); |
---|
547 | else if (st.st_nlink > 1) |
---|
548 | cp = _("hard linked somewhere"); |
---|
549 | } |
---|
550 | |
---|
551 | /* If there were any problems, quit. */ |
---|
552 | if (cp != NULL) |
---|
553 | { |
---|
554 | __rcmd_errstr = cp; |
---|
555 | if (res) |
---|
556 | fclose (res); |
---|
557 | return NULL; |
---|
558 | } |
---|
559 | |
---|
560 | /* No threads use this stream. */ |
---|
561 | __fsetlocking (res, FSETLOCKING_BYCALLER); |
---|
562 | |
---|
563 | return res; |
---|
564 | } |
---|
565 | |
---|
566 | /* |
---|
567 | * New .rhosts strategy: We are passed an ip address. We spin through |
---|
568 | * hosts.equiv and .rhosts looking for a match. When the .rhosts only |
---|
569 | * has ip addresses, we don't have to trust a nameserver. When it |
---|
570 | * contains hostnames, we spin through the list of addresses the nameserver |
---|
571 | * gives us and look for a match. |
---|
572 | * |
---|
573 | * Returns 0 if ok, -1 if not ok. |
---|
574 | */ |
---|
575 | static int |
---|
576 | ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost) |
---|
577 | struct sockaddr *ra; |
---|
578 | size_t ralen; |
---|
579 | int superuser; |
---|
580 | const char *ruser, *luser, *rhost; |
---|
581 | { |
---|
582 | FILE *hostf = NULL; |
---|
583 | int isbad = -1; |
---|
584 | |
---|
585 | if (!superuser) |
---|
586 | hostf = iruserfopen (_PATH_HEQUIV, 0); |
---|
587 | |
---|
588 | if (hostf) |
---|
589 | { |
---|
590 | isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost); |
---|
591 | fclose (hostf); |
---|
592 | |
---|
593 | if (!isbad) |
---|
594 | return 0; |
---|
595 | } |
---|
596 | |
---|
597 | if (__check_rhosts_file || superuser) |
---|
598 | { |
---|
599 | char *pbuf; |
---|
600 | struct passwd pwdbuf, *pwd; |
---|
601 | size_t dirlen; |
---|
602 | size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX); |
---|
603 | char *buffer = __alloca (buflen); |
---|
604 | uid_t uid; |
---|
605 | |
---|
606 | if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0 |
---|
607 | || pwd == NULL) |
---|
608 | return -1; |
---|
609 | |
---|
610 | dirlen = strlen (pwd->pw_dir); |
---|
611 | pbuf = alloca (dirlen + sizeof "/.rhosts"); |
---|
612 | __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen), |
---|
613 | "/.rhosts", sizeof "/.rhosts"); |
---|
614 | |
---|
615 | /* Change effective uid while reading .rhosts. If root and |
---|
616 | reading an NFS mounted file system, can't read files that |
---|
617 | are protected read/write owner only. */ |
---|
618 | uid = __geteuid (); |
---|
619 | seteuid (pwd->pw_uid); |
---|
620 | hostf = iruserfopen (pbuf, pwd->pw_uid); |
---|
621 | |
---|
622 | if (hostf != NULL) |
---|
623 | { |
---|
624 | isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost); |
---|
625 | fclose (hostf); |
---|
626 | } |
---|
627 | |
---|
628 | seteuid (uid); |
---|
629 | return isbad; |
---|
630 | } |
---|
631 | return -1; |
---|
632 | } |
---|
633 | /* |
---|
634 | * ruserok_sa() is now discussed on ipng, so |
---|
635 | * currently disabled for external use |
---|
636 | */ |
---|
637 | static int ruserok_sa(ra, ralen, superuser, ruser, luser) |
---|
638 | struct sockaddr *ra; |
---|
639 | size_t ralen; |
---|
640 | int superuser; |
---|
641 | const char *ruser, *luser; |
---|
642 | { |
---|
643 | return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-"); |
---|
644 | } |
---|
645 | |
---|
646 | /* This is the exported version. */ |
---|
647 | int |
---|
648 | iruserok_af (raddr, superuser, ruser, luser, af) |
---|
649 | const void *raddr; |
---|
650 | int superuser; |
---|
651 | const char *ruser, *luser; |
---|
652 | sa_family_t af; |
---|
653 | { |
---|
654 | struct sockaddr_storage ra; |
---|
655 | size_t ralen; |
---|
656 | |
---|
657 | memset (&ra, '\0', sizeof(ra)); |
---|
658 | switch (af){ |
---|
659 | case AF_INET: |
---|
660 | ((struct sockaddr_in *)&ra)->sin_family = AF_INET; |
---|
661 | memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr, |
---|
662 | sizeof(struct in_addr)); |
---|
663 | ralen = sizeof(struct sockaddr_in); |
---|
664 | break; |
---|
665 | case AF_INET6: |
---|
666 | ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6; |
---|
667 | memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr, |
---|
668 | sizeof(struct in6_addr)); |
---|
669 | ralen = sizeof(struct sockaddr_in6); |
---|
670 | break; |
---|
671 | default: |
---|
672 | return 0; |
---|
673 | } |
---|
674 | return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser); |
---|
675 | } |
---|
676 | libc_hidden_def (iruserok_af) |
---|
677 | |
---|
678 | int |
---|
679 | iruserok (raddr, superuser, ruser, luser) |
---|
680 | u_int32_t raddr; |
---|
681 | int superuser; |
---|
682 | const char *ruser, *luser; |
---|
683 | { |
---|
684 | return iruserok_af (&raddr, superuser, ruser, luser, AF_INET); |
---|
685 | } |
---|
686 | |
---|
687 | /* |
---|
688 | * XXX |
---|
689 | * Don't make static, used by lpd(8). |
---|
690 | * |
---|
691 | * This function is not used anymore. It is only present because lpd(8) |
---|
692 | * calls it (!?!). We simply call __invaliduser2() with an illegal rhost |
---|
693 | * argument. This means that netgroups won't work in .rhost/hosts.equiv |
---|
694 | * files. If you want lpd to work with netgroups, fix lpd to use ruserok() |
---|
695 | * or PAM. |
---|
696 | * Returns 0 if ok, -1 if not ok. |
---|
697 | */ |
---|
698 | int |
---|
699 | __ivaliduser(hostf, raddr, luser, ruser) |
---|
700 | FILE *hostf; |
---|
701 | u_int32_t raddr; |
---|
702 | const char *luser, *ruser; |
---|
703 | { |
---|
704 | struct sockaddr_in ra; |
---|
705 | memset(&ra, '\0', sizeof(ra)); |
---|
706 | ra.sin_family = AF_INET; |
---|
707 | ra.sin_addr.s_addr = raddr; |
---|
708 | return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra), |
---|
709 | luser, ruser, "-"); |
---|
710 | } |
---|
711 | |
---|
712 | |
---|
713 | /* Returns 1 on positive match, 0 on no match, -1 on negative match. */ |
---|
714 | static int |
---|
715 | internal_function |
---|
716 | __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost, |
---|
717 | const char *rhost) |
---|
718 | { |
---|
719 | struct addrinfo hints, *res0, *res; |
---|
720 | char raddr[INET6_ADDRSTRLEN]; |
---|
721 | int match; |
---|
722 | int negate=1; /* Multiply return with this to get -1 instead of 1 */ |
---|
723 | |
---|
724 | /* Check nis netgroup. */ |
---|
725 | if (strncmp ("+@", lhost, 2) == 0) |
---|
726 | return innetgr (&lhost[2], rhost, NULL, NULL); |
---|
727 | |
---|
728 | if (strncmp ("-@", lhost, 2) == 0) |
---|
729 | return -innetgr (&lhost[2], rhost, NULL, NULL); |
---|
730 | |
---|
731 | /* -host */ |
---|
732 | if (strncmp ("-", lhost,1) == 0) { |
---|
733 | negate = -1; |
---|
734 | lhost++; |
---|
735 | } else if (strcmp ("+",lhost) == 0) { |
---|
736 | return 1; /* asking for trouble, but ok.. */ |
---|
737 | } |
---|
738 | |
---|
739 | /* Try for raw ip address first. */ |
---|
740 | /* XXX */ |
---|
741 | if (getnameinfo(ra, ralen, |
---|
742 | raddr, sizeof(raddr), NULL, 0, |
---|
743 | NI_NUMERICHOST) == 0 |
---|
744 | && strcmp(raddr, lhost) == 0) |
---|
745 | return negate; |
---|
746 | |
---|
747 | /* Better be a hostname. */ |
---|
748 | match = 0; |
---|
749 | memset(&hints, '\0', sizeof(hints)); |
---|
750 | hints.ai_family = ra->sa_family; |
---|
751 | if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){ |
---|
752 | /* Spin through ip addresses. */ |
---|
753 | for (res = res0; res; res = res->ai_next) |
---|
754 | { |
---|
755 | if (res->ai_family == ra->sa_family |
---|
756 | && !memcmp(res->ai_addr, ra, res->ai_addrlen)) |
---|
757 | { |
---|
758 | match = 1; |
---|
759 | break; |
---|
760 | } |
---|
761 | } |
---|
762 | freeaddrinfo (res0); |
---|
763 | } |
---|
764 | return negate * match; |
---|
765 | } |
---|
766 | |
---|
767 | /* Returns 1 on positive match, 0 on no match, -1 on negative match. */ |
---|
768 | static int |
---|
769 | internal_function |
---|
770 | __icheckuser (const char *luser, const char *ruser) |
---|
771 | { |
---|
772 | /* |
---|
773 | luser is user entry from .rhosts/hosts.equiv file |
---|
774 | ruser is user id on remote host |
---|
775 | */ |
---|
776 | |
---|
777 | /* [-+]@netgroup */ |
---|
778 | if (strncmp ("+@", luser, 2) == 0) |
---|
779 | return innetgr (&luser[2], NULL, ruser, NULL); |
---|
780 | |
---|
781 | if (strncmp ("-@", luser,2) == 0) |
---|
782 | return -innetgr (&luser[2], NULL, ruser, NULL); |
---|
783 | |
---|
784 | /* -user */ |
---|
785 | if (strncmp ("-", luser, 1) == 0) |
---|
786 | return -(strcmp (&luser[1], ruser) == 0); |
---|
787 | |
---|
788 | /* + */ |
---|
789 | if (strcmp ("+", luser) == 0) |
---|
790 | return 1; |
---|
791 | |
---|
792 | /* simple string match */ |
---|
793 | return strcmp (ruser, luser) == 0; |
---|
794 | } |
---|
795 | |
---|
796 | /* |
---|
797 | * Returns 1 for blank lines (or only comment lines) and 0 otherwise |
---|
798 | */ |
---|
799 | static int |
---|
800 | __isempty (char *p) |
---|
801 | { |
---|
802 | while (*p && isspace (*p)) { |
---|
803 | ++p; |
---|
804 | } |
---|
805 | |
---|
806 | return (*p == '\0' || *p == '#') ? 1 : 0 ; |
---|
807 | } |
---|
808 | |
---|
809 | /* |
---|
810 | * Returns 0 if positive match, -1 if _not_ ok. |
---|
811 | */ |
---|
812 | static int |
---|
813 | __validuser2_sa(hostf, ra, ralen, luser, ruser, rhost) |
---|
814 | FILE *hostf; |
---|
815 | struct sockaddr *ra; |
---|
816 | size_t ralen; |
---|
817 | const char *luser, *ruser, *rhost; |
---|
818 | { |
---|
819 | register const char *user; |
---|
820 | register char *p; |
---|
821 | int hcheck, ucheck; |
---|
822 | char *buf = NULL; |
---|
823 | size_t bufsize = 0; |
---|
824 | int retval = -1; |
---|
825 | |
---|
826 | while (__getline (&buf, &bufsize, hostf) > 0) { |
---|
827 | buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */ |
---|
828 | p = buf; |
---|
829 | |
---|
830 | /* Skip empty or comment lines */ |
---|
831 | if (__isempty (p)) { |
---|
832 | continue; |
---|
833 | } |
---|
834 | |
---|
835 | for (;*p && !isspace(*p); ++p) { |
---|
836 | *p = _tolower (*p); |
---|
837 | } |
---|
838 | |
---|
839 | /* Next we want to find the permitted name for the remote user. */ |
---|
840 | if (*p == ' ' || *p == '\t') { |
---|
841 | /* <nul> terminate hostname and skip spaces */ |
---|
842 | for (*p++='\0'; *p && isspace (*p); ++p); |
---|
843 | |
---|
844 | user = p; /* this is the user's name */ |
---|
845 | while (*p && !isspace (*p)) |
---|
846 | ++p; /* find end of user's name */ |
---|
847 | } else |
---|
848 | user = p; |
---|
849 | |
---|
850 | *p = '\0'; /* <nul> terminate username (+host?) */ |
---|
851 | |
---|
852 | /* buf -> host(?) ; user -> username(?) */ |
---|
853 | |
---|
854 | /* First check host part */ |
---|
855 | hcheck = __checkhost_sa (ra, ralen, buf, rhost); |
---|
856 | |
---|
857 | if (hcheck < 0) |
---|
858 | break; |
---|
859 | |
---|
860 | if (hcheck) { |
---|
861 | /* Then check user part */ |
---|
862 | if (! (*user)) |
---|
863 | user = luser; |
---|
864 | |
---|
865 | ucheck = __icheckuser (user, ruser); |
---|
866 | |
---|
867 | /* Positive 'host user' match? */ |
---|
868 | if (ucheck > 0) { |
---|
869 | retval = 0; |
---|
870 | break; |
---|
871 | } |
---|
872 | |
---|
873 | /* Negative 'host -user' match? */ |
---|
874 | if (ucheck < 0) |
---|
875 | break; |
---|
876 | |
---|
877 | /* Neither, go on looking for match */ |
---|
878 | } |
---|
879 | } |
---|
880 | |
---|
881 | if (buf != NULL) |
---|
882 | free (buf); |
---|
883 | |
---|
884 | return retval; |
---|
885 | } |
---|