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(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, af
)
109 const char *locuser
, *remuser
, *cmd
;
113 char paddr
[INET6_ADDRSTRLEN
];
114 struct addrinfo hints
, *res
, *ai
;
118 struct sockaddr_storage ss
;
119 struct sockaddr_in sin
;
120 struct sockaddr_in6 sin6
;
122 struct pollfd pfd
[2];
125 int s
, lport
, timo
, error
;
131 if (af
!= AF_INET
&& af
!= AF_INET6
&& af
!= AF_UNSPEC
)
133 __set_errno (EAFNOSUPPORT
);
139 memset(&hints
, '\0', sizeof(hints
));
140 hints
.ai_flags
= AI_CANONNAME
;
141 hints
.ai_family
= af
;
142 hints
.ai_socktype
= SOCK_STREAM
;
143 (void)__snprintf(num
, sizeof(num
), "%d", ntohs(rport
));
144 error
= getaddrinfo(*ahost
, num
, &hints
, &res
);
146 if (error
== EAI_NONAME
&& *ahost
!= NULL
)
147 __fxprintf(NULL
, "%s: Unknown host\n", *ahost
);
149 __fxprintf(NULL
, "rcmd: getaddrinfo: %s\n",
150 gai_strerror(error
));
155 pfd
[0].events
= POLLIN
;
156 pfd
[1].events
= POLLIN
;
158 if (res
->ai_canonname
){
160 ahostbuf
= strdup (res
->ai_canonname
);
161 if (ahostbuf
== NULL
) {
162 __fxprintf(NULL
, "%s",
163 _("rcmd: Cannot allocate memory\n"));
171 oldmask
= __sigblock(sigmask(SIGURG
));
172 for (timo
= 1, lport
= IPPORT_RESERVED
- 1;;) {
175 s
= rresvport_af(&lport
, ai
->ai_family
);
178 __fxprintf(NULL
, "%s", _("\
179 rcmd: socket: All ports in use\n"));
181 __fxprintf(NULL
, "rcmd: socket: %m\n");
183 __sigsetmask(oldmask
);
187 __fcntl(s
, F_SETOWN
, pid
);
188 if (__connect(s
, ai
->ai_addr
, ai
->ai_addrlen
) >= 0)
191 if (errno
== EADDRINUSE
) {
195 if (errno
== ECONNREFUSED
)
197 if (ai
->ai_next
!= NULL
) {
201 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
202 paddr
, sizeof(paddr
),
206 if (__asprintf (&buf
, _("connect to address %s: "),
209 __fxprintf(NULL
, "%s", buf
);
212 __set_errno (oerrno
);
215 getnameinfo(ai
->ai_addr
, ai
->ai_addrlen
,
216 paddr
, sizeof(paddr
),
219 if (__asprintf (&buf
, _("Trying %s...\n"), paddr
) >= 0)
221 __fxprintf (NULL
, "%s", buf
);
226 if (refused
&& timo
<= 16) {
234 (void)__fxprintf(NULL
, "%s: %s\n", *ahost
,
235 __strerror_r(errno
, errbuf
, sizeof (errbuf
)));
236 __sigsetmask(oldmask
);
245 int s2
= rresvport_af(&lport
, ai
->ai_family
), s3
;
246 socklen_t len
= ai
->ai_addrlen
;
251 (void)__snprintf(num
, sizeof(num
), "%d", lport
);
252 if (__write(s
, num
, strlen(num
)+1) != (ssize_t
)strlen(num
)+1) {
255 if (__asprintf (&buf
, _("\
256 rcmd: write (setting up stderr): %m\n")) >= 0)
258 __fxprintf(NULL
, "%s", buf
);
267 if (__poll (pfd
, 2, -1) < 1 || (pfd
[1].revents
& POLLIN
) == 0){
271 && __asprintf(&buf
, _("\
272 rcmd: poll (setting up stderr): %m\n")) >= 0)
274 && __asprintf(&buf
, _("\
275 poll: protocol failure in circuit setup\n")) >= 0))
277 __fxprintf (NULL
, "%s", buf
);
283 s3
= TEMP_FAILURE_RETRY (accept(s2
, &from
.sa
, &len
));
284 switch (from
.sa
.sa_family
) {
286 rport
= ntohs(from
.sin
.sin_port
);
289 rport
= ntohs(from
.sin6
.sin6_port
);
297 (void)__fxprintf(NULL
, "rcmd: accept: %m\n");
303 if (rport
>= IPPORT_RESERVED
|| rport
< IPPORT_RESERVED
/ 2){
306 if (__asprintf(&buf
, _("\
307 socket: protocol failure in circuit setup\n")) >= 0)
309 __fxprintf (NULL
, "%s", buf
);
315 struct iovec iov
[3] =
317 [0] = { .iov_base
= (void *) locuser
,
318 .iov_len
= strlen (locuser
) + 1 },
319 [1] = { .iov_base
= (void *) remuser
,
320 .iov_len
= strlen (remuser
) + 1 },
321 [2] = { .iov_base
= (void *) cmd
,
322 .iov_len
= strlen (cmd
) + 1 }
324 (void) TEMP_FAILURE_RETRY (__writev (s
, iov
, 3));
325 n
= TEMP_FAILURE_RETRY (__read(s
, &c
, 1));
330 && __asprintf(&buf
, _("rcmd: %s: short read"),
333 && __asprintf(&buf
, "rcmd: %s: %m\n", *ahost
) >= 0))
335 __fxprintf (NULL
, "%s", buf
);
341 while (__read(s
, &c
, 1) == 1) {
342 (void)__write(STDERR_FILENO
, &c
, 1);
348 __sigsetmask(oldmask
);
353 (void)__close(*fd2p
);
356 __sigsetmask(oldmask
);
360 libc_hidden_def (rcmd_af
)
363 rcmd(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
)
366 const char *locuser
, *remuser
, *cmd
;
369 return rcmd_af (ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
373 rresvport_af(alport
, family
)
378 struct sockaddr generic
;
379 struct sockaddr_in in
;
380 struct sockaddr_in6 in6
;
388 len
= sizeof(struct sockaddr_in
);
389 sport
= &ss
.in
.sin_port
;
392 len
= sizeof(struct sockaddr_in6
);
393 sport
= &ss
.in6
.sin6_port
;
396 __set_errno (EAFNOSUPPORT
);
399 s
= __socket(family
, SOCK_STREAM
, 0);
403 memset (&ss
, '\0', sizeof(ss
));
405 ss
.generic
.__ss_len
= len
;
407 ss
.generic
.sa_family
= family
;
409 /* Ignore invalid values. */
410 if (*alport
< IPPORT_RESERVED
/ 2)
411 *alport
= IPPORT_RESERVED
/ 2;
412 else if (*alport
>= IPPORT_RESERVED
)
413 *alport
= IPPORT_RESERVED
- 1;
417 *sport
= htons((uint16_t) *alport
);
418 if (__bind(s
, &ss
.generic
, len
) >= 0)
420 if (errno
!= EADDRINUSE
) {
424 if ((*alport
)-- == IPPORT_RESERVED
/2)
425 *alport
= IPPORT_RESERVED
- 1;
426 } while (*alport
!= start
);
428 __set_errno (EAGAIN
);
431 libc_hidden_def (rresvport_af
)
437 return rresvport_af(alport
, AF_INET
);
440 int __check_rhosts_file
= 1;
444 ruserok_af(rhost
, superuser
, ruser
, luser
, af
)
445 const char *rhost
, *ruser
, *luser
;
449 struct addrinfo hints
, *res
, *res0
;
453 memset (&hints
, '\0', sizeof(hints
));
454 hints
.ai_family
= af
;
455 gai
= getaddrinfo(rhost
, NULL
, &hints
, &res0
);
459 for (res
=res0
; res
; res
=res
->ai_next
)
460 if (ruserok2_sa(res
->ai_addr
, res
->ai_addrlen
,
461 superuser
, ruser
, luser
, rhost
) == 0){
468 libc_hidden_def (ruserok_af
)
471 ruserok(rhost
, superuser
, ruser
, luser
)
472 const char *rhost
, *ruser
, *luser
;
475 return ruserok_af(rhost
, superuser
, ruser
, luser
, AF_INET
);
478 /* Extremely paranoid file open function. */
480 iruserfopen (const char *file
, uid_t okuser
)
486 /* If not a regular file, if owned by someone other than user or
487 root, if writeable by anyone but the owner, or if hardlinked
489 if (__lxstat64 (_STAT_VER
, file
, &st
))
490 cp
= _("lstat failed");
491 else if (!S_ISREG (st
.st_mode
))
492 cp
= _("not regular file");
495 res
= fopen (file
, "rce");
497 cp
= _("cannot open");
498 else if (__fxstat64 (_STAT_VER
, fileno (res
), &st
) < 0)
499 cp
= _("fstat failed");
500 else if (st
.st_uid
&& st
.st_uid
!= okuser
)
502 else if (st
.st_mode
& (S_IWGRP
|S_IWOTH
))
503 cp
= _("writeable by other than owner");
504 else if (st
.st_nlink
> 1)
505 cp
= _("hard linked somewhere");
508 /* If there were any problems, quit. */
517 /* No threads use this stream. */
518 __fsetlocking (res
, FSETLOCKING_BYCALLER
);
524 * New .rhosts strategy: We are passed an ip address. We spin through
525 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
526 * has ip addresses, we don't have to trust a nameserver. When it
527 * contains hostnames, we spin through the list of addresses the nameserver
528 * gives us and look for a match.
530 * Returns 0 if ok, -1 if not ok.
533 ruserok2_sa (ra
, ralen
, superuser
, ruser
, luser
, rhost
)
537 const char *ruser
, *luser
, *rhost
;
543 hostf
= iruserfopen (_PATH_HEQUIV
, 0);
547 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
554 if (__check_rhosts_file
|| superuser
)
557 struct passwd pwdbuf
, *pwd
;
559 size_t buflen
= __sysconf (_SC_GETPW_R_SIZE_MAX
);
560 char *buffer
= __alloca (buflen
);
563 if (__getpwnam_r (luser
, &pwdbuf
, buffer
, buflen
, &pwd
) != 0
567 dirlen
= strlen (pwd
->pw_dir
);
568 pbuf
= alloca (dirlen
+ sizeof "/.rhosts");
569 __mempcpy (__mempcpy (pbuf
, pwd
->pw_dir
, dirlen
),
570 "/.rhosts", sizeof "/.rhosts");
572 /* Change effective uid while reading .rhosts. If root and
573 reading an NFS mounted file system, can't read files that
574 are protected read/write owner only. */
576 seteuid (pwd
->pw_uid
);
577 hostf
= iruserfopen (pbuf
, pwd
->pw_uid
);
581 isbad
= __validuser2_sa (hostf
, ra
, ralen
, luser
, ruser
, rhost
);
591 * ruserok_sa() is now discussed on ipng, so
592 * currently disabled for external use
594 static int ruserok_sa(ra
, ralen
, superuser
, ruser
, luser
)
598 const char *ruser
, *luser
;
600 return ruserok2_sa(ra
, ralen
, superuser
, ruser
, luser
, "-");
603 /* This is the exported version. */
605 iruserok_af (raddr
, superuser
, ruser
, luser
, af
)
608 const char *ruser
, *luser
;
612 struct sockaddr generic
;
613 struct sockaddr_in in
;
614 struct sockaddr_in6 in6
;
618 memset (&ra
, '\0', sizeof(ra
));
621 ra
.in
.sin_family
= AF_INET
;
622 memcpy (&ra
.in
.sin_addr
, raddr
, sizeof(struct in_addr
));
623 ralen
= sizeof(struct sockaddr_in
);
626 ra
.in6
.sin6_family
= AF_INET6
;
627 memcpy (&ra
.in6
.sin6_addr
, raddr
, sizeof(struct in6_addr
));
628 ralen
= sizeof(struct sockaddr_in6
);
633 return ruserok_sa (&ra
.generic
, ralen
, superuser
, ruser
, luser
);
635 libc_hidden_def (iruserok_af
)
638 iruserok (raddr
, superuser
, ruser
, luser
)
641 const char *ruser
, *luser
;
643 return iruserok_af (&raddr
, superuser
, ruser
, luser
, AF_INET
);
648 * Don't make static, used by lpd(8).
650 * This function is not used anymore. It is only present because lpd(8)
651 * calls it (!?!). We simply call __invaliduser2() with an illegal rhost
652 * argument. This means that netgroups won't work in .rhost/hosts.equiv
653 * files. If you want lpd to work with netgroups, fix lpd to use ruserok()
655 * Returns 0 if ok, -1 if not ok.
658 __ivaliduser(hostf
, raddr
, luser
, ruser
)
661 const char *luser
, *ruser
;
663 struct sockaddr_in ra
;
664 memset(&ra
, '\0', sizeof(ra
));
665 ra
.sin_family
= AF_INET
;
666 ra
.sin_addr
.s_addr
= raddr
;
667 return __validuser2_sa(hostf
, (struct sockaddr
*)&ra
, sizeof(ra
),
672 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
675 __checkhost_sa (struct sockaddr
*ra
, size_t ralen
, char *lhost
,
678 struct addrinfo hints
, *res0
, *res
;
679 char raddr
[INET6_ADDRSTRLEN
];
681 int negate
=1; /* Multiply return with this to get -1 instead of 1 */
683 /* Check nis netgroup. */
684 if (strncmp ("+@", lhost
, 2) == 0)
685 return innetgr (&lhost
[2], rhost
, NULL
, NULL
);
687 if (strncmp ("-@", lhost
, 2) == 0)
688 return -innetgr (&lhost
[2], rhost
, NULL
, NULL
);
691 if (strncmp ("-", lhost
,1) == 0) {
694 } else if (strcmp ("+",lhost
) == 0) {
695 return 1; /* asking for trouble, but ok.. */
698 /* Try for raw ip address first. */
700 if (getnameinfo(ra
, ralen
,
701 raddr
, sizeof(raddr
), NULL
, 0,
703 && strcmp(raddr
, lhost
) == 0)
706 /* Better be a hostname. */
708 memset(&hints
, '\0', sizeof(hints
));
709 hints
.ai_family
= ra
->sa_family
;
710 if (getaddrinfo(lhost
, NULL
, &hints
, &res0
) == 0){
711 /* Spin through ip addresses. */
712 for (res
= res0
; res
; res
= res
->ai_next
)
714 if (res
->ai_family
== ra
->sa_family
715 && !memcmp(res
->ai_addr
, ra
, res
->ai_addrlen
))
723 return negate
* match
;
726 /* Returns 1 on positive match, 0 on no match, -1 on negative match. */
729 __icheckuser (const char *luser
, const char *ruser
)
732 luser is user entry from .rhosts/hosts.equiv file
733 ruser is user id on remote host
737 if (strncmp ("+@", luser
, 2) == 0)
738 return innetgr (&luser
[2], NULL
, ruser
, NULL
);
740 if (strncmp ("-@", luser
,2) == 0)
741 return -innetgr (&luser
[2], NULL
, ruser
, NULL
);
744 if (strncmp ("-", luser
, 1) == 0)
745 return -(strcmp (&luser
[1], ruser
) == 0);
748 if (strcmp ("+", luser
) == 0)
751 /* simple string match */
752 return strcmp (ruser
, luser
) == 0;
756 * Returns 1 for blank lines (or only comment lines) and 0 otherwise
761 while (*p
&& isspace (*p
)) {
765 return (*p
== '\0' || *p
== '#') ? 1 : 0 ;
769 * Returns 0 if positive match, -1 if _not_ ok.
772 __validuser2_sa(hostf
, ra
, ralen
, luser
, ruser
, rhost
)
776 const char *luser
, *ruser
, *rhost
;
785 while (__getline (&buf
, &bufsize
, hostf
) > 0) {
786 buf
[bufsize
- 1] = '\0'; /* Make sure it's terminated. */
789 /* Skip empty or comment lines */
794 for (;*p
&& !isspace(*p
); ++p
) {
798 /* Next we want to find the permitted name for the remote user. */
799 if (*p
== ' ' || *p
== '\t') {
800 /* <nul> terminate hostname and skip spaces */
801 for (*p
++='\0'; *p
&& isspace (*p
); ++p
);
803 user
= p
; /* this is the user's name */
804 while (*p
&& !isspace (*p
))
805 ++p
; /* find end of user's name */
809 *p
= '\0'; /* <nul> terminate username (+host?) */
811 /* buf -> host(?) ; user -> username(?) */
817 /* First check the user part. In a naive implementation we
818 would check the host part first, then the user. However,
819 if we check the user first and reject the entry we will
820 have saved doing any host lookups to normalize the comparison
821 and that likely saves several DNS queries. Therefore we
822 check the user first. */
823 ucheck
= __icheckuser (user
, ruser
);
825 /* Either we found the user, or we didn't and this is a
826 negative host check. We must do the negative host lookup
827 in order to preserve the semantics of stopping on this line
828 before processing others. */
829 if (ucheck
!= 0 || *buf
== '-') {
831 /* Next check host part. */
832 hcheck
= __checkhost_sa (ra
, ralen
, buf
, rhost
);
834 /* Negative '-host user(?)' match? */
838 /* Positive 'host user' match? */
839 if (hcheck
> 0 && ucheck
> 0) {
844 /* Negative 'host -user' match? */
845 if (hcheck
> 0 && ucheck
< 0)
848 /* Neither, go on looking for match. */