1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58: #if defined(LIBC_SCCS) && !defined(lint)
59: static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
60: #endif
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:
87: int __ivaliduser (FILE *, u_int32_t, const char *, const char *);
88: static int __validuser2_sa (FILE *, struct sockaddr *, size_t,
89: const char *, const char *, const char *);
90: static int ruserok2_sa (struct sockaddr *ra, size_t ralen,
91: int superuser, const char *ruser,
92: const char *luser, const char *rhost);
93: static int ruserok_sa (struct sockaddr *ra, size_t ralen,
94: int superuser, const char *ruser,
95: const char *luser);
96: int iruserok_af (const void *raddr, int superuser, const char *ruser,
97: const char *luser, sa_family_t af);
98: int iruserok (u_int32_t raddr, int superuser, const char *ruser,
99: const char *luser);
100:
101: libc_hidden_proto (iruserok_af)
102:
103: libc_freeres_ptr(static char *ahostbuf);
104:
105: int
106: rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
107: char **ahost;
108: u_short rport;
109: const char *locuser, *remuser, *cmd;
110: int *fd2p;
111: sa_family_t af;
112: {
113: char paddr[INET6_ADDRSTRLEN];
114: struct addrinfo hints, *res, *ai;
115: struct sockaddr_storage from;
116: struct pollfd pfd[2];
117: int32_t oldmask;
118: pid_t pid;
119: int s, lport, timo, error;
120: char c;
121: int refused;
122: char num[8];
123: ssize_t n;
124:
125: if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
126: {
127: __set_errno (EAFNOSUPPORT);
128: return -1;
129: }
130:
131: pid = __getpid();
132:
133: memset(&hints, '\0', sizeof(hints));
134: hints.ai_flags = AI_CANONNAME;
135: hints.ai_family = af;
136: hints.ai_socktype = SOCK_STREAM;
137: (void)__snprintf(num, sizeof(num), "%d", ntohs(rport));
138: error = getaddrinfo(*ahost, num, &hints, &res);
139: if (error) {
140: if (error == EAI_NONAME && *ahost != NULL)
141: __fxprintf(NULL, "%s: Unknown host\n", *ahost);
142: else
143: __fxprintf(NULL, "rcmd: getaddrinfo: %s\n",
144: gai_strerror(error));
145:
146: return -1;
147: }
148:
149: pfd[0].events = POLLIN;
150: pfd[1].events = POLLIN;
151:
152: if (res->ai_canonname){
153: free (ahostbuf);
154: ahostbuf = strdup (res->ai_canonname);
155: if (ahostbuf == NULL) {
156: __fxprintf(NULL, "%s",
157: _("rcmd: Cannot allocate memory\n"));
158: return -1;
159: }
160: *ahost = ahostbuf;
161: } else
162: *ahost = NULL;
163: ai = res;
164: refused = 0;
165: oldmask = __sigblock(sigmask(SIGURG));
166: for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
167: char errbuf[200];
168:
169: s = rresvport_af(&lport, ai->ai_family);
170: if (s < 0) {
171: if (errno == EAGAIN)
172: __fxprintf(NULL, "%s", _("\
173: rcmd: socket: All ports in use\n"));
174: else
175: __fxprintf(NULL, "rcmd: socket: %m\n");
176:
177: __sigsetmask(oldmask);
178: freeaddrinfo(res);
179: return -1;
180: }
181: __fcntl(s, F_SETOWN, pid);
182: if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
183: break;
184: (void)__close(s);
185: if (errno == EADDRINUSE) {
186: lport--;
187: continue;
188: }
189: if (errno == ECONNREFUSED)
190: refused = 1;
191: if (ai->ai_next != NULL) {
192: int oerrno = errno;
193: char *buf = NULL;
194:
195: getnameinfo(ai->ai_addr, ai->ai_addrlen,
196: paddr, sizeof(paddr),
197: NULL, 0,
198: NI_NUMERICHOST);
199:
200: if (__asprintf (&buf, _("connect to address %s: "),
201: paddr) >= 0)
202: {
203: __fxprintf(NULL, "%s", buf);
204: free (buf);
205: }
206: __set_errno (oerrno);
207: perror(0);
208: ai = ai->ai_next;
209: getnameinfo(ai->ai_addr, ai->ai_addrlen,
210: paddr, sizeof(paddr),
211: NULL, 0,
212: NI_NUMERICHOST);
213: if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
214: {
215: __fxprintf (NULL, "%s", buf);
216: free (buf);
217: }
218: continue;
219: }
220: if (refused && timo <= 16) {
221: (void)__sleep(timo);
222: timo *= 2;
223: ai = res;
224: refused = 0;
225: continue;
226: }
227: freeaddrinfo(res);
228: (void)__fxprintf(NULL, "%s: %s\n", *ahost,
229: __strerror_r(errno, errbuf, sizeof (errbuf)));
230: __sigsetmask(oldmask);
231: return -1;
232: }
233: lport--;
234: if (fd2p == 0) {
235: __write(s, "", 1);
236: lport = 0;
237: } else {
238: char num[8];
239: int s2 = rresvport_af(&lport, ai->ai_family), s3;
240: socklen_t len = ai->ai_addrlen;
241:
242: if (s2 < 0)
243: goto bad;
244: __listen(s2, 1);
245: (void)__snprintf(num, sizeof(num), "%d", lport);
246: if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
247: char *buf = NULL;
248:
249: if (__asprintf (&buf, _("\
250: rcmd: write (setting up stderr): %m\n")) >= 0)
251: {
252: __fxprintf(NULL, "%s", buf);
253: free (buf);
254: }
255: (void)__close(s2);
256: goto bad;
257: }
258: pfd[0].fd = s;
259: pfd[1].fd = s2;
260: __set_errno (0);
261: if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
262: char *buf = NULL;
263:
264: if ((errno != 0
265: && __asprintf(&buf, _("\
266: rcmd: poll (setting up stderr): %m\n")) >= 0)
267: || (errno == 0
268: && __asprintf(&buf, _("\
269: poll: protocol failure in circuit setup\n")) >= 0))
270: {
271: __fxprintf (NULL, "%s", buf);
272: free (buf);
273: }
274: (void)__close(s2);
275: goto bad;
276: }
277: s3 = TEMP_FAILURE_RETRY (accept(s2, (struct sockaddr *)&from,
278: &len));
279: switch (from.ss_family) {
280: case AF_INET:
281: rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
282: break;
283: case AF_INET6:
284: rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
285: break;
286: default:
287: rport = 0;
288: break;
289: }
290: (void)__close(s2);
291: if (s3 < 0) {
292: (void)__fxprintf(NULL, "rcmd: accept: %m\n");
293: lport = 0;
294: goto bad;
295: }
296: *fd2p = s3;
297:
298: if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
299: char *buf = NULL;
300:
301: if (__asprintf(&buf, _("\
302: socket: protocol failure in circuit setup\n")) >= 0)
303: {
304: __fxprintf (NULL, "%s", buf);
305: free (buf);
306: }
307: goto bad2;
308: }
309: }
310: struct iovec iov[3] =
311: {
312: [0] = { .iov_base = (void *) locuser,
313: .iov_len = strlen (locuser) + 1 },
314: [1] = { .iov_base = (void *) remuser,
315: .iov_len = strlen (remuser) + 1 },
316: [2] = { .iov_base = (void *) cmd,
317: .iov_len = strlen (cmd) + 1 }
318: };
319: (void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
320: n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
321: if (n != 1) {
322: char *buf = NULL;
323:
324: if ((n == 0
325: && __asprintf(&buf, _("rcmd: %s: short read"),
326: *ahost) >= 0)
327: || (n != 0
328: && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
329: {
330: __fxprintf (NULL, "%s", buf);
331: free (buf);
332: }
333: goto bad2;
334: }
335: if (c != 0) {
336: while (__read(s, &c, 1) == 1) {
337: (void)__write(STDERR_FILENO, &c, 1);
338: if (c == '\n')
339: break;
340: }
341: goto bad2;
342: }
343: __sigsetmask(oldmask);
344: freeaddrinfo(res);
345: return s;
346: bad2:
347: if (lport)
348: (void)__close(*fd2p);
349: bad:
350: (void)__close(s);
351: __sigsetmask(oldmask);
352: freeaddrinfo(res);
353: return -1;
354: }
355: libc_hidden_def (rcmd_af)
356:
357: int
358: rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
359: char **ahost;
360: u_short rport;
361: const char *locuser, *remuser, *cmd;
362: int *fd2p;
363: {
364: return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
365: }
366:
367: int
368: rresvport_af(alport, family)
369: int *alport;
370: sa_family_t family;
371: {
372: struct sockaddr_storage ss;
373: int s;
374: size_t len;
375: uint16_t *sport;
376:
377: switch(family){
378: case AF_INET:
379: len = sizeof(struct sockaddr_in);
380: sport = &((struct sockaddr_in *)&ss)->sin_port;
381: break;
382: case AF_INET6:
383: len = sizeof(struct sockaddr_in6);
384: sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
385: break;
386: default:
387: __set_errno (EAFNOSUPPORT);
388: return -1;
389: }
390: s = __socket(family, SOCK_STREAM, 0);
391: if (s < 0)
392: return -1;
393:
394: memset (&ss, '\0', sizeof(ss));
395: #ifdef SALEN
396: ss.__ss_len = len;
397: #endif
398: ss.ss_family = family;
399:
400:
401: if (*alport < IPPORT_RESERVED / 2)
402: *alport = IPPORT_RESERVED / 2;
403: else if (*alport >= IPPORT_RESERVED)
404: *alport = IPPORT_RESERVED - 1;
405:
406: int start = *alport;
407: do {
408: *sport = htons((uint16_t) *alport);
409: if (__bind(s, (struct sockaddr *)&ss, len) >= 0)
410: return s;
411: if (errno != EADDRINUSE) {
412: (void)__close(s);
413: return -1;
414: }
415: if ((*alport)-- == IPPORT_RESERVED/2)
416: *alport = IPPORT_RESERVED - 1;
417: } while (*alport != start);
418: (void)__close(s);
419: __set_errno (EAGAIN);
420: return -1;
421: }
422: libc_hidden_def (rresvport_af)
423:
424: int
425: rresvport(alport)
426: int *alport;
427: {
428: return rresvport_af(alport, AF_INET);
429: }
430:
431: int __check_rhosts_file = 1;
432: char *__rcmd_errstr;
433:
434: int
435: ruserok_af(rhost, superuser, ruser, luser, af)
436: const char *rhost, *ruser, *luser;
437: int superuser;
438: sa_family_t af;
439: {
440: struct addrinfo hints, *res, *res0;
441: int gai;
442: int ret;
443:
444: memset (&hints, '\0', sizeof(hints));
445: hints.ai_family = af;
446: gai = getaddrinfo(rhost, NULL, &hints, &res0);
447: if (gai)
448: return -1;
449: ret = -1;
450: for (res=res0; res; res=res->ai_next)
451: if (ruserok2_sa(res->ai_addr, res->ai_addrlen,
452: superuser, ruser, luser, rhost) == 0){
453: ret = 0;
454: break;
455: }
456: freeaddrinfo(res0);
457: return (ret);
458: }
459: libc_hidden_def (ruserok_af)
460:
461: int
462: ruserok(rhost, superuser, ruser, luser)
463: const char *rhost, *ruser, *luser;
464: int superuser;
465: {
466: return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
467: }
468:
469:
470: static FILE *
471: iruserfopen (const char *file, uid_t okuser)
472: {
473: struct stat64 st;
474: char *cp = NULL;
475: FILE *res = NULL;
476:
477:
478:
479:
480: if (__lxstat64 (_STAT_VER, file, &st))
481: cp = _("lstat failed");
482: else if (!S_ISREG (st.st_mode))
483: cp = _("not regular file");
484: else
485: {
486: res = fopen (file, "rc");
487: if (!res)
488: cp = _("cannot open");
489: else if (__fxstat64 (_STAT_VER, fileno (res), &st) < 0)
490: cp = _("fstat failed");
491: else if (st.st_uid && st.st_uid != okuser)
492: cp = _("bad owner");
493: else if (st.st_mode & (S_IWGRP|S_IWOTH))
494: cp = _("writeable by other than owner");
495: else if (st.st_nlink > 1)
496: cp = _("hard linked somewhere");
497: }
498:
499:
500: if (cp != NULL)
501: {
502: __rcmd_errstr = cp;
503: if (res)
504: fclose (res);
505: return NULL;
506: }
507:
508:
509: __fsetlocking (res, FSETLOCKING_BYCALLER);
510:
511: return res;
512: }
513:
514:
515:
516:
517:
518:
519:
520:
521:
522:
523: static int
524: ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
525: struct sockaddr *ra;
526: size_t ralen;
527: int superuser;
528: const char *ruser, *luser, *rhost;
529: {
530: FILE *hostf = NULL;
531: int isbad = -1;
532:
533: if (!superuser)
534: hostf = iruserfopen (_PATH_HEQUIV, 0);
535:
536: if (hostf)
537: {
538: isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
539: fclose (hostf);
540:
541: if (!isbad)
542: return 0;
543: }
544:
545: if (__check_rhosts_file || superuser)
546: {
547: char *pbuf;
548: struct passwd pwdbuf, *pwd;
549: size_t dirlen;
550: size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
551: char *buffer = __alloca (buflen);
552: uid_t uid;
553:
554: if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
555: || pwd == NULL)
556: return -1;
557:
558: dirlen = strlen (pwd->pw_dir);
559: pbuf = alloca (dirlen + sizeof "/.rhosts");
560: __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
561: "/.rhosts", sizeof "/.rhosts");
562:
563:
564: