2 * Copyright (C) 1998 WIDE Project.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
30 * Copyright (c) 1983, 1993, 1994
31 * The Regents of the University of California. All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
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.
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
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 */
62 #include <sys/param.h>
64 #include <sys/socket.h>
67 #include <netinet/in.h>
68 #include <arpa/inet.h>
78 #include <stdio_ext.h>
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,
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,
101 libc_hidden_proto (iruserok_af)
103 libc_freeres_ptr(static char *ahostbuf);
106 rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
109 const char *locuser, *remuser, *cmd;
113 char paddr[INET6_ADDRSTRLEN];
114 struct addrinfo hints, *res, *ai;
115 struct sockaddr_storage from;
116 struct pollfd pfd[2];
119 int s, lport, timo, error;
125 if (af != AF_INET && af != AF_INET6 && af != AF_UNSPEC)
127 __set_errno (EAFNOSUPPORT);
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);
140 if (error == EAI_NONAME && *ahost != NULL)
141 __fxprintf(NULL, "%s: Unknown host\n", *ahost);
143 __fxprintf(NULL, "rcmd: getaddrinfo: %s\n",
144 gai_strerror(error));
149 pfd[0].events = POLLIN;
150 pfd[1].events = POLLIN;
152 if (res->ai_canonname){
154 ahostbuf = strdup (res->ai_canonname);
155 if (ahostbuf == NULL) {
156 __fxprintf(NULL, "%s",
157 _("rcmd: Cannot allocate memory\n"));
165 oldmask = __sigblock(sigmask(SIGURG));
166 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
169 s = rresvport_af(&lport, ai->ai_family);
172 __fxprintf(NULL, "%s", _("\
173 rcmd: socket: All ports in use\n"));
175 __fxprintf(NULL, "rcmd: socket: %m\n");
177 __sigsetmask(oldmask);
181 __fcntl(s, F_SETOWN, pid);
182 if (__connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
185 if (errno == EADDRINUSE) {
189 if (errno == ECONNREFUSED)
191 if (ai->ai_next != NULL) {
195 getnameinfo(ai->ai_addr, ai->ai_addrlen,
196 paddr, sizeof(paddr),
200 if (__asprintf (&buf, _("connect to address %s: "),
203 __fxprintf(NULL, "%s", buf);
206 __set_errno (oerrno);
209 getnameinfo(ai->ai_addr, ai->ai_addrlen,
210 paddr, sizeof(paddr),
213 if (__asprintf (&buf, _("Trying %s...\n"), paddr) >= 0)
215 __fxprintf (NULL, "%s", buf);
220 if (refused && timo <= 16) {
228 (void)__fxprintf(NULL, "%s: %s\n", *ahost,
229 __strerror_r(errno, errbuf, sizeof (errbuf)));
230 __sigsetmask(oldmask);
239 int s2 = rresvport_af(&lport, ai->ai_family), s3;
240 socklen_t len = ai->ai_addrlen;
245 (void)__snprintf(num, sizeof(num), "%d", lport);
246 if (__write(s, num, strlen(num)+1) != (ssize_t)strlen(num)+1) {
249 if (__asprintf (&buf, _("\
250 rcmd: write (setting up stderr): %m\n")) >= 0)
252 __fxprintf(NULL, "%s", buf);
261 if (__poll (pfd, 2, -1) < 1 || (pfd[1].revents & POLLIN) == 0){
265 && __asprintf(&buf, _("\
266 rcmd: poll (setting up stderr): %m\n")) >= 0)
268 && __asprintf(&buf, _("\
269 poll: protocol failure in circuit setup\n")) >= 0))
271 __fxprintf (NULL, "%s", buf);
277 s3 = TEMP_FAILURE_RETRY (accept(s2, (struct sockaddr *)&from,
279 switch (from.ss_family) {
281 rport = ntohs(((struct sockaddr_in *)&from)->sin_port);
284 rport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
292 (void)__fxprintf(NULL, "rcmd: accept: %m\n");
298 if (rport >= IPPORT_RESERVED || rport < IPPORT_RESERVED / 2){
301 if (__asprintf(&buf, _("\
302 socket: protocol failure in circuit setup\n")) >= 0)
304 __fxprintf (NULL, "%s", buf);
310 struct iovec iov[3] =
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 }
319 (void) TEMP_FAILURE_RETRY (__writev (s, iov, 3));
320 n = TEMP_FAILURE_RETRY (__read(s, &c, 1));
325 && __asprintf(&buf, _("rcmd: %s: short read"),
328 && __asprintf(&buf, "rcmd: %s: %m\n", *ahost) >= 0))
330 __fxprintf (NULL, "%s", buf);
336 while (__read(s, &c, 1) == 1) {
337 (void)__write(STDERR_FILENO, &c, 1);
343 __sigsetmask(oldmask);
348 (void)__close(*fd2p);
351 __sigsetmask(oldmask);
355 libc_hidden_def (rcmd_af)
358 rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
361 const char *locuser, *remuser, *cmd;
364 return rcmd_af (ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
368 rresvport_af(alport, family)
372 struct sockaddr_storage ss;
379 len = sizeof(struct sockaddr_in);
380 sport = &((struct sockaddr_in *)&ss)->sin_port;
383 len = sizeof(struct sockaddr_in6);
384 sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
387 __set_errno (EAFNOSUPPORT);
390 s = __socket(family, SOCK_STREAM, 0);
394 memset (&ss, '\0', sizeof(ss));
398 ss.ss_family = family;
400 /* Ignore invalid values. */
401 if (*alport < IPPORT_RESERVED / 2)
402 *alport = IPPORT_RESERVED / 2;
403 else if (*alport >= IPPORT_RESERVED)
404 *alport = IPPORT_RESERVED - 1;
408 *sport = htons((uint16_t) *alport);
409 if (__bind(s, (struct sockaddr *)&ss, len) >= 0)
411 if (errno != EADDRINUSE) {
415 if ((*alport)-- == IPPORT_RESERVED/2)
416 *alport = IPPORT_RESERVED - 1;
417 } while (*alport != start);
419 __set_errno (EAGAIN);
422 libc_hidden_def (rresvport_af)
428 return rresvport_af(alport, AF_INET);
431 int __check_rhosts_file = 1;
435 ruserok_af(rhost, superuser, ruser, luser, af)
436 const char *rhost, *ruser, *luser;
440 struct addrinfo hints, *res, *res0;
444 memset (&hints, '\0', sizeof(hints));
445 hints.ai_family = af;
446 gai = getaddrinfo(rhost, NULL, &hints, &res0);
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){
459 libc_hidden_def (ruserok_af)
462 ruserok(rhost, superuser, ruser, luser)
463 const char *rhost, *ruser, *luser;
466 return ruserok_af(rhost, superuser, ruser, luser, AF_INET);
469 /* Extremely paranoid file open function. */
471 iruserfopen (const char *file, uid_t okuser)
477 /* If not a regular file, if owned by someone other than user or
478 root, if writeable by anyone but the owner, or if hardlinked
480 if (__lxstat64 (_STAT_VER, file, &st))
481 cp = _("lstat failed");
482 else if (!S_ISREG (st.st_mode))
483 cp = _("not regular file");
486 res = fopen (file, "rc");
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)
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");
499 /* If there were any problems, quit. */
508 /* No threads use this stream. */
509 __fsetlocking (res, FSETLOCKING_BYCALLER);
515 * New .rhosts strategy: We are passed an ip address. We spin through
516 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
517 * has ip addresses, we don't have to trust a nameserver. When it
518 * contains hostnames, we spin through the list of addresses the nameserver
519 * gives us and look for a match.
521 * Returns 0 if ok, -1 if not ok.
524 ruserok2_sa (ra, ralen, superuser, ruser, luser, rhost)
528 const char *ruser, *luser, *rhost;
534 hostf = iruserfopen (_PATH_HEQUIV, 0);
538 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
545 if (__check_rhosts_file || superuser)
548 struct passwd pwdbuf, *pwd;
550 size_t buflen = __sysconf (_SC_GETPW_R_SIZE_MAX);
551 char *buffer = __alloca (buflen);
554 if (__getpwnam_r (luser, &pwdbuf, buffer, buflen, &pwd) != 0
558 dirlen = strlen (pwd->pw_dir);
559 pbuf = alloca (dirlen + sizeof "/.rhosts");
560 __mempcpy (__mempcpy (pbuf, pwd->pw_dir, dirlen),
561 "/.rhosts", sizeof "/.rhosts");
563 /* Change effective uid while reading .rhosts. If root and
564 reading an NFS mounted file system, can't read files that
565 are protected read/write owner only. */
567 seteuid (pwd->pw_uid);
568 hostf = iruserfopen (pbuf, pwd->pw_uid);
572 isbad = __validuser2_sa (hostf, ra, ralen, luser, ruser, rhost);
582 * ruserok_sa() is now discussed on ipng, so
583 * currently disabled for external use
585 static int ruserok_sa(ra, ralen, superuser, ruser, luser)
589 const char *ruser, *luser;
591 return ruserok2_sa(ra, ralen, superuser, ruser, luser, "-");
594 /* This is the exported version. */
596 iruserok_af (raddr, superuser, ruser, luser, af)
599 const char *ruser, *luser;
602 struct sockaddr_storage ra;
605 memset (&ra, '\0', sizeof(ra));
608 ((struct sockaddr_in *)&ra)->sin_family = AF_INET;
609 memcpy (&(((struct sockaddr_in *)&ra)->sin_addr), raddr,
610 sizeof(struct in_addr));
611 ralen = sizeof(struct sockaddr_in);
614 ((struct sockaddr_in6 *)&ra)->sin6_family = AF_INET6;
615 memcpy (&(((struct sockaddr_in6 *)&ra)->sin6_addr), raddr,
616 sizeof(struct in6_addr));
617 ralen = sizeof(struct sockaddr_in6);
622 return ruserok_sa ((struct sockaddr *)&ra, ralen, superuser, ruser, luser);
624 libc_hidden_def (iruserok_af)
627 iruserok (raddr, superuser, ruser, luser)
630 const char *ruser, *luser;
632 return iruserok_af (&raddr, superuser, ruser, luser, AF_INET);
637 * Don't make static, used by lpd(8).
639 * This function is not used anymore. It is only present because lpd(8)
640 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
641 * argument. This means that netgroups won't work in .rhost/hosts.equiv
642 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
644 * Returns 0 if ok, -1 if not ok.
647 __ivaliduser(hostf, raddr, luser, ruser)
650 const char *luser, *ruser;
652 struct sockaddr_in ra;
653 memset(&ra, '\0', sizeof(ra));
654 ra.sin_family = AF_INET;
655 ra.sin_addr.s_addr = raddr;
656 return __validuser2_sa(hostf, (struct sockaddr *)&ra, sizeof(ra),
661 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
664 __checkhost_sa (struct sockaddr *ra, size_t ralen, char *lhost,
667 struct addrinfo hints, *res0, *res;
668 char raddr[INET6_ADDRSTRLEN];
670 int negate=1; /* Multiply return with this to get -1 instead of 1 */
672 /* Check nis netgroup. */
673 if (strncmp ("+@", lhost, 2) == 0)
674 return innetgr (&lhost[2], rhost, NULL, NULL);
676 if (strncmp ("-@", lhost, 2) == 0)
677 return -innetgr (&lhost[2], rhost, NULL, NULL);
680 if (strncmp ("-", lhost,1) == 0) {
683 } else if (strcmp ("+",lhost) == 0) {
684 return 1; /* asking for trouble, but ok.. */
687 /* Try for raw ip address first. */
689 if (getnameinfo(ra, ralen,
690 raddr, sizeof(raddr), NULL, 0,
692 && strcmp(raddr, lhost) == 0)
695 /* Better be a hostname. */
697 memset(&hints, '\0', sizeof(hints));
698 hints.ai_family = ra->sa_family;
699 if (getaddrinfo(lhost, NULL, &hints, &res0) == 0){
700 /* Spin through ip addresses. */
701 for (res = res0; res; res = res->ai_next)
703 if (res->ai_family == ra->sa_family
704 && !memcmp(res->ai_addr, ra, res->ai_addrlen))
712 return negate * match;
715 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
718 __icheckuser (const char *luser, const char *ruser)
721 luser is user entry from .rhosts/hosts.equiv file
722 ruser is user id on remote host
726 if (strncmp ("+@", luser, 2) == 0)
727 return innetgr (&luser[2], NULL, ruser, NULL);
729 if (strncmp ("-@", luser,2) == 0)
730 return -innetgr (&luser[2], NULL, ruser, NULL);
733 if (strncmp ("-", luser, 1) == 0)
734 return -(strcmp (&luser[1], ruser) == 0);
737 if (strcmp ("+", luser) == 0)
740 /* simple string match */
741 return strcmp (ruser, luser) == 0;
745 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
750 while (*p && isspace (*p)) {
754 return (*p == '\0' || *p == '#') ? 1 : 0 ;
758 * Returns 0 if positive match, -1 if _not_ ok.
761 __validuser2_sa(hostf, ra, ralen, luser, ruser, rhost)
765 const char *luser, *ruser, *rhost;
767 register const char *user;
774 while (__getline (&buf, &bufsize, hostf) > 0) {
775 buf[bufsize - 1] = '\0'; /* Make sure it's terminated. */
778 /* Skip empty or comment lines */
783 for (;*p && !isspace(*p); ++p) {
787 /* Next we want to find the permitted name for the remote user. */
788 if (*p == ' ' || *p == '\t') {
789 /* <nul> terminate hostname and skip spaces */
790 for (*p++='\0'; *p && isspace (*p); ++p);
792 user = p; /* this is the user's name */
793 while (*p && !isspace (*p))
794 ++p; /* find end of user's name */
798 *p = '\0'; /* <nul> terminate username (+host?) */
800 /* buf -> host(?) ; user -> username(?) */
802 /* First check host part */
803 hcheck = __checkhost_sa (ra, ralen, buf, rhost);
809 /* Then check user part */
813 ucheck = __icheckuser (user, ruser);
815 /* Positive 'host user' match? */
821 /* Negative 'host -user' match? */
825 /* Neither, go on looking for match */