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>
83 int __ivaliduser (FILE *, u_int32_t
, const char *, const char *);
84 static int __validuser2_sa (FILE *, struct sockaddr
*, size_t,
85 const char *, const char *, const char *);
86 static int ruserok2_sa (struct sockaddr
*ra
, size_t ralen
,
87 int superuser
, const char *ruser
,
88 const char *luser
, const char *rhost
);
89 static int ruserok_sa (struct sockaddr
*ra
, size_t ralen
,
90 int superuser
, const char *ruser
,
92 int iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
93 const char *luser
, sa_family_t af
);
94 int iruserok (u_int32_t raddr
, int superuser
, const char *ruser
,
97 libc_hidden_proto (iruserok_af
)
99 libc_freeres_ptr(static char *ahostbuf
);
102 rcmd_af (char **ahost
, u_short rport
, const char *locuser
, const char *remuser
,
103 const char *cmd
, int *fd2p
, sa_family_t af
)
105 char paddr
[INET6_ADDRSTRLEN
];
106 struct addrinfo hints
, *res
, *ai
;
110 struct sockaddr_storage ss
;
111 struct sockaddr_in sin
;
112 struct sockaddr_in6 sin6
;
114 struct pollfd pfd
[2];
117 int s
, lport
, timo
, error
;
123 if (af
!= AF_INET
&& af
!= AF_INET6
&& af
!= AF_UNSPEC
)
125 __set_errno (EAFNOSUPPORT
);
131 memset(&hints
, '\0', sizeof(hints
));
132 hints
.ai_flags
= AI_CANONNAME
;
133 hints
.ai_family
= af
;
134 hints
.ai_socktype
= SOCK_STREAM
;
135 (void)__snprintf(num
, sizeof(num
), "%d", ntohs(rport
));
136 error
= getaddrinfo(*ahost
, num
, &hints
, &res
);
138 if (error
== EAI_NONAME
&& *ahost
!= NULL
)
139 __fxprintf(NULL
, "%s: Unknown host\n", *ahost
);
141 __fxprintf(NULL
, "rcmd: getaddrinfo: %s\n",
142 gai_strerror(error
));
147 pfd
[0].events
= POLLIN
;
148 pfd
[1].events
= POLLIN
;
150 if (res
->ai_canonname
){
152 ahostbuf
= strdup (res
->ai_canonname
);
153 if (ahostbuf
== NULL
) {
154 __fxprintf(NULL
, "%s",
155 _("rcmd: Cannot allocate memory\n"));
163 oldmask
= __sigblock(sigmask(SIGURG
));
164 for (timo
= 1, lport
= IPPORT_RESERVED
- 1;;) {
167 s
= rresvport_af(&lport
, ai
->ai_family
);
170 __fxprintf(NULL
, "%s", _("\
171 rcmd: socket: All ports in use\n"));
173 __fxprintf(NULL
, "rcmd: socket: %m\n");
175 __sigsetmask(oldmask
);
179 __fcntl(s
, F_SETOWN
, pid
);
180 if (__connect(s
, ai
->ai_addr
, ai
->ai_addrlen
) >= 0)
183 if (errno
== EADDRINUSE
) {
187 if (errno
== ECONNREFUSED
)
189 if (ai
->ai_next
!= NULL
) {
193 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
194 paddr
, sizeof(paddr
),
198 if (__asprintf (&buf
, _("connect to address %s: "),
201 __fxprintf(NULL
, "%s", buf
);
204 __set_errno (oerrno
);
207 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
208 paddr
, sizeof(paddr
),
211 if (__asprintf (&buf
, _("Trying %s...\n"), paddr
) >= 0)
213 __fxprintf (NULL
, "%s", buf
);
218 if (refused
&& timo
<= 16) {
226 (void)__fxprintf(NULL
, "%s: %s\n", *ahost
,
227 __strerror_r(errno
, errbuf
, sizeof (errbuf
)));
228 __sigsetmask(oldmask
);
237 int s2
= rresvport_af(&lport
, ai
->ai_family
), s3
;
238 socklen_t len
= ai
->ai_addrlen
;
243 (void)__snprintf(num
, sizeof(num
), "%d", lport
);
244 if (__write(s
, num
, strlen(num
)+1) != (ssize_t
)strlen(num
)+1) {
247 if (__asprintf (&buf
, _("\
248 rcmd: write (setting up stderr): %m\n")) >= 0)
250 __fxprintf(NULL
, "%s", buf
);
259 if (__poll (pfd
, 2, -1) < 1 || (pfd
[1].revents
& POLLIN
) == 0){
263 && __asprintf(&buf
, _("\
264 rcmd: poll (setting up stderr): %m\n")) >= 0)
266 && __asprintf(&buf
, _("\
267 poll: protocol failure in circuit setup\n")) >= 0))
269 __fxprintf (NULL
, "%s", buf
);
275 s3
= TEMP_FAILURE_RETRY (accept(s2
, &from
.sa
, &len
));
276 switch (from
.sa
.sa_family
) {
278 rport
= ntohs(from
.sin
.sin_port
);
281 rport
= ntohs(from
.sin6
.sin6_port
);
289 (void)__fxprintf(NULL
, "rcmd: accept: %m\n");
295 if (rport
>= IPPORT_RESERVED
|| rport
< IPPORT_RESERVED
/ 2){
298 if (__asprintf(&buf
, _("\
299 socket: protocol failure in circuit setup\n")) >= 0)
301 __fxprintf (NULL
, "%s", buf
);
307 struct iovec iov
[3] =
309 [0] = { .iov_base
= (void *) locuser
,
310 .iov_len
= strlen (locuser
) + 1 },
311 [1] = { .iov_base
= (void *) remuser
,
312 .iov_len
= strlen (remuser
) + 1 },
313 [2] = { .iov_base
= (void *) cmd
,
314 .iov_len
= strlen (cmd
) + 1 }
316 (void) TEMP_FAILURE_RETRY (__writev (s
, iov
, 3));
317 n
= TEMP_FAILURE_RETRY (__read(s
, &c
, 1));
322 && __asprintf(&buf
, _("rcmd: %s: short read"),
325 && __asprintf(&buf
, "rcmd: %s: %m\n", *ahost
) >= 0))
327 __fxprintf (NULL
, "%s", buf
);
333 while (__read(s
, &c
, 1) == 1) {
334 (void)__write(STDERR_FILENO
, &c
, 1);
340 __sigsetmask(oldmask
);
345 (void)__close(*fd2p
);
348 __sigsetmask(oldmask
);
352 libc_hidden_def (rcmd_af
)
355 rcmd (char **ahost
, u_short rport
, const char *locuser
, const char *remuser
,
356 const char *cmd
, int *fd2p
)
358 return rcmd_af (ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
362 rresvport_af (int *alport
, sa_family_t family
)
365 struct sockaddr generic
;
366 struct sockaddr_in in
;
367 struct sockaddr_in6 in6
;
375 len
= sizeof(struct sockaddr_in
);
376 sport
= &ss
.in
.sin_port
;
379 len
= sizeof(struct sockaddr_in6
);
380 sport
= &ss
.in6
.sin6_port
;
383 __set_errno (EAFNOSUPPORT
);
386 s
= __socket(family
, SOCK_STREAM
, 0);
390 memset (&ss
, '\0', sizeof(ss
));
392 ss
.generic
.__ss_len
= len
;
394 ss
.generic
.sa_family
= family
;
396 /* Ignore invalid values. */
397 if (*alport
< IPPORT_RESERVED
/ 2)
398 *alport
= IPPORT_RESERVED
/ 2;
399 else if (*alport
>= IPPORT_RESERVED
)
400 *alport
= IPPORT_RESERVED
- 1;
404 *sport
= htons((uint16_t) *alport
);
405 if (__bind(s
, &ss
.generic
, len
) >= 0)
407 if (errno
!= EADDRINUSE
) {
411 if ((*alport
)-- == IPPORT_RESERVED
/2)
412 *alport
= IPPORT_RESERVED
- 1;
413 } while (*alport
!= start
);
415 __set_errno (EAGAIN
);
418 libc_hidden_def (rresvport_af
)
421 rresvport (int *alport
)
423 return rresvport_af(alport
, AF_INET
);
426 int __check_rhosts_file
= 1;
430 ruserok_af (const char *rhost
, int superuser
, const char *ruser
,
431 const char *luser
, sa_family_t af
)
433 struct addrinfo hints
, *res
, *res0
;
437 memset (&hints
, '\0', sizeof(hints
));
438 hints
.ai_family
= af
;
439 gai
= getaddrinfo(rhost
, NULL
, &hints
, &res0
);
443 for (res
=res0
; res
; res
=res
->ai_next
)
444 if (ruserok2_sa(res
->ai_addr
, res
->ai_addrlen
,
445 superuser
, ruser
, luser
, rhost
) == 0){
452 libc_hidden_def (ruserok_af
)
455 ruserok (const char *rhost
, int superuser
, const char *ruser
,
458 return ruserok_af(rhost
, superuser
, ruser
, luser
, AF_INET
);
461 /* Extremely paranoid file open function. */
463 iruserfopen (const char *file
, uid_t okuser
)
469 /* If not a regular file, if owned by someone other than user or
470 root, if writeable by anyone but the owner, or if hardlinked
472 if (__lxstat64 (_STAT_VER
, file
, &st
))
473 cp
= _("lstat failed");
474 else if (!S_ISREG (st
.st_mode
))
475 cp
= _("not regular file");
478 res
= fopen (file
, "rce");
480 cp
= _("cannot open");
481 else if (__fxstat64 (_STAT_VER
, fileno (res
), &st
) < 0)
482 cp
= _("fstat failed");
483 else if (st
.st_uid
&& st
.st_uid
!= okuser
)
485 else if (st
.st_mode
& (S_IWGRP
|S_IWOTH
))
486 cp
= _("writeable by other than owner");
487 else if (st
.st_nlink
> 1)
488 cp
= _("hard linked somewhere");
491 /* If there were any problems, quit. */
500 /* No threads use this stream. */
501 __fsetlocking (res
, FSETLOCKING_BYCALLER
);
507 * New .rhosts strategy: We are passed an ip address. We spin through
508 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
509 * has ip addresses, we don't have to trust a nameserver. When it
510 * contains hostnames, we spin through the list of addresses the nameserver
511 * gives us and look for a match.
513 * Returns 0 if ok, -1 if not ok.
516 ruserok2_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
517 const char *ruser
, const char *luser
, const char *rhost
)
523 hostf
= iruserfopen (_PATH_HEQUIV
, 0);
527 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
534 if (__check_rhosts_file
|| superuser
)
537 struct passwd pwdbuf
, *pwd
;
539 size_t buflen
= __sysconf (_SC_GETPW_R_SIZE_MAX
);
540 char *buffer
= __alloca (buflen
);
543 if (__getpwnam_r (luser
, &pwdbuf
, buffer
, buflen
, &pwd
) != 0
547 dirlen
= strlen (pwd
->pw_dir
);
548 pbuf
= alloca (dirlen
+ sizeof "/.rhosts");
549 __mempcpy (__mempcpy (pbuf
, pwd
->pw_dir
, dirlen
),
550 "/.rhosts", sizeof "/.rhosts");
552 /* Change effective uid while reading .rhosts. If root and
553 reading an NFS mounted file system, can't read files that
554 are protected read/write owner only. */
556 seteuid (pwd
->pw_uid
);
557 hostf
= iruserfopen (pbuf
, pwd
->pw_uid
);
561 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
571 * ruserok_sa() is now discussed on ipng, so
572 * currently disabled for external use
575 ruserok_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
576 const char *ruser
, const char *luser
)
578 return ruserok2_sa(ra
, ralen
, superuser
, ruser
, luser
, "-");
581 /* This is the exported version. */
583 iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
584 const char *luser
, sa_family_t af
)
587 struct sockaddr generic
;
588 struct sockaddr_in in
;
589 struct sockaddr_in6 in6
;
593 memset (&ra
, '\0', sizeof(ra
));
596 ra
.in
.sin_family
= AF_INET
;
597 memcpy (&ra
.in
.sin_addr
, raddr
, sizeof(struct in_addr
));
598 ralen
= sizeof(struct sockaddr_in
);
601 ra
.in6
.sin6_family
= AF_INET6
;
602 memcpy (&ra
.in6
.sin6_addr
, raddr
, sizeof(struct in6_addr
));
603 ralen
= sizeof(struct sockaddr_in6
);
608 return ruserok_sa (&ra
.generic
, ralen
, superuser
, ruser
, luser
);
610 libc_hidden_def (iruserok_af
)
613 iruserok (u_int32_t raddr
, int superuser
, const char *ruser
, const char *luser
)
615 return iruserok_af (&raddr
, superuser
, ruser
, luser
, AF_INET
);
620 * Don't make static, used by lpd(8).
622 * This function is not used anymore. It is only present because lpd(8)
623 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
624 * argument. This means that netgroups won't work in .rhost/hosts.equiv
625 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
627 * Returns 0 if ok, -1 if not ok.
630 __ivaliduser (FILE *hostf
, u_int32_t raddr
, const char *luser
,
633 struct sockaddr_in ra
;
634 memset(&ra
, '\0', sizeof(ra
));
635 ra
.sin_family
= AF_INET
;
636 ra
.sin_addr
.s_addr
= raddr
;
637 return __validuser2_sa(hostf
, (struct sockaddr
*)&ra
, sizeof(ra
),
642 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
645 __checkhost_sa (struct sockaddr
*ra
, size_t ralen
, char *lhost
,
648 struct addrinfo hints
, *res0
, *res
;
649 char raddr
[INET6_ADDRSTRLEN
];
651 int negate
=1; /* Multiply return with this to get -1 instead of 1 */
653 /* Check nis netgroup. */
654 if (strncmp ("+@", lhost
, 2) == 0)
655 return innetgr (&lhost
[2], rhost
, NULL
, NULL
);
657 if (strncmp ("-@", lhost
, 2) == 0)
658 return -innetgr (&lhost
[2], rhost
, NULL
, NULL
);
661 if (strncmp ("-", lhost
,1) == 0) {
664 } else if (strcmp ("+",lhost
) == 0) {
665 return 1; /* asking for trouble, but ok.. */
668 /* Try for raw ip address first. */
670 if (getnameinfo(ra
, ralen
,
671 raddr
, sizeof(raddr
), NULL
, 0,
673 && strcmp(raddr
, lhost
) == 0)
676 /* Better be a hostname. */
678 memset(&hints
, '\0', sizeof(hints
));
679 hints
.ai_family
= ra
->sa_family
;
680 if (getaddrinfo(lhost
, NULL
, &hints
, &res0
) == 0){
681 /* Spin through ip addresses. */
682 for (res
= res0
; res
; res
= res
->ai_next
)
684 if (res
->ai_family
== ra
->sa_family
685 && !memcmp(res
->ai_addr
, ra
, res
->ai_addrlen
))
693 return negate
* match
;
696 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
699 __icheckuser (const char *luser
, const char *ruser
)
702 luser is user entry from .rhosts/hosts.equiv file
703 ruser is user id on remote host
707 if (strncmp ("+@", luser
, 2) == 0)
708 return innetgr (&luser
[2], NULL
, ruser
, NULL
);
710 if (strncmp ("-@", luser
,2) == 0)
711 return -innetgr (&luser
[2], NULL
, ruser
, NULL
);
714 if (strncmp ("-", luser
, 1) == 0)
715 return -(strcmp (&luser
[1], ruser
) == 0);
718 if (strcmp ("+", luser
) == 0)
721 /* simple string match */
722 return strcmp (ruser
, luser
) == 0;
726 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
731 while (*p
&& isspace (*p
)) {
735 return (*p
== '\0' || *p
== '#') ? 1 : 0 ;
739 * Returns 0 if positive match, -1 if _not_ ok.
742 __validuser2_sa (FILE *hostf
, struct sockaddr
*ra
, size_t ralen
,
743 const char *luser
, const char *ruser
, const char *rhost
)
752 while (__getline (&buf
, &bufsize
, hostf
) > 0) {
753 buf
[bufsize
- 1] = '\0'; /* Make sure it's terminated. */
756 /* Skip empty or comment lines */
761 for (;*p
&& !isspace(*p
); ++p
) {
765 /* Next we want to find the permitted name for the remote user. */
766 if (*p
== ' ' || *p
== '\t') {
767 /* <nul> terminate hostname and skip spaces */
768 for (*p
++='\0'; *p
&& isspace (*p
); ++p
);
770 user
= p
; /* this is the user's name */
771 while (*p
&& !isspace (*p
))
772 ++p
; /* find end of user's name */
776 *p
= '\0'; /* <nul> terminate username (+host?) */
778 /* buf -> host(?) ; user -> username(?) */
784 /* First check the user part. In a naive implementation we
785 would check the host part first, then the user. However,
786 if we check the user first and reject the entry we will
787 have saved doing any host lookups to normalize the comparison
788 and that likely saves several DNS queries. Therefore we
789 check the user first. */
790 ucheck
= __icheckuser (user
, ruser
);
792 /* Either we found the user, or we didn't and this is a
793 negative host check. We must do the negative host lookup
794 in order to preserve the semantics of stopping on this line
795 before processing others. */
796 if (ucheck
!= 0 || *buf
== '-') {
798 /* Next check host part. */
799 hcheck
= __checkhost_sa (ra
, ralen
, buf
, rhost
);
801 /* Negative '-host user(?)' match? */
805 /* Positive 'host user' match? */
806 if (hcheck
> 0 && ucheck
> 0) {
811 /* Negative 'host -user' match? */
812 if (hcheck
> 0 && ucheck
< 0)
815 /* Neither, go on looking for match. */