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
) {
156 __fxprintf(NULL
, "%s",
157 _("rcmd: Cannot allocate memory\n"));
165 __sigemptyset(&mask
);
166 __sigaddset(&mask
, SIGURG
);
167 __sigprocmask (SIG_BLOCK
, &mask
, &omask
);
168 for (timo
= 1, lport
= IPPORT_RESERVED
- 1;;) {
171 s
= rresvport_af(&lport
, ai
->ai_family
);
174 __fxprintf(NULL
, "%s", _("\
175 rcmd: socket: All ports in use\n"));
177 __fxprintf(NULL
, "rcmd: socket: %m\n");
179 __sigprocmask (SIG_SETMASK
, &omask
, 0);
183 __fcntl(s
, F_SETOWN
, pid
);
184 if (__connect(s
, ai
->ai_addr
, ai
->ai_addrlen
) >= 0)
187 if (errno
== EADDRINUSE
) {
191 if (errno
== ECONNREFUSED
)
193 if (ai
->ai_next
!= NULL
) {
197 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
198 paddr
, sizeof(paddr
),
202 if (__asprintf (&buf
, _("connect to address %s: "),
205 __fxprintf(NULL
, "%s", buf
);
208 __set_errno (oerrno
);
211 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
212 paddr
, sizeof(paddr
),
215 if (__asprintf (&buf
, _("Trying %s...\n"), paddr
) >= 0)
217 __fxprintf (NULL
, "%s", buf
);
222 if (refused
&& timo
<= 16) {
230 (void)__fxprintf(NULL
, "%s: %s\n", *ahost
,
231 __strerror_r(errno
, errbuf
, sizeof (errbuf
)));
232 __sigprocmask (SIG_SETMASK
, &omask
, 0);
241 int s2
= rresvport_af(&lport
, ai
->ai_family
), s3
;
242 socklen_t len
= ai
->ai_addrlen
;
247 (void)__snprintf(num
, sizeof(num
), "%d", lport
);
248 if (__write(s
, num
, strlen(num
)+1) != (ssize_t
)strlen(num
)+1) {
251 if (__asprintf (&buf
, _("\
252 rcmd: write (setting up stderr): %m\n")) >= 0)
254 __fxprintf(NULL
, "%s", buf
);
263 if (__poll (pfd
, 2, -1) < 1 || (pfd
[1].revents
& POLLIN
) == 0){
267 && __asprintf(&buf
, _("\
268 rcmd: poll (setting up stderr): %m\n")) >= 0)
270 && __asprintf(&buf
, _("\
271 poll: protocol failure in circuit setup\n")) >= 0))
273 __fxprintf (NULL
, "%s", buf
);
279 s3
= TEMP_FAILURE_RETRY (accept(s2
, &from
.sa
, &len
));
280 switch (from
.sa
.sa_family
) {
282 rport
= ntohs(from
.sin
.sin_port
);
285 rport
= ntohs(from
.sin6
.sin6_port
);
293 (void)__fxprintf(NULL
, "rcmd: accept: %m\n");
299 if (rport
>= IPPORT_RESERVED
|| rport
< IPPORT_RESERVED
/ 2){
302 if (__asprintf(&buf
, _("\
303 socket: protocol failure in circuit setup\n")) >= 0)
305 __fxprintf (NULL
, "%s", buf
);
311 struct iovec iov
[3] =
313 [0] = { .iov_base
= (void *) locuser
,
314 .iov_len
= strlen (locuser
) + 1 },
315 [1] = { .iov_base
= (void *) remuser
,
316 .iov_len
= strlen (remuser
) + 1 },
317 [2] = { .iov_base
= (void *) cmd
,
318 .iov_len
= strlen (cmd
) + 1 }
320 (void) TEMP_FAILURE_RETRY (__writev (s
, iov
, 3));
321 n
= TEMP_FAILURE_RETRY (__read(s
, &c
, 1));
326 && __asprintf(&buf
, _("rcmd: %s: short read"),
329 && __asprintf(&buf
, "rcmd: %s: %m\n", *ahost
) >= 0))
331 __fxprintf (NULL
, "%s", buf
);
337 while (__read(s
, &c
, 1) == 1) {
338 (void)__write(STDERR_FILENO
, &c
, 1);
344 __sigprocmask (SIG_SETMASK
, &omask
, 0);
349 (void)__close(*fd2p
);
352 __sigprocmask (SIG_SETMASK
, &omask
, 0);
356 libc_hidden_def (rcmd_af
)
359 rcmd (char **ahost
, u_short rport
, const char *locuser
, const char *remuser
,
360 const char *cmd
, int *fd2p
)
362 return rcmd_af (ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
366 rresvport_af (int *alport
, sa_family_t family
)
369 struct sockaddr generic
;
370 struct sockaddr_in in
;
371 struct sockaddr_in6 in6
;
379 len
= sizeof(struct sockaddr_in
);
380 sport
= &ss
.in
.sin_port
;
383 len
= sizeof(struct sockaddr_in6
);
384 sport
= &ss
.in6
.sin6_port
;
387 __set_errno (EAFNOSUPPORT
);
390 /* NB: No SOCK_CLOEXEC for backwards compatibility. */
391 s
= __socket(family
, SOCK_STREAM
, 0);
395 memset (&ss
, '\0', sizeof(ss
));
397 ss
.generic
.__ss_len
= len
;
399 ss
.generic
.sa_family
= family
;
401 /* Ignore invalid values. */
402 if (*alport
< IPPORT_RESERVED
/ 2)
403 *alport
= IPPORT_RESERVED
/ 2;
404 else if (*alport
>= IPPORT_RESERVED
)
405 *alport
= IPPORT_RESERVED
- 1;
409 *sport
= htons((uint16_t) *alport
);
410 if (__bind(s
, &ss
.generic
, len
) >= 0)
412 if (errno
!= EADDRINUSE
) {
416 if ((*alport
)-- == IPPORT_RESERVED
/2)
417 *alport
= IPPORT_RESERVED
- 1;
418 } while (*alport
!= start
);
420 __set_errno (EAGAIN
);
423 libc_hidden_def (rresvport_af
)
426 rresvport (int *alport
)
428 return rresvport_af(alport
, AF_INET
);
431 int __check_rhosts_file
= 1;
435 ruserok_af (const char *rhost
, int superuser
, const char *ruser
,
436 const char *luser
, sa_family_t af
)
438 struct addrinfo hints
, *res
, *res0
;
442 memset (&hints
, '\0', sizeof(hints
));
443 hints
.ai_family
= af
;
444 gai
= getaddrinfo(rhost
, NULL
, &hints
, &res0
);
448 for (res
=res0
; res
; res
=res
->ai_next
)
449 if (ruserok2_sa(res
->ai_addr
, res
->ai_addrlen
,
450 superuser
, ruser
, luser
, rhost
) == 0){
457 libc_hidden_def (ruserok_af
)
460 ruserok (const char *rhost
, int superuser
, const char *ruser
,
463 return ruserok_af(rhost
, superuser
, ruser
, luser
, AF_INET
);
466 /* Extremely paranoid file open function. */
468 iruserfopen (const char *file
, uid_t okuser
)
474 /* If not a regular file, if owned by someone other than user or
475 root, if writeable by anyone but the owner, or if hardlinked
477 if (__lxstat64 (_STAT_VER
, file
, &st
))
478 cp
= _("lstat failed");
479 else if (!S_ISREG (st
.st_mode
))
480 cp
= _("not regular file");
483 res
= fopen (file
, "rce");
485 cp
= _("cannot open");
486 else if (__fxstat64 (_STAT_VER
, fileno (res
), &st
) < 0)
487 cp
= _("fstat failed");
488 else if (st
.st_uid
&& st
.st_uid
!= okuser
)
490 else if (st
.st_mode
& (S_IWGRP
|S_IWOTH
))
491 cp
= _("writeable by other than owner");
492 else if (st
.st_nlink
> 1)
493 cp
= _("hard linked somewhere");
496 /* If there were any problems, quit. */
505 /* No threads use this stream. */
506 __fsetlocking (res
, FSETLOCKING_BYCALLER
);
512 * New .rhosts strategy: We are passed an ip address. We spin through
513 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
514 * has ip addresses, we don't have to trust a nameserver. When it
515 * contains hostnames, we spin through the list of addresses the nameserver
516 * gives us and look for a match.
518 * Returns 0 if ok, -1 if not ok.
521 ruserok2_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
522 const char *ruser
, const char *luser
, const char *rhost
)
528 hostf
= iruserfopen (_PATH_HEQUIV
, 0);
532 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
539 if (__check_rhosts_file
|| superuser
)
542 struct passwd pwdbuf
, *pwd
;
544 size_t buflen
= __sysconf (_SC_GETPW_R_SIZE_MAX
);
545 char *buffer
= __alloca (buflen
);
548 if (__getpwnam_r (luser
, &pwdbuf
, buffer
, buflen
, &pwd
) != 0
552 dirlen
= strlen (pwd
->pw_dir
);
553 pbuf
= alloca (dirlen
+ sizeof "/.rhosts");
554 __mempcpy (__mempcpy (pbuf
, pwd
->pw_dir
, dirlen
),
555 "/.rhosts", sizeof "/.rhosts");
557 /* Change effective uid while reading .rhosts. If root and
558 reading an NFS mounted file system, can't read files that
559 are protected read/write owner only. */
561 seteuid (pwd
->pw_uid
);
562 hostf
= iruserfopen (pbuf
, pwd
->pw_uid
);
566 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
576 * ruserok_sa() is now discussed on ipng, so
577 * currently disabled for external use
580 ruserok_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
581 const char *ruser
, const char *luser
)
583 return ruserok2_sa(ra
, ralen
, superuser
, ruser
, luser
, "-");
586 /* This is the exported version. */
588 iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
589 const char *luser
, sa_family_t af
)
592 struct sockaddr generic
;
593 struct sockaddr_in in
;
594 struct sockaddr_in6 in6
;
598 memset (&ra
, '\0', sizeof(ra
));
601 ra
.in
.sin_family
= AF_INET
;
602 memcpy (&ra
.in
.sin_addr
, raddr
, sizeof(struct in_addr
));
603 ralen
= sizeof(struct sockaddr_in
);
606 ra
.in6
.sin6_family
= AF_INET6
;
607 memcpy (&ra
.in6
.sin6_addr
, raddr
, sizeof(struct in6_addr
));
608 ralen
= sizeof(struct sockaddr_in6
);
613 return ruserok_sa (&ra
.generic
, ralen
, superuser
, ruser
, luser
);
615 libc_hidden_def (iruserok_af
)
618 iruserok (uint32_t raddr
, int superuser
, const char *ruser
, const char *luser
)
620 return iruserok_af (&raddr
, superuser
, ruser
, luser
, AF_INET
);
625 * Don't make static, used by lpd(8).
627 * This function is not used anymore. It is only present because lpd(8)
628 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
629 * argument. This means that netgroups won't work in .rhost/hosts.equiv
630 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
632 * Returns 0 if ok, -1 if not ok.
635 __ivaliduser (FILE *hostf
, uint32_t raddr
, const char *luser
,
638 struct sockaddr_in ra
;
639 memset(&ra
, '\0', sizeof(ra
));
640 ra
.sin_family
= AF_INET
;
641 ra
.sin_addr
.s_addr
= raddr
;
642 return __validuser2_sa(hostf
, (struct sockaddr
*)&ra
, sizeof(ra
),
647 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
649 __checkhost_sa (struct sockaddr
*ra
, size_t ralen
, char *lhost
,
652 struct addrinfo hints
, *res0
, *res
;
653 char raddr
[INET6_ADDRSTRLEN
];
655 int negate
=1; /* Multiply return with this to get -1 instead of 1 */
657 /* Check nis netgroup. */
658 if (strncmp ("+@", lhost
, 2) == 0)
659 return innetgr (&lhost
[2], rhost
, NULL
, NULL
);
661 if (strncmp ("-@", lhost
, 2) == 0)
662 return -innetgr (&lhost
[2], rhost
, NULL
, NULL
);
665 if (strncmp ("-", lhost
,1) == 0) {
668 } else if (strcmp ("+",lhost
) == 0) {
669 return 1; /* asking for trouble, but ok.. */
672 /* Try for raw ip address first. */
674 if (getnameinfo(ra
, ralen
,
675 raddr
, sizeof(raddr
), NULL
, 0,
677 && strcmp(raddr
, lhost
) == 0)
680 /* Better be a hostname. */
682 memset(&hints
, '\0', sizeof(hints
));
683 hints
.ai_family
= ra
->sa_family
;
684 if (getaddrinfo(lhost
, NULL
, &hints
, &res0
) == 0){
685 /* Spin through ip addresses. */
686 for (res
= res0
; res
; res
= res
->ai_next
)
688 if (res
->ai_family
== ra
->sa_family
689 && !memcmp(res
->ai_addr
, ra
, res
->ai_addrlen
))
697 return negate
* match
;
700 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
702 __icheckuser (const char *luser
, const char *ruser
)
705 luser is user entry from .rhosts/hosts.equiv file
706 ruser is user id on remote host
710 if (strncmp ("+@", luser
, 2) == 0)
711 return innetgr (&luser
[2], NULL
, ruser
, NULL
);
713 if (strncmp ("-@", luser
,2) == 0)
714 return -innetgr (&luser
[2], NULL
, ruser
, NULL
);
717 if (strncmp ("-", luser
, 1) == 0)
718 return -(strcmp (&luser
[1], ruser
) == 0);
721 if (strcmp ("+", luser
) == 0)
724 /* simple string match */
725 return strcmp (ruser
, luser
) == 0;
729 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
734 while (*p
&& isspace (*p
)) {
738 return (*p
== '\0' || *p
== '#') ? 1 : 0 ;
742 * Returns 0 if positive match, -1 if _not_ ok.
745 __validuser2_sa (FILE *hostf
, struct sockaddr
*ra
, size_t ralen
,
746 const char *luser
, const char *ruser
, const char *rhost
)
755 while (__getline (&buf
, &bufsize
, hostf
) > 0) {
756 buf
[bufsize
- 1] = '\0'; /* Make sure it's terminated. */
759 /* Skip empty or comment lines */
764 for (;*p
&& !isspace(*p
); ++p
) {
768 /* Next we want to find the permitted name for the remote user. */
769 if (*p
== ' ' || *p
== '\t') {
770 /* <nul> terminate hostname and skip spaces */
771 for (*p
++='\0'; *p
&& isspace (*p
); ++p
);
773 user
= p
; /* this is the user's name */
774 while (*p
&& !isspace (*p
))
775 ++p
; /* find end of user's name */
779 *p
= '\0'; /* <nul> terminate username (+host?) */
781 /* buf -> host(?) ; user -> username(?) */
787 /* First check the user part. In a naive implementation we
788 would check the host part first, then the user. However,
789 if we check the user first and reject the entry we will
790 have saved doing any host lookups to normalize the comparison
791 and that likely saves several DNS queries. Therefore we
792 check the user first. */
793 ucheck
= __icheckuser (user
, ruser
);
795 /* Either we found the user, or we didn't and this is a
796 negative host check. We must do the negative host lookup
797 in order to preserve the semantics of stopping on this line
798 before processing others. */
799 if (ucheck
!= 0 || *buf
== '-') {
801 /* Next check host part. */
802 hcheck
= __checkhost_sa (ra
, ralen
, buf
, rhost
);
804 /* Negative '-host user(?)' match? */
808 /* Positive 'host user' match? */
809 if (hcheck
> 0 && ucheck
> 0) {
814 /* Negative 'host -user' match? */
815 if (hcheck
> 0 && ucheck
< 0)
818 /* Neither, go on looking for match. */