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>
83 #include <set-freeres.h>
86 int __ivaliduser (FILE *, uint32_t, const char *, const char *);
87 static int __validuser2_sa (FILE *, struct sockaddr
*, size_t,
88 const char *, const char *, const char *);
89 static int ruserok2_sa (struct sockaddr
*ra
, size_t ralen
,
90 int superuser
, const char *ruser
,
91 const char *luser
, const char *rhost
);
92 static int ruserok_sa (struct sockaddr
*ra
, size_t ralen
,
93 int superuser
, const char *ruser
,
95 int iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
96 const char *luser
, sa_family_t af
);
97 int iruserok (uint32_t raddr
, int superuser
, const char *ruser
,
100 libc_hidden_proto (iruserok_af
)
102 static char *ahostbuf
;
105 rcmd_af (char **ahost
, u_short rport
, const char *locuser
, const char *remuser
,
106 const char *cmd
, int *fd2p
, sa_family_t af
)
108 char paddr
[INET6_ADDRSTRLEN
];
109 struct addrinfo hints
, *res
, *ai
;
113 struct sockaddr_storage ss
;
114 struct sockaddr_in sin
;
115 struct sockaddr_in6 sin6
;
117 struct pollfd pfd
[2];
118 sigset_t mask
, omask
;
121 int s
, lport
, timo
, error
;
127 if (af
!= AF_INET
&& af
!= AF_INET6
&& af
!= AF_UNSPEC
)
129 __set_errno (EAFNOSUPPORT
);
135 memset(&hints
, '\0', sizeof(hints
));
136 hints
.ai_flags
= AI_CANONNAME
;
137 hints
.ai_family
= af
;
138 hints
.ai_socktype
= SOCK_STREAM
;
139 (void)__snprintf(num
, sizeof(num
), "%d", ntohs(rport
));
140 error
= getaddrinfo(*ahost
, num
, &hints
, &res
);
142 if (error
== EAI_NONAME
&& *ahost
!= NULL
)
143 __fxprintf(NULL
, "%s: Unknown host\n", *ahost
);
145 __fxprintf(NULL
, "rcmd: getaddrinfo: %s\n",
146 gai_strerror(error
));
151 pfd
[0].events
= POLLIN
;
152 pfd
[1].events
= POLLIN
;
154 if (res
->ai_canonname
){
156 ahostbuf
= __strdup (res
->ai_canonname
);
157 if (ahostbuf
== NULL
) {
159 __fxprintf(NULL
, "%s",
160 _("rcmd: Cannot allocate memory\n"));
168 __sigemptyset(&mask
);
169 __sigaddset(&mask
, SIGURG
);
170 __sigprocmask (SIG_BLOCK
, &mask
, &omask
);
171 for (timo
= 1, lport
= IPPORT_RESERVED
- 1;;) {
174 s
= rresvport_af(&lport
, ai
->ai_family
);
177 __fxprintf(NULL
, "%s", _("\
178 rcmd: socket: All ports in use\n"));
180 __fxprintf(NULL
, "rcmd: socket: %m\n");
182 __sigprocmask (SIG_SETMASK
, &omask
, 0);
186 __fcntl(s
, F_SETOWN
, pid
);
187 if (__connect(s
, ai
->ai_addr
, ai
->ai_addrlen
) >= 0)
190 if (errno
== EADDRINUSE
) {
194 if (errno
== ECONNREFUSED
)
196 if (ai
->ai_next
!= NULL
) {
200 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
201 paddr
, sizeof(paddr
),
205 if (__asprintf (&buf
, _("connect to address %s: "),
208 __fxprintf(NULL
, "%s", buf
);
211 __set_errno (oerrno
);
214 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
215 paddr
, sizeof(paddr
),
218 if (__asprintf (&buf
, _("Trying %s...\n"), paddr
) >= 0)
220 __fxprintf (NULL
, "%s", buf
);
225 if (refused
&& timo
<= 16) {
233 (void)__fxprintf(NULL
, "%s: %s\n", *ahost
,
234 __strerror_r(errno
, errbuf
, sizeof (errbuf
)));
235 __sigprocmask (SIG_SETMASK
, &omask
, 0);
244 int s2
= rresvport_af(&lport
, ai
->ai_family
), s3
;
245 socklen_t len
= ai
->ai_addrlen
;
250 (void)__snprintf(num
, sizeof(num
), "%d", lport
);
251 if (__write(s
, num
, strlen(num
)+1) != (ssize_t
)strlen(num
)+1) {
254 if (__asprintf (&buf
, _("\
255 rcmd: write (setting up stderr): %m\n")) >= 0)
257 __fxprintf(NULL
, "%s", buf
);
266 if (__poll (pfd
, 2, -1) < 1 || (pfd
[1].revents
& POLLIN
) == 0){
270 && __asprintf(&buf
, _("\
271 rcmd: poll (setting up stderr): %m\n")) >= 0)
273 && __asprintf(&buf
, _("\
274 poll: protocol failure in circuit setup\n")) >= 0))
276 __fxprintf (NULL
, "%s", buf
);
282 s3
= TEMP_FAILURE_RETRY (accept(s2
, &from
.sa
, &len
));
283 switch (from
.sa
.sa_family
) {
285 rport
= ntohs(from
.sin
.sin_port
);
288 rport
= ntohs(from
.sin6
.sin6_port
);
296 (void)__fxprintf(NULL
, "rcmd: accept: %m\n");
302 if (rport
>= IPPORT_RESERVED
|| rport
< IPPORT_RESERVED
/ 2){
305 if (__asprintf(&buf
, _("\
306 socket: protocol failure in circuit setup\n")) >= 0)
308 __fxprintf (NULL
, "%s", buf
);
314 struct iovec iov
[3] =
316 [0] = { .iov_base
= (void *) locuser
,
317 .iov_len
= strlen (locuser
) + 1 },
318 [1] = { .iov_base
= (void *) remuser
,
319 .iov_len
= strlen (remuser
) + 1 },
320 [2] = { .iov_base
= (void *) cmd
,
321 .iov_len
= strlen (cmd
) + 1 }
323 (void) TEMP_FAILURE_RETRY (__writev (s
, iov
, 3));
324 n
= TEMP_FAILURE_RETRY (__read(s
, &c
, 1));
329 && __asprintf(&buf
, _("rcmd: %s: short read"),
332 && __asprintf(&buf
, "rcmd: %s: %m\n", *ahost
) >= 0))
334 __fxprintf (NULL
, "%s", buf
);
340 while (__read(s
, &c
, 1) == 1) {
341 (void)__write(STDERR_FILENO
, &c
, 1);
347 __sigprocmask (SIG_SETMASK
, &omask
, 0);
352 (void)__close(*fd2p
);
355 __sigprocmask (SIG_SETMASK
, &omask
, 0);
359 libc_hidden_def (rcmd_af
)
362 rcmd (char **ahost
, u_short rport
, const char *locuser
, const char *remuser
,
363 const char *cmd
, int *fd2p
)
365 return rcmd_af (ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
369 rresvport_af (int *alport
, sa_family_t family
)
372 struct sockaddr generic
;
373 struct sockaddr_in in
;
374 struct sockaddr_in6 in6
;
382 len
= sizeof(struct sockaddr_in
);
383 sport
= &ss
.in
.sin_port
;
386 len
= sizeof(struct sockaddr_in6
);
387 sport
= &ss
.in6
.sin6_port
;
390 __set_errno (EAFNOSUPPORT
);
393 /* NB: No SOCK_CLOEXEC for backwards compatibility. */
394 s
= __socket(family
, SOCK_STREAM
, 0);
398 memset (&ss
, '\0', sizeof(ss
));
400 ss
.generic
.__ss_len
= len
;
402 ss
.generic
.sa_family
= family
;
404 /* Ignore invalid values. */
405 if (*alport
< IPPORT_RESERVED
/ 2)
406 *alport
= IPPORT_RESERVED
/ 2;
407 else if (*alport
>= IPPORT_RESERVED
)
408 *alport
= IPPORT_RESERVED
- 1;
412 *sport
= htons((uint16_t) *alport
);
413 if (__bind(s
, &ss
.generic
, len
) >= 0)
415 if (errno
!= EADDRINUSE
) {
419 if ((*alport
)-- == IPPORT_RESERVED
/2)
420 *alport
= IPPORT_RESERVED
- 1;
421 } while (*alport
!= start
);
423 __set_errno (EAGAIN
);
426 libc_hidden_def (rresvport_af
)
429 rresvport (int *alport
)
431 return rresvport_af(alport
, AF_INET
);
434 int __check_rhosts_file
= 1;
438 ruserok_af (const char *rhost
, int superuser
, const char *ruser
,
439 const char *luser
, sa_family_t af
)
441 struct addrinfo hints
, *res
, *res0
;
445 memset (&hints
, '\0', sizeof(hints
));
446 hints
.ai_family
= af
;
447 gai
= getaddrinfo(rhost
, NULL
, &hints
, &res0
);
451 for (res
=res0
; res
; res
=res
->ai_next
)
452 if (ruserok2_sa(res
->ai_addr
, res
->ai_addrlen
,
453 superuser
, ruser
, luser
, rhost
) == 0){
460 libc_hidden_def (ruserok_af
)
463 ruserok (const char *rhost
, int superuser
, const char *ruser
,
466 return ruserok_af(rhost
, superuser
, ruser
, luser
, AF_INET
);
469 /* Extremely paranoid file open function. */
471 iruserfopen (const char *file
, uid_t okuser
)
473 struct __stat64_t64 st
;
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 (__lstat64_time64 (file
, &st
))
481 cp
= _("lstat failed");
482 else if (!S_ISREG (st
.st_mode
))
483 cp
= _("not regular file");
486 res
= fopen (file
, "rce");
488 cp
= _("cannot open");
489 else if (__fstat64_time64 (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 (struct sockaddr
*ra
, size_t ralen
, int superuser
,
525 const char *ruser
, const char *luser
, const char *rhost
)
531 hostf
= iruserfopen (_PATH_HEQUIV
, 0);
535 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
542 if (__check_rhosts_file
|| superuser
)
545 struct passwd pwdbuf
, *pwd
;
547 size_t buflen
= __sysconf (_SC_GETPW_R_SIZE_MAX
);
548 char *buffer
= __alloca (buflen
);
551 if (__getpwnam_r (luser
, &pwdbuf
, buffer
, buflen
, &pwd
) != 0
555 dirlen
= strlen (pwd
->pw_dir
);
556 pbuf
= alloca (dirlen
+ sizeof "/.rhosts");
557 __mempcpy (__mempcpy (pbuf
, pwd
->pw_dir
, dirlen
),
558 "/.rhosts", sizeof "/.rhosts");
560 /* Change effective uid while reading .rhosts. If root and
561 reading an NFS mounted file system, can't read files that
562 are protected read/write owner only. */
564 if (seteuid (pwd
->pw_uid
) < 0)
567 hostf
= iruserfopen (pbuf
, pwd
->pw_uid
);
571 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
575 if (seteuid (uid
) < 0)
582 * ruserok_sa() is now discussed on ipng, so
583 * currently disabled for external use
586 ruserok_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
587 const char *ruser
, const char *luser
)
589 return ruserok2_sa(ra
, ralen
, superuser
, ruser
, luser
, "-");
592 /* This is the exported version. */
594 iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
595 const char *luser
, sa_family_t af
)
598 struct sockaddr generic
;
599 struct sockaddr_in in
;
600 struct sockaddr_in6 in6
;
604 memset (&ra
, '\0', sizeof(ra
));
607 ra
.in
.sin_family
= AF_INET
;
608 memcpy (&ra
.in
.sin_addr
, raddr
, sizeof(struct in_addr
));
609 ralen
= sizeof(struct sockaddr_in
);
612 ra
.in6
.sin6_family
= AF_INET6
;
613 memcpy (&ra
.in6
.sin6_addr
, raddr
, sizeof(struct in6_addr
));
614 ralen
= sizeof(struct sockaddr_in6
);
619 return ruserok_sa (&ra
.generic
, ralen
, superuser
, ruser
, luser
);
621 libc_hidden_def (iruserok_af
)
624 iruserok (uint32_t raddr
, int superuser
, const char *ruser
, const char *luser
)
626 return iruserok_af (&raddr
, superuser
, ruser
, luser
, AF_INET
);
629 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_37)
630 /* Previously used by lpd. Current lpd versions have their own copy. */
631 int attribute_compat_text_section
632 __ivaliduser (FILE *hostf
, uint32_t raddr
, const char *luser
,
635 struct sockaddr_in ra
;
636 memset(&ra
, '\0', sizeof(ra
));
637 ra
.sin_family
= AF_INET
;
638 ra
.sin_addr
.s_addr
= raddr
;
639 return __validuser2_sa(hostf
, (struct sockaddr
*)&ra
, sizeof(ra
),
642 compat_symbol (libc
, __ivaliduser
, __ivaliduser
, GLIBC_2_0
);
645 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
647 __checkhost_sa (struct sockaddr
*ra
, size_t ralen
, char *lhost
,
650 struct addrinfo hints
, *res0
, *res
;
651 char raddr
[INET6_ADDRSTRLEN
];
653 int negate
=1; /* Multiply return with this to get -1 instead of 1 */
655 /* Check nis netgroup. */
656 if (strncmp ("+@", lhost
, 2) == 0)
657 return innetgr (&lhost
[2], rhost
, NULL
, NULL
);
659 if (strncmp ("-@", lhost
, 2) == 0)
660 return -innetgr (&lhost
[2], rhost
, NULL
, NULL
);
663 if (strncmp ("-", lhost
,1) == 0) {
666 } else if (strcmp ("+",lhost
) == 0) {
667 return 1; /* asking for trouble, but ok.. */
670 /* Try for raw ip address first. */
672 if (getnameinfo(ra
, ralen
,
673 raddr
, sizeof(raddr
), NULL
, 0,
675 && strcmp(raddr
, lhost
) == 0)
678 /* Better be a hostname. */
680 memset(&hints
, '\0', sizeof(hints
));
681 hints
.ai_family
= ra
->sa_family
;
682 if (getaddrinfo(lhost
, NULL
, &hints
, &res0
) == 0){
683 /* Spin through ip addresses. */
684 for (res
= res0
; res
; res
= res
->ai_next
)
686 if (res
->ai_family
== ra
->sa_family
687 && !memcmp(res
->ai_addr
, ra
, res
->ai_addrlen
))
695 return negate
* match
;
698 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
700 __icheckuser (const char *luser
, const char *ruser
)
703 luser is user entry from .rhosts/hosts.equiv file
704 ruser is user id on remote host
708 if (strncmp ("+@", luser
, 2) == 0)
709 return innetgr (&luser
[2], NULL
, ruser
, NULL
);
711 if (strncmp ("-@", luser
,2) == 0)
712 return -innetgr (&luser
[2], NULL
, ruser
, NULL
);
715 if (strncmp ("-", luser
, 1) == 0)
716 return -(strcmp (&luser
[1], ruser
) == 0);
719 if (strcmp ("+", luser
) == 0)
722 /* simple string match */
723 return strcmp (ruser
, luser
) == 0;
727 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
732 while (*p
&& isspace (*p
)) {
736 return (*p
== '\0' || *p
== '#') ? 1 : 0 ;
740 * Returns 0 if positive match, -1 if _not_ ok.
743 __validuser2_sa (FILE *hostf
, struct sockaddr
*ra
, size_t ralen
,
744 const char *luser
, const char *ruser
, const char *rhost
)
753 while (__getline (&buf
, &bufsize
, hostf
) > 0) {
754 buf
[bufsize
- 1] = '\0'; /* Make sure it's terminated. */
757 /* Skip empty or comment lines */
762 for (;*p
&& !isspace(*p
); ++p
) {
766 /* Next we want to find the permitted name for the remote user. */
767 if (*p
== ' ' || *p
== '\t') {
768 /* <nul> terminate hostname and skip spaces */
769 for (*p
++='\0'; *p
&& isspace (*p
); ++p
);
771 user
= p
; /* this is the user's name */
772 while (*p
&& !isspace (*p
))
773 ++p
; /* find end of user's name */
777 *p
= '\0'; /* <nul> terminate username (+host?) */
779 /* buf -> host(?) ; user -> username(?) */
785 /* First check the user part. In a naive implementation we
786 would check the host part first, then the user. However,
787 if we check the user first and reject the entry we will
788 have saved doing any host lookups to normalize the comparison
789 and that likely saves several DNS queries. Therefore we
790 check the user first. */
791 ucheck
= __icheckuser (user
, ruser
);
793 /* Either we found the user, or we didn't and this is a
794 negative host check. We must do the negative host lookup
795 in order to preserve the semantics of stopping on this line
796 before processing others. */
797 if (ucheck
!= 0 || *buf
== '-') {
799 /* Next check host part. */
800 hcheck
= __checkhost_sa (ra
, ralen
, buf
, rhost
);
802 /* Negative '-host user(?)' match? */
806 /* Positive 'host user' match? */
807 if (hcheck
> 0 && ucheck
> 0) {
812 /* Negative 'host -user' match? */
813 if (hcheck
> 0 && ucheck
< 0)
816 /* Neither, go on looking for match. */
825 weak_alias (ahostbuf
, __libc_rcmd_freemem_ptr
)