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 #include <sys/param.h>
60 #include <sys/socket.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
74 #include <stdio_ext.h>
81 #include <sigsetops.h>
84 int __ivaliduser (FILE *, uint32_t, const char *, const char *);
85 static int __validuser2_sa (FILE *, struct sockaddr
*, size_t,
86 const char *, const char *, const char *);
87 static int ruserok2_sa (struct sockaddr
*ra
, size_t ralen
,
88 int superuser
, const char *ruser
,
89 const char *luser
, const char *rhost
);
90 static int ruserok_sa (struct sockaddr
*ra
, size_t ralen
,
91 int superuser
, const char *ruser
,
93 int iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
94 const char *luser
, sa_family_t af
);
95 int iruserok (uint32_t raddr
, int superuser
, const char *ruser
,
98 libc_hidden_proto (iruserok_af
)
100 libc_freeres_ptr(static char *ahostbuf
);
103 rcmd_af (char **ahost
, u_short rport
, const char *locuser
, const char *remuser
,
104 const char *cmd
, int *fd2p
, sa_family_t af
)
106 char paddr
[INET6_ADDRSTRLEN
];
107 struct addrinfo hints
, *res
, *ai
;
111 struct sockaddr_storage ss
;
112 struct sockaddr_in sin
;
113 struct sockaddr_in6 sin6
;
115 struct pollfd pfd
[2];
116 sigset_t mask
, omask
;
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
) {
157 __fxprintf(NULL
, "%s",
158 _("rcmd: Cannot allocate memory\n"));
166 __sigemptyset(&mask
);
167 __sigaddset(&mask
, SIGURG
);
168 __sigprocmask (SIG_BLOCK
, &mask
, &omask
);
169 for (timo
= 1, lport
= IPPORT_RESERVED
- 1;;) {
172 s
= rresvport_af(&lport
, ai
->ai_family
);
175 __fxprintf(NULL
, "%s", _("\
176 rcmd: socket: All ports in use\n"));
178 __fxprintf(NULL
, "rcmd: socket: %m\n");
180 __sigprocmask (SIG_SETMASK
, &omask
, 0);
184 __fcntl(s
, F_SETOWN
, pid
);
185 if (__connect(s
, ai
->ai_addr
, ai
->ai_addrlen
) >= 0)
188 if (errno
== EADDRINUSE
) {
192 if (errno
== ECONNREFUSED
)
194 if (ai
->ai_next
!= NULL
) {
198 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
199 paddr
, sizeof(paddr
),
203 if (__asprintf (&buf
, _("connect to address %s: "),
206 __fxprintf(NULL
, "%s", buf
);
209 __set_errno (oerrno
);
212 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
213 paddr
, sizeof(paddr
),
216 if (__asprintf (&buf
, _("Trying %s...\n"), paddr
) >= 0)
218 __fxprintf (NULL
, "%s", buf
);
223 if (refused
&& timo
<= 16) {
231 (void)__fxprintf(NULL
, "%s: %s\n", *ahost
,
232 __strerror_r(errno
, errbuf
, sizeof (errbuf
)));
233 __sigprocmask (SIG_SETMASK
, &omask
, 0);
242 int s2
= rresvport_af(&lport
, ai
->ai_family
), s3
;
243 socklen_t len
= ai
->ai_addrlen
;
248 (void)__snprintf(num
, sizeof(num
), "%d", lport
);
249 if (__write(s
, num
, strlen(num
)+1) != (ssize_t
)strlen(num
)+1) {
252 if (__asprintf (&buf
, _("\
253 rcmd: write (setting up stderr): %m\n")) >= 0)
255 __fxprintf(NULL
, "%s", buf
);
264 if (__poll (pfd
, 2, -1) < 1 || (pfd
[1].revents
& POLLIN
) == 0){
268 && __asprintf(&buf
, _("\
269 rcmd: poll (setting up stderr): %m\n")) >= 0)
271 && __asprintf(&buf
, _("\
272 poll: protocol failure in circuit setup\n")) >= 0))
274 __fxprintf (NULL
, "%s", buf
);
280 s3
= TEMP_FAILURE_RETRY (accept(s2
, &from
.sa
, &len
));
281 switch (from
.sa
.sa_family
) {
283 rport
= ntohs(from
.sin
.sin_port
);
286 rport
= ntohs(from
.sin6
.sin6_port
);
294 (void)__fxprintf(NULL
, "rcmd: accept: %m\n");
300 if (rport
>= IPPORT_RESERVED
|| rport
< IPPORT_RESERVED
/ 2){
303 if (__asprintf(&buf
, _("\
304 socket: protocol failure in circuit setup\n")) >= 0)
306 __fxprintf (NULL
, "%s", buf
);
312 struct iovec iov
[3] =
314 [0] = { .iov_base
= (void *) locuser
,
315 .iov_len
= strlen (locuser
) + 1 },
316 [1] = { .iov_base
= (void *) remuser
,
317 .iov_len
= strlen (remuser
) + 1 },
318 [2] = { .iov_base
= (void *) cmd
,
319 .iov_len
= strlen (cmd
) + 1 }
321 (void) TEMP_FAILURE_RETRY (__writev (s
, iov
, 3));
322 n
= TEMP_FAILURE_RETRY (__read(s
, &c
, 1));
327 && __asprintf(&buf
, _("rcmd: %s: short read"),
330 && __asprintf(&buf
, "rcmd: %s: %m\n", *ahost
) >= 0))
332 __fxprintf (NULL
, "%s", buf
);
338 while (__read(s
, &c
, 1) == 1) {
339 (void)__write(STDERR_FILENO
, &c
, 1);
345 __sigprocmask (SIG_SETMASK
, &omask
, 0);
350 (void)__close(*fd2p
);
353 __sigprocmask (SIG_SETMASK
, &omask
, 0);
357 libc_hidden_def (rcmd_af
)
360 rcmd (char **ahost
, u_short rport
, const char *locuser
, const char *remuser
,
361 const char *cmd
, int *fd2p
)
363 return rcmd_af (ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
367 rresvport_af (int *alport
, sa_family_t family
)
370 struct sockaddr generic
;
371 struct sockaddr_in in
;
372 struct sockaddr_in6 in6
;
380 len
= sizeof(struct sockaddr_in
);
381 sport
= &ss
.in
.sin_port
;
384 len
= sizeof(struct sockaddr_in6
);
385 sport
= &ss
.in6
.sin6_port
;
388 __set_errno (EAFNOSUPPORT
);
391 /* NB: No SOCK_CLOEXEC for backwards compatibility. */
392 s
= __socket(family
, SOCK_STREAM
, 0);
396 memset (&ss
, '\0', sizeof(ss
));
398 ss
.generic
.__ss_len
= len
;
400 ss
.generic
.sa_family
= family
;
402 /* Ignore invalid values. */
403 if (*alport
< IPPORT_RESERVED
/ 2)
404 *alport
= IPPORT_RESERVED
/ 2;
405 else if (*alport
>= IPPORT_RESERVED
)
406 *alport
= IPPORT_RESERVED
- 1;
410 *sport
= htons((uint16_t) *alport
);
411 if (__bind(s
, &ss
.generic
, len
) >= 0)
413 if (errno
!= EADDRINUSE
) {
417 if ((*alport
)-- == IPPORT_RESERVED
/2)
418 *alport
= IPPORT_RESERVED
- 1;
419 } while (*alport
!= start
);
421 __set_errno (EAGAIN
);
424 libc_hidden_def (rresvport_af
)
427 rresvport (int *alport
)
429 return rresvport_af(alport
, AF_INET
);
432 int __check_rhosts_file
= 1;
436 ruserok_af (const char *rhost
, int superuser
, const char *ruser
,
437 const char *luser
, sa_family_t af
)
439 struct addrinfo hints
, *res
, *res0
;
443 memset (&hints
, '\0', sizeof(hints
));
444 hints
.ai_family
= af
;
445 gai
= getaddrinfo(rhost
, NULL
, &hints
, &res0
);
449 for (res
=res0
; res
; res
=res
->ai_next
)
450 if (ruserok2_sa(res
->ai_addr
, res
->ai_addrlen
,
451 superuser
, ruser
, luser
, rhost
) == 0){
458 libc_hidden_def (ruserok_af
)
461 ruserok (const char *rhost
, int superuser
, const char *ruser
,
464 return ruserok_af(rhost
, superuser
, ruser
, luser
, AF_INET
);
467 /* Extremely paranoid file open function. */
469 iruserfopen (const char *file
, uid_t okuser
)
471 struct __stat64_t64 st
;
475 /* If not a regular file, if owned by someone other than user or
476 root, if writeable by anyone but the owner, or if hardlinked
478 if (__lstat64_time64 (file
, &st
))
479 cp
= _("lstat failed");
480 else if (!S_ISREG (st
.st_mode
))
481 cp
= _("not regular file");
484 res
= fopen (file
, "rce");
486 cp
= _("cannot open");
487 else if (__fstat64_time64 (fileno (res
), &st
) < 0)
488 cp
= _("fstat failed");
489 else if (st
.st_uid
&& st
.st_uid
!= okuser
)
491 else if (st
.st_mode
& (S_IWGRP
|S_IWOTH
))
492 cp
= _("writeable by other than owner");
493 else if (st
.st_nlink
> 1)
494 cp
= _("hard linked somewhere");
497 /* If there were any problems, quit. */
506 /* No threads use this stream. */
507 __fsetlocking (res
, FSETLOCKING_BYCALLER
);
513 * New .rhosts strategy: We are passed an ip address. We spin through
514 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
515 * has ip addresses, we don't have to trust a nameserver. When it
516 * contains hostnames, we spin through the list of addresses the nameserver
517 * gives us and look for a match.
519 * Returns 0 if ok, -1 if not ok.
522 ruserok2_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
523 const char *ruser
, const char *luser
, const char *rhost
)
529 hostf
= iruserfopen (_PATH_HEQUIV
, 0);
533 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
540 if (__check_rhosts_file
|| superuser
)
543 struct passwd pwdbuf
, *pwd
;
545 size_t buflen
= __sysconf (_SC_GETPW_R_SIZE_MAX
);
546 char *buffer
= __alloca (buflen
);
549 if (__getpwnam_r (luser
, &pwdbuf
, buffer
, buflen
, &pwd
) != 0
553 dirlen
= strlen (pwd
->pw_dir
);
554 pbuf
= alloca (dirlen
+ sizeof "/.rhosts");
555 __mempcpy (__mempcpy (pbuf
, pwd
->pw_dir
, dirlen
),
556 "/.rhosts", sizeof "/.rhosts");
558 /* Change effective uid while reading .rhosts. If root and
559 reading an NFS mounted file system, can't read files that
560 are protected read/write owner only. */
562 seteuid (pwd
->pw_uid
);
563 hostf
= iruserfopen (pbuf
, pwd
->pw_uid
);
567 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
577 * ruserok_sa() is now discussed on ipng, so
578 * currently disabled for external use
581 ruserok_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
582 const char *ruser
, const char *luser
)
584 return ruserok2_sa(ra
, ralen
, superuser
, ruser
, luser
, "-");
587 /* This is the exported version. */
589 iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
590 const char *luser
, sa_family_t af
)
593 struct sockaddr generic
;
594 struct sockaddr_in in
;
595 struct sockaddr_in6 in6
;
599 memset (&ra
, '\0', sizeof(ra
));
602 ra
.in
.sin_family
= AF_INET
;
603 memcpy (&ra
.in
.sin_addr
, raddr
, sizeof(struct in_addr
));
604 ralen
= sizeof(struct sockaddr_in
);
607 ra
.in6
.sin6_family
= AF_INET6
;
608 memcpy (&ra
.in6
.sin6_addr
, raddr
, sizeof(struct in6_addr
));
609 ralen
= sizeof(struct sockaddr_in6
);
614 return ruserok_sa (&ra
.generic
, ralen
, superuser
, ruser
, luser
);
616 libc_hidden_def (iruserok_af
)
619 iruserok (uint32_t raddr
, int superuser
, const char *ruser
, const char *luser
)
621 return iruserok_af (&raddr
, superuser
, ruser
, luser
, AF_INET
);
626 * Don't make static, used by lpd(8).
628 * This function is not used anymore. It is only present because lpd(8)
629 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
630 * argument. This means that netgroups won't work in .rhost/hosts.equiv
631 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
633 * Returns 0 if ok, -1 if not ok.
636 __ivaliduser (FILE *hostf
, uint32_t raddr
, const char *luser
,
639 struct sockaddr_in ra
;
640 memset(&ra
, '\0', sizeof(ra
));
641 ra
.sin_family
= AF_INET
;
642 ra
.sin_addr
.s_addr
= raddr
;
643 return __validuser2_sa(hostf
, (struct sockaddr
*)&ra
, sizeof(ra
),
648 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
650 __checkhost_sa (struct sockaddr
*ra
, size_t ralen
, char *lhost
,
653 struct addrinfo hints
, *res0
, *res
;
654 char raddr
[INET6_ADDRSTRLEN
];
656 int negate
=1; /* Multiply return with this to get -1 instead of 1 */
658 /* Check nis netgroup. */
659 if (strncmp ("+@", lhost
, 2) == 0)
660 return innetgr (&lhost
[2], rhost
, NULL
, NULL
);
662 if (strncmp ("-@", lhost
, 2) == 0)
663 return -innetgr (&lhost
[2], rhost
, NULL
, NULL
);
666 if (strncmp ("-", lhost
,1) == 0) {
669 } else if (strcmp ("+",lhost
) == 0) {
670 return 1; /* asking for trouble, but ok.. */
673 /* Try for raw ip address first. */
675 if (getnameinfo(ra
, ralen
,
676 raddr
, sizeof(raddr
), NULL
, 0,
678 && strcmp(raddr
, lhost
) == 0)
681 /* Better be a hostname. */
683 memset(&hints
, '\0', sizeof(hints
));
684 hints
.ai_family
= ra
->sa_family
;
685 if (getaddrinfo(lhost
, NULL
, &hints
, &res0
) == 0){
686 /* Spin through ip addresses. */
687 for (res
= res0
; res
; res
= res
->ai_next
)
689 if (res
->ai_family
== ra
->sa_family
690 && !memcmp(res
->ai_addr
, ra
, res
->ai_addrlen
))
698 return negate
* match
;
701 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
703 __icheckuser (const char *luser
, const char *ruser
)
706 luser is user entry from .rhosts/hosts.equiv file
707 ruser is user id on remote host
711 if (strncmp ("+@", luser
, 2) == 0)
712 return innetgr (&luser
[2], NULL
, ruser
, NULL
);
714 if (strncmp ("-@", luser
,2) == 0)
715 return -innetgr (&luser
[2], NULL
, ruser
, NULL
);
718 if (strncmp ("-", luser
, 1) == 0)
719 return -(strcmp (&luser
[1], ruser
) == 0);
722 if (strcmp ("+", luser
) == 0)
725 /* simple string match */
726 return strcmp (ruser
, luser
) == 0;
730 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
735 while (*p
&& isspace (*p
)) {
739 return (*p
== '\0' || *p
== '#') ? 1 : 0 ;
743 * Returns 0 if positive match, -1 if _not_ ok.
746 __validuser2_sa (FILE *hostf
, struct sockaddr
*ra
, size_t ralen
,
747 const char *luser
, const char *ruser
, const char *rhost
)
756 while (__getline (&buf
, &bufsize
, hostf
) > 0) {
757 buf
[bufsize
- 1] = '\0'; /* Make sure it's terminated. */
760 /* Skip empty or comment lines */
765 for (;*p
&& !isspace(*p
); ++p
) {
769 /* Next we want to find the permitted name for the remote user. */
770 if (*p
== ' ' || *p
== '\t') {
771 /* <nul> terminate hostname and skip spaces */
772 for (*p
++='\0'; *p
&& isspace (*p
); ++p
);
774 user
= p
; /* this is the user's name */
775 while (*p
&& !isspace (*p
))
776 ++p
; /* find end of user's name */
780 *p
= '\0'; /* <nul> terminate username (+host?) */
782 /* buf -> host(?) ; user -> username(?) */
788 /* First check the user part. In a naive implementation we
789 would check the host part first, then the user. However,
790 if we check the user first and reject the entry we will
791 have saved doing any host lookups to normalize the comparison
792 and that likely saves several DNS queries. Therefore we
793 check the user first. */
794 ucheck
= __icheckuser (user
, ruser
);
796 /* Either we found the user, or we didn't and this is a
797 negative host check. We must do the negative host lookup
798 in order to preserve the semantics of stopping on this line
799 before processing others. */
800 if (ucheck
!= 0 || *buf
== '-') {
802 /* Next check host part. */
803 hcheck
= __checkhost_sa (ra
, ralen
, buf
, rhost
);
805 /* Negative '-host user(?)' match? */
809 /* Positive 'host user' match? */
810 if (hcheck
> 0 && ucheck
> 0) {
815 /* Negative 'host -user' match? */
816 if (hcheck
> 0 && ucheck
< 0)
819 /* Neither, go on looking for match. */