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 #if defined(LIBC_SCCS) && !defined(lint)
59 static char sccsid
[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
60 #endif /* LIBC_SCCS and not lint */
62 #include <sys/param.h>
64 #include <sys/socket.h>
67 #include <netinet/in.h>
68 #include <arpa/inet.h>
78 #include <stdio_ext.h>
87 int __ivaliduser (FILE *, u_int32_t
, const char *, const char *);
88 static int __validuser2_sa (FILE *, struct sockaddr
*, size_t,
89 const char *, const char *, const char *);
90 static int ruserok2_sa (struct sockaddr
*ra
, size_t ralen
,
91 int superuser
, const char *ruser
,
92 const char *luser
, const char *rhost
);
93 static int ruserok_sa (struct sockaddr
*ra
, size_t ralen
,
94 int superuser
, const char *ruser
,
96 int iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
97 const char *luser
, sa_family_t af
);
98 int iruserok (u_int32_t raddr
, int superuser
, const char *ruser
,
101 libc_hidden_proto (iruserok_af
)
103 libc_freeres_ptr(static char *ahostbuf
);
106 rcmd_af (char **ahost
, u_short rport
, const char *locuser
, const char *remuser
,
107 const char *cmd
, int *fd2p
, sa_family_t af
)
109 char paddr
[INET6_ADDRSTRLEN
];
110 struct addrinfo hints
, *res
, *ai
;
114 struct sockaddr_storage ss
;
115 struct sockaddr_in sin
;
116 struct sockaddr_in6 sin6
;
118 struct pollfd pfd
[2];
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
) {
158 __fxprintf(NULL
, "%s",
159 _("rcmd: Cannot allocate memory\n"));
167 oldmask
= __sigblock(sigmask(SIGURG
));
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 __sigsetmask(oldmask
);
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 __sigsetmask(oldmask
);
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 __sigsetmask(oldmask
);
349 (void)__close(*fd2p
);
352 __sigsetmask(oldmask
);
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 s
= __socket(family
, SOCK_STREAM
, 0);
394 memset (&ss
, '\0', sizeof(ss
));
396 ss
.generic
.__ss_len
= len
;
398 ss
.generic
.sa_family
= family
;
400 /* Ignore invalid values. */
401 if (*alport
< IPPORT_RESERVED
/ 2)
402 *alport
= IPPORT_RESERVED
/ 2;
403 else if (*alport
>= IPPORT_RESERVED
)
404 *alport
= IPPORT_RESERVED
- 1;
408 *sport
= htons((uint16_t) *alport
);
409 if (__bind(s
, &ss
.generic
, len
) >= 0)
411 if (errno
!= EADDRINUSE
) {
415 if ((*alport
)-- == IPPORT_RESERVED
/2)
416 *alport
= IPPORT_RESERVED
- 1;
417 } while (*alport
!= start
);
419 __set_errno (EAGAIN
);
422 libc_hidden_def (rresvport_af
)
425 rresvport (int *alport
)
427 return rresvport_af(alport
, AF_INET
);
430 int __check_rhosts_file
= 1;
434 ruserok_af (const char *rhost
, int superuser
, const char *ruser
,
435 const char *luser
, sa_family_t af
)
437 struct addrinfo hints
, *res
, *res0
;
441 memset (&hints
, '\0', sizeof(hints
));
442 hints
.ai_family
= af
;
443 gai
= getaddrinfo(rhost
, NULL
, &hints
, &res0
);
447 for (res
=res0
; res
; res
=res
->ai_next
)
448 if (ruserok2_sa(res
->ai_addr
, res
->ai_addrlen
,
449 superuser
, ruser
, luser
, rhost
) == 0){
456 libc_hidden_def (ruserok_af
)
459 ruserok (const char *rhost
, int superuser
, const char *ruser
,
462 return ruserok_af(rhost
, superuser
, ruser
, luser
, AF_INET
);
465 /* Extremely paranoid file open function. */
467 iruserfopen (const char *file
, uid_t okuser
)
473 /* If not a regular file, if owned by someone other than user or
474 root, if writeable by anyone but the owner, or if hardlinked
476 if (__lxstat64 (_STAT_VER
, file
, &st
))
477 cp
= _("lstat failed");
478 else if (!S_ISREG (st
.st_mode
))
479 cp
= _("not regular file");
482 res
= fopen (file
, "rce");
484 cp
= _("cannot open");
485 else if (__fxstat64 (_STAT_VER
, fileno (res
), &st
) < 0)
486 cp
= _("fstat failed");
487 else if (st
.st_uid
&& st
.st_uid
!= okuser
)
489 else if (st
.st_mode
& (S_IWGRP
|S_IWOTH
))
490 cp
= _("writeable by other than owner");
491 else if (st
.st_nlink
> 1)
492 cp
= _("hard linked somewhere");
495 /* If there were any problems, quit. */
504 /* No threads use this stream. */
505 __fsetlocking (res
, FSETLOCKING_BYCALLER
);
511 * New .rhosts strategy: We are passed an ip address. We spin through
512 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
513 * has ip addresses, we don't have to trust a nameserver. When it
514 * contains hostnames, we spin through the list of addresses the nameserver
515 * gives us and look for a match.
517 * Returns 0 if ok, -1 if not ok.
520 ruserok2_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
521 const char *ruser
, const char *luser
, const char *rhost
)
527 hostf
= iruserfopen (_PATH_HEQUIV
, 0);
531 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
538 if (__check_rhosts_file
|| superuser
)
541 struct passwd pwdbuf
, *pwd
;
543 size_t buflen
= __sysconf (_SC_GETPW_R_SIZE_MAX
);
544 char *buffer
= __alloca (buflen
);
547 if (__getpwnam_r (luser
, &pwdbuf
, buffer
, buflen
, &pwd
) != 0
551 dirlen
= strlen (pwd
->pw_dir
);
552 pbuf
= alloca (dirlen
+ sizeof "/.rhosts");
553 __mempcpy (__mempcpy (pbuf
, pwd
->pw_dir
, dirlen
),
554 "/.rhosts", sizeof "/.rhosts");
556 /* Change effective uid while reading .rhosts. If root and
557 reading an NFS mounted file system, can't read files that
558 are protected read/write owner only. */
560 seteuid (pwd
->pw_uid
);
561 hostf
= iruserfopen (pbuf
, pwd
->pw_uid
);
565 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
575 * ruserok_sa() is now discussed on ipng, so
576 * currently disabled for external use
579 ruserok_sa (struct sockaddr
*ra
, size_t ralen
, int superuser
,
580 const char *ruser
, const char *luser
)
582 return ruserok2_sa(ra
, ralen
, superuser
, ruser
, luser
, "-");
585 /* This is the exported version. */
587 iruserok_af (const void *raddr
, int superuser
, const char *ruser
,
588 const char *luser
, sa_family_t af
)
591 struct sockaddr generic
;
592 struct sockaddr_in in
;
593 struct sockaddr_in6 in6
;
597 memset (&ra
, '\0', sizeof(ra
));
600 ra
.in
.sin_family
= AF_INET
;
601 memcpy (&ra
.in
.sin_addr
, raddr
, sizeof(struct in_addr
));
602 ralen
= sizeof(struct sockaddr_in
);
605 ra
.in6
.sin6_family
= AF_INET6
;
606 memcpy (&ra
.in6
.sin6_addr
, raddr
, sizeof(struct in6_addr
));
607 ralen
= sizeof(struct sockaddr_in6
);
612 return ruserok_sa (&ra
.generic
, ralen
, superuser
, ruser
, luser
);
614 libc_hidden_def (iruserok_af
)
617 iruserok (u_int32_t raddr
, int superuser
, const char *ruser
, const char *luser
)
619 return iruserok_af (&raddr
, superuser
, ruser
, luser
, AF_INET
);
624 * Don't make static, used by lpd(8).
626 * This function is not used anymore. It is only present because lpd(8)
627 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
628 * argument. This means that netgroups won't work in .rhost/hosts.equiv
629 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
631 * Returns 0 if ok, -1 if not ok.
634 __ivaliduser (FILE *hostf
, u_int32_t raddr
, const char *luser
,
637 struct sockaddr_in ra
;
638 memset(&ra
, '\0', sizeof(ra
));
639 ra
.sin_family
= AF_INET
;
640 ra
.sin_addr
.s_addr
= raddr
;
641 return __validuser2_sa(hostf
, (struct sockaddr
*)&ra
, sizeof(ra
),
646 /* 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. */
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. */