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>
82 #include <shlib-compat.h>
85 int __ivaliduser (FILE *, uint32_t, const char *, const char *);
86 static int __validuser2_sa (FILE *, struct sockaddr
*, size_t,
87 const char *, const char *, const char *);
88 static int ruserok2_sa (struct sockaddr
*ra
, size_t ralen
,
89 int superuser
, const char *ruser
,
90 const char *luser
, const char *rhost
);
91 static int ruserok_sa (struct sockaddr
*ra
, size_t ralen
,
92 int superuser
, const char *ruser
,
94 int iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
95 const char *luser
, sa_family_t af
);
96 int iruserok (uint32_t raddr
, int superuser
, const char *ruser
,
99 libc_hidden_proto (iruserok_af
)
101 libc_freeres_ptr(static char *ahostbuf
);
104 rcmd_af (char **ahost
, u_short rport
, const char *locuser
, const char *remuser
,
105 const char *cmd
, int *fd2p
, sa_family_t af
)
107 char paddr
[INET6_ADDRSTRLEN
];
108 struct addrinfo hints
, *res
, *ai
;
112 struct sockaddr_storage ss
;
113 struct sockaddr_in sin
;
114 struct sockaddr_in6 sin6
;
116 struct pollfd pfd
[2];
117 sigset_t mask
, omask
;
120 int s
, lport
, timo
, error
;
126 if (af
!= AF_INET
&& af
!= AF_INET6
&& af
!= AF_UNSPEC
)
128 __set_errno (EAFNOSUPPORT
);
134 memset(&hints
, '\0', sizeof(hints
));
135 hints
.ai_flags
= AI_CANONNAME
;
136 hints
.ai_family
= af
;
137 hints
.ai_socktype
= SOCK_STREAM
;
138 (void)__snprintf(num
, sizeof(num
), "%d", ntohs(rport
));
139 error
= getaddrinfo(*ahost
, num
, &hints
, &res
);
141 if (error
== EAI_NONAME
&& *ahost
!= NULL
)
142 __fxprintf(NULL
, "%s: Unknown host\n", *ahost
);
144 __fxprintf(NULL
, "rcmd: getaddrinfo: %s\n",
145 gai_strerror(error
));
150 pfd
[0].events
= POLLIN
;
151 pfd
[1].events
= POLLIN
;
153 if (res
->ai_canonname
){
155 ahostbuf
= __strdup (res
->ai_canonname
);
156 if (ahostbuf
== NULL
) {
158 __fxprintf(NULL
, "%s",
159 _("rcmd: Cannot allocate memory\n"));
167 __sigemptyset(&mask
);
168 __sigaddset(&mask
, SIGURG
);
169 __sigprocmask (SIG_BLOCK
, &mask
, &omask
);
170 for (timo
= 1, lport
= IPPORT_RESERVED
- 1;;) {
173 s
= rresvport_af(&lport
, ai
->ai_family
);
176 __fxprintf(NULL
, "%s", _("\
177 rcmd: socket: All ports in use\n"));
179 __fxprintf(NULL
, "rcmd: socket: %m\n");
181 __sigprocmask (SIG_SETMASK
, &omask
, 0);
185 __fcntl(s
, F_SETOWN
, pid
);
186 if (__connect(s
, ai
->ai_addr
, ai
->ai_addrlen
) >= 0)
189 if (errno
== EADDRINUSE
) {
193 if (errno
== ECONNREFUSED
)
195 if (ai
->ai_next
!= NULL
) {
199 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
200 paddr
, sizeof(paddr
),
204 if (__asprintf (&buf
, _("connect to address %s: "),
207 __fxprintf(NULL
, "%s", buf
);
210 __set_errno (oerrno
);
213 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
214 paddr
, sizeof(paddr
),
217 if (__asprintf (&buf
, _("Trying %s...\n"), paddr
) >= 0)
219 __fxprintf (NULL
, "%s", buf
);
224 if (refused
&& timo
<= 16) {
232 (void)__fxprintf(NULL
, "%s: %s\n", *ahost
,
233 __strerror_r(errno
, errbuf
, sizeof (errbuf
)));
234 __sigprocmask (SIG_SETMASK
, &omask
, 0);
243 int s2
= rresvport_af(&lport
, ai
->ai_family
), s3
;
244 socklen_t len
= ai
->ai_addrlen
;
249 (void)__snprintf(num
, sizeof(num
), "%d", lport
);
250 if (__write(s
, num
, strlen(num
)+1) != (ssize_t
)strlen(num
)+1) {
253 if (__asprintf (&buf
, _("\
254 rcmd: write (setting up stderr): %m\n")) >= 0)
256 __fxprintf(NULL
, "%s", buf
);
265 if (__poll (pfd
, 2, -1) < 1 || (pfd
[1].revents
& POLLIN
) == 0){
269 && __asprintf(&buf
, _("\
270 rcmd: poll (setting up stderr): %m\n")) >= 0)
272 && __asprintf(&buf
, _("\
273 poll: protocol failure in circuit setup\n")) >= 0))
275 __fxprintf (NULL
, "%s", buf
);
281 s3
= TEMP_FAILURE_RETRY (accept(s2
, &from
.sa
, &len
));
282 switch (from
.sa
.sa_family
) {
284 rport
= ntohs(from
.sin
.sin_port
);
287 rport
= ntohs(from
.sin6
.sin6_port
);
295 (void)__fxprintf(NULL
, "rcmd: accept: %m\n");
301 if (rport
>= IPPORT_RESERVED
|| rport
< IPPORT_RESERVED
/ 2){
304 if (__asprintf(&buf
, _("\
305 socket: protocol failure in circuit setup\n")) >= 0)
307 __fxprintf (NULL
, "%s", buf
);
313 struct iovec iov
[3] =
315 [0] = { .iov_base
= (void *) locuser
,
316 .iov_len
= strlen (locuser
) + 1 },
317 [1] = { .iov_base
= (void *) remuser
,
318 .iov_len
= strlen (remuser
) + 1 },
319 [2] = { .iov_base
= (void *) cmd
,
320 .iov_len
= strlen (cmd
) + 1 }
322 (void) TEMP_FAILURE_RETRY (__writev (s
, iov
, 3));
323 n
= TEMP_FAILURE_RETRY (__read(s
, &c
, 1));
328 && __asprintf(&buf
, _("rcmd: %s: short read"),
331 && __asprintf(&buf
, "rcmd: %s: %m\n", *ahost
) >= 0))
333 __fxprintf (NULL
, "%s", buf
);
339 while (__read(s
, &c
, 1) == 1) {
340 (void)__write(STDERR_FILENO
, &c
, 1);
346 __sigprocmask (SIG_SETMASK
, &omask
, 0);
351 (void)__close(*fd2p
);
354 __sigprocmask (SIG_SETMASK
, &omask
, 0);
358 libc_hidden_def (rcmd_af
)
361 rcmd (char **ahost
, u_short rport
, const char *locuser
, const char *remuser
,
362 const char *cmd
, int *fd2p
)
364 return rcmd_af (ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
368 rresvport_af (int *alport
, sa_family_t family
)
371 struct sockaddr generic
;
372 struct sockaddr_in in
;
373 struct sockaddr_in6 in6
;
381 len
= sizeof(struct sockaddr_in
);
382 sport
= &ss
.in
.sin_port
;
385 len
= sizeof(struct sockaddr_in6
);
386 sport
= &ss
.in6
.sin6_port
;
389 __set_errno (EAFNOSUPPORT
);
392 /* NB: No SOCK_CLOEXEC for backwards compatibility. */
393 s
= __socket(family
, SOCK_STREAM
, 0);
397 memset (&ss
, '\0', sizeof(ss
));
399 ss
.generic
.__ss_len
= len
;
401 ss
.generic
.sa_family
= family
;
403 /* Ignore invalid values. */
404 if (*alport
< IPPORT_RESERVED
/ 2)
405 *alport
= IPPORT_RESERVED
/ 2;
406 else if (*alport
>= IPPORT_RESERVED
)
407 *alport
= IPPORT_RESERVED
- 1;
411 *sport
= htons((uint16_t) *alport
);
412 if (__bind(s
, &ss
.generic
, len
) >= 0)
414 if (errno
!= EADDRINUSE
) {
418 if ((*alport
)-- == IPPORT_RESERVED
/2)
419 *alport
= IPPORT_RESERVED
- 1;
420 } while (*alport
!= start
);
422 __set_errno (EAGAIN
);
425 libc_hidden_def (rresvport_af
)
428 rresvport (int *alport
)
430 return rresvport_af(alport
, AF_INET
);
433 int __check_rhosts_file
= 1;
437 ruserok_af (const char *rhost
, int superuser
, const char *ruser
,
438 const char *luser
, sa_family_t af
)
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 (const char *rhost
, int superuser
, const char *ruser
,
465 return ruserok_af(rhost
, superuser
, ruser
, luser
, AF_INET
);
468 /* Extremely paranoid file open function. */
470 iruserfopen (const char *file
, uid_t okuser
)
472 struct __stat64_t64 st
;
476 /* If not a regular file, if owned by someone other than user or
477 root, if writeable by anyone but the owner, or if hardlinked
479 if (__lstat64_time64 (file
, &st
))
480 cp
= _("lstat failed");
481 else if (!S_ISREG (st
.st_mode
))
482 cp
= _("not regular file");
485 res
= fopen (file
, "rce");
487 cp
= _("cannot open");
488 else if (__fstat64_time64 (fileno (res
), &st
) < 0)
489 cp
= _("fstat failed");
490 else if (st
.st_uid
&& st
.st_uid
!= okuser
)
492 else if (st
.st_mode
& (S_IWGRP
|S_IWOTH
))
493 cp
= _("writeable by other than owner");
494 else if (st
.st_nlink
> 1)
495 cp
= _("hard linked somewhere");
498 /* If there were any problems, quit. */
507 /* No threads use this stream. */
508 __fsetlocking (res
, FSETLOCKING_BYCALLER
);
514 * New .rhosts strategy: We are passed an ip address. We spin through
515 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
516 * has ip addresses, we don't have to trust a nameserver. When it
517 * contains hostnames, we spin through the list of addresses the nameserver
518 * gives us and look for a match.
520 * Returns 0 if ok, -1 if not ok.
523 ruserok2_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
524 const char *ruser
, const char *luser
, const char *rhost
)
530 hostf
= iruserfopen (_PATH_HEQUIV
, 0);
534 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
541 if (__check_rhosts_file
|| superuser
)
544 struct passwd pwdbuf
, *pwd
;
546 size_t buflen
= __sysconf (_SC_GETPW_R_SIZE_MAX
);
547 char *buffer
= __alloca (buflen
);
550 if (__getpwnam_r (luser
, &pwdbuf
, buffer
, buflen
, &pwd
) != 0
554 dirlen
= strlen (pwd
->pw_dir
);
555 pbuf
= alloca (dirlen
+ sizeof "/.rhosts");
556 __mempcpy (__mempcpy (pbuf
, pwd
->pw_dir
, dirlen
),
557 "/.rhosts", sizeof "/.rhosts");
559 /* Change effective uid while reading .rhosts. If root and
560 reading an NFS mounted file system, can't read files that
561 are protected read/write owner only. */
563 seteuid (pwd
->pw_uid
);
564 hostf
= iruserfopen (pbuf
, pwd
->pw_uid
);
568 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
578 * ruserok_sa() is now discussed on ipng, so
579 * currently disabled for external use
582 ruserok_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
583 const char *ruser
, const char *luser
)
585 return ruserok2_sa(ra
, ralen
, superuser
, ruser
, luser
, "-");
588 /* This is the exported version. */
590 iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
591 const char *luser
, sa_family_t af
)
594 struct sockaddr generic
;
595 struct sockaddr_in in
;
596 struct sockaddr_in6 in6
;
600 memset (&ra
, '\0', sizeof(ra
));
603 ra
.in
.sin_family
= AF_INET
;
604 memcpy (&ra
.in
.sin_addr
, raddr
, sizeof(struct in_addr
));
605 ralen
= sizeof(struct sockaddr_in
);
608 ra
.in6
.sin6_family
= AF_INET6
;
609 memcpy (&ra
.in6
.sin6_addr
, raddr
, sizeof(struct in6_addr
));
610 ralen
= sizeof(struct sockaddr_in6
);
615 return ruserok_sa (&ra
.generic
, ralen
, superuser
, ruser
, luser
);
617 libc_hidden_def (iruserok_af
)
620 iruserok (uint32_t raddr
, int superuser
, const char *ruser
, const char *luser
)
622 return iruserok_af (&raddr
, superuser
, ruser
, luser
, AF_INET
);
625 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_37)
626 /* Previously used by lpd. Current lpd versions have their own copy. */
627 int attribute_compat_text_section
628 __ivaliduser (FILE *hostf
, uint32_t raddr
, const char *luser
,
631 struct sockaddr_in ra
;
632 memset(&ra
, '\0', sizeof(ra
));
633 ra
.sin_family
= AF_INET
;
634 ra
.sin_addr
.s_addr
= raddr
;
635 return __validuser2_sa(hostf
, (struct sockaddr
*)&ra
, sizeof(ra
),
638 compat_symbol (libc
, __ivaliduser
, __ivaliduser
, GLIBC_2_0
);
641 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
643 __checkhost_sa (struct sockaddr
*ra
, size_t ralen
, char *lhost
,
646 struct addrinfo hints
, *res0
, *res
;
647 char raddr
[INET6_ADDRSTRLEN
];
649 int negate
=1; /* Multiply return with this to get -1 instead of 1 */
651 /* Check nis netgroup. */
652 if (strncmp ("+@", lhost
, 2) == 0)
653 return innetgr (&lhost
[2], rhost
, NULL
, NULL
);
655 if (strncmp ("-@", lhost
, 2) == 0)
656 return -innetgr (&lhost
[2], rhost
, NULL
, NULL
);
659 if (strncmp ("-", lhost
,1) == 0) {
662 } else if (strcmp ("+",lhost
) == 0) {
663 return 1; /* asking for trouble, but ok.. */
666 /* Try for raw ip address first. */
668 if (getnameinfo(ra
, ralen
,
669 raddr
, sizeof(raddr
), NULL
, 0,
671 && strcmp(raddr
, lhost
) == 0)
674 /* Better be a hostname. */
676 memset(&hints
, '\0', sizeof(hints
));
677 hints
.ai_family
= ra
->sa_family
;
678 if (getaddrinfo(lhost
, NULL
, &hints
, &res0
) == 0){
679 /* Spin through ip addresses. */
680 for (res
= res0
; res
; res
= res
->ai_next
)
682 if (res
->ai_family
== ra
->sa_family
683 && !memcmp(res
->ai_addr
, ra
, res
->ai_addrlen
))
691 return negate
* match
;
694 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
696 __icheckuser (const char *luser
, const char *ruser
)
699 luser is user entry from .rhosts/hosts.equiv file
700 ruser is user id on remote host
704 if (strncmp ("+@", luser
, 2) == 0)
705 return innetgr (&luser
[2], NULL
, ruser
, NULL
);
707 if (strncmp ("-@", luser
,2) == 0)
708 return -innetgr (&luser
[2], NULL
, ruser
, NULL
);
711 if (strncmp ("-", luser
, 1) == 0)
712 return -(strcmp (&luser
[1], ruser
) == 0);
715 if (strcmp ("+", luser
) == 0)
718 /* simple string match */
719 return strcmp (ruser
, luser
) == 0;
723 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
728 while (*p
&& isspace (*p
)) {
732 return (*p
== '\0' || *p
== '#') ? 1 : 0 ;
736 * Returns 0 if positive match, -1 if _not_ ok.
739 __validuser2_sa (FILE *hostf
, struct sockaddr
*ra
, size_t ralen
,
740 const char *luser
, const char *ruser
, const char *rhost
)
749 while (__getline (&buf
, &bufsize
, hostf
) > 0) {
750 buf
[bufsize
- 1] = '\0'; /* Make sure it's terminated. */
753 /* Skip empty or comment lines */
758 for (;*p
&& !isspace(*p
); ++p
) {
762 /* Next we want to find the permitted name for the remote user. */
763 if (*p
== ' ' || *p
== '\t') {
764 /* <nul> terminate hostname and skip spaces */
765 for (*p
++='\0'; *p
&& isspace (*p
); ++p
);
767 user
= p
; /* this is the user's name */
768 while (*p
&& !isspace (*p
))
769 ++p
; /* find end of user's name */
773 *p
= '\0'; /* <nul> terminate username (+host?) */
775 /* buf -> host(?) ; user -> username(?) */
781 /* First check the user part. In a naive implementation we
782 would check the host part first, then the user. However,
783 if we check the user first and reject the entry we will
784 have saved doing any host lookups to normalize the comparison
785 and that likely saves several DNS queries. Therefore we
786 check the user first. */
787 ucheck
= __icheckuser (user
, ruser
);
789 /* Either we found the user, or we didn't and this is a
790 negative host check. We must do the negative host lookup
791 in order to preserve the semantics of stopping on this line
792 before processing others. */
793 if (ucheck
!= 0 || *buf
== '-') {
795 /* Next check host part. */
796 hcheck
= __checkhost_sa (ra
, ralen
, buf
, rhost
);
798 /* Negative '-host user(?)' match? */
802 /* Positive 'host user' match? */
803 if (hcheck
> 0 && ucheck
> 0) {
808 /* Negative 'host -user' match? */
809 if (hcheck
> 0 && ucheck
< 0)
812 /* Neither, go on looking for match. */