4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
44 #include <sys/types.h>
45 #include <sys/param.h>
49 #include <sys/socket.h>
52 #include <netinet/in.h>
53 #include <netinet/tcp.h>
54 #include <inet/common.h>
64 #include <arpa/inet.h>
66 #include <priv_utils.h>
69 #define bcopy(s1, s2, len) (void) memcpy(s2, s1, len)
70 #define bzero(s, len) (void) memset(s, 0, len)
71 #define index(s, c) strchr(s, c)
77 extern int usingypmap();
79 static int _validuser(FILE *hostf
, char *rhost
, const char *luser
,
80 const char *ruser
, int baselen
);
81 static int _checkhost(char *rhost
, char *lhost
, int len
);
88 int rcmd(char **ahost
, unsigned short rport
, const char *locuser
,
89 const char *remuser
, const char *cmd
, int *fd2p
)
93 rcmd_ret
= rcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
,
98 int rcmd_af(char **ahost
, unsigned short rport
, const char *locuser
,
99 const char *remuser
, const char *cmd
, int *fd2p
, int af
)
104 struct sockaddr_storage caddr
, faddr
;
105 struct sockaddr_in
*sin
;
106 struct sockaddr_in6
*sin6
;
107 struct addrinfo hints
;
108 struct addrinfo
*res
, *resp
;
111 #define MAX_SHORTSTRLEN 6
112 char aport
[MAX_SHORTSTRLEN
];
118 struct sigaction oldaction
;
119 struct sigaction newaction
;
126 static char hostname
[MAXHOSTNAMELEN
];
128 char abuf
[INET6_ADDRSTRLEN
];
130 if (!(af
== AF_INET
|| af
== AF_INET6
|| af
== AF_UNSPEC
)) {
131 errno
= EAFNOSUPPORT
;
136 memset(&hints
, 0, sizeof (hints
));
137 hints
.ai_socktype
= SOCK_STREAM
;
138 hints
.ai_flags
= AI_CANONNAME
;
139 if (af
== AF_INET6
) {
140 hints
.ai_flags
|= AI_V4MAPPED
;
141 hints
.ai_family
= AF_UNSPEC
;
143 hints
.ai_family
= af
;
145 (void) snprintf(aport
, MAX_SHORTSTRLEN
, "%u", ntohs(rport
));
146 rc
= getaddrinfo(*ahost
, aport
, &hints
, &res
);
148 (void) fprintf(stderr
,
149 dgettext(TEXT_DOMAIN
, "%s: unknown host%s\n"),
150 *ahost
, rc
== EAI_AGAIN
? " (try again later)" : "");
154 (void) strlcpy(hostname
, res
->ai_canonname
, MAXHOSTNAMELEN
);
158 bzero((char *)&newaction
, sizeof (newaction
));
159 newaction
.sa_handler
= SIG_IGN
;
160 (void) sigaction(SIGPIPE
, &newaction
, &oldaction
);
163 bzero((char *)&newmask
, sizeof (newmask
));
164 (void) sigaddset(&newmask
, SIGURG
);
165 (void) sigprocmask(SIG_BLOCK
, &newmask
, &oldmask
);
167 oldmask
= _sigblock(sigmask(SIGURG
));
170 s
= rresvport_af(&lport
, res
->ai_family
);
172 int af
= res
->ai_family
;
175 * See if we have any addresses of a different type
178 while (res
!= NULL
&& res
->ai_family
== af
)
185 (void) fprintf(stderr
,
186 dgettext(TEXT_DOMAIN
,
187 "socket: All ports in use\n"));
189 perror("rcmd: socket");
191 /* restore original SIGPIPE handler */
192 (void) sigaction(SIGPIPE
, &oldaction
,
193 (struct sigaction
*)0);
195 /* restore original signal mask */
196 (void) sigprocmask(SIG_SETMASK
, &oldmask
,
204 bzero((char *)&caddr
, sizeof (caddr
));
205 bcopy(res
->ai_addr
, &caddr
, res
->ai_addrlen
);
206 addrlen
= res
->ai_addrlen
;
207 if (af
== AF_INET6
&& res
->ai_addr
->sa_family
== AF_INET
) {
209 struct sockaddr_in6
*in6addr
;
210 IN6_INADDR_TO_V4MAPPED(&((struct sockaddr_in
*)
211 res
->ai_addr
)->sin_addr
, &ia6
);
212 in6addr
= (struct sockaddr_in6
*)&caddr
;
213 in6addr
->sin6_addr
= ia6
;
214 in6addr
->sin6_family
= AF_INET6
;
215 addrlen
= sizeof (struct sockaddr_in6
);
217 (void) fcntl(s
, F_SETOWN
, pid
);
218 if (connect(s
, (struct sockaddr
*)&caddr
, addrlen
) >= 0)
221 if (errno
== EADDRINUSE
) {
225 if (errno
== ECONNREFUSED
&& timo
<= 16) {
230 if (res
->ai_next
!= NULL
) {
232 if (res
->ai_addr
->sa_family
== AF_INET6
)
233 addr
= (char *)&((struct sockaddr_in6
*)
234 res
->ai_addr
)->sin6_addr
;
236 addr
= (char *)&((struct sockaddr_in
*)
237 res
->ai_addr
)->sin_addr
;
238 (void) fprintf(stderr
,
239 dgettext(TEXT_DOMAIN
, "connect to address %s: "),
240 inet_ntop(res
->ai_addr
->sa_family
, addr
,
241 abuf
, sizeof (abuf
)));
245 if (res
->ai_addr
->sa_family
== AF_INET6
)
246 addr
= (char *)&((struct sockaddr_in6
*)
247 res
->ai_addr
)->sin6_addr
;
249 addr
= (char *)&((struct sockaddr_in
*)
250 res
->ai_addr
)->sin_addr
;
251 (void) fprintf(stderr
,
252 dgettext(TEXT_DOMAIN
, "Trying %s...\n"),
253 inet_ntop(res
->ai_addr
->sa_family
, addr
,
254 abuf
, sizeof (abuf
)));
260 /* restore original SIGPIPE handler */
261 (void) sigaction(SIGPIPE
, &oldaction
,
262 (struct sigaction
*)0);
264 /* restore original signal mask */
265 (void) sigprocmask(SIG_SETMASK
, &oldmask
, (sigset_t
*)0);
273 (void) write(s
, "", 1);
275 int s2
= rresvport_af(&lport
, res
->ai_family
), s3
;
277 len
= (socklen_t
)sizeof (faddr
);
281 (void) listen(s2
, 1);
282 (void) snprintf(aport
, MAX_SHORTSTRLEN
, "%d", lport
);
283 if (write(s
, aport
, strlen(aport
)+1) != strlen(aport
)+1) {
284 perror(dgettext(TEXT_DOMAIN
,
285 "write: setting up stderr"));
292 while ((selret
= select(FD_SETSIZE
, &fdset
, (fd_set
*)0,
293 (fd_set
*)0, (struct timeval
*)0)) > 0) {
294 if (FD_ISSET(s
, &fdset
)) {
296 * Something's wrong: we should get no
297 * data on this connection at this point,
298 * so we assume that the connection has
304 if (FD_ISSET(s2
, &fdset
)) {
306 * We assume this is an incoming connect
307 * request and proceed normally.
309 s3
= accept(s2
, (struct sockaddr
*)&faddr
,
324 * This should not happen, and we treat it as
332 switch (faddr
.ss_family
) {
334 sin
= (struct sockaddr_in
*)&faddr
;
335 if (ntohs(sin
->sin_port
) >= IPPORT_RESERVED
) {
336 (void) fprintf(stderr
,
337 dgettext(TEXT_DOMAIN
,
338 "socket: protocol failure in circuit "
344 sin6
= (struct sockaddr_in6
*)&faddr
;
345 if (ntohs(sin6
->sin6_port
) >= IPPORT_RESERVED
) {
346 (void) fprintf(stderr
,
347 dgettext(TEXT_DOMAIN
,
348 "socket: protocol failure in circuit "
354 (void) fprintf(stderr
,
355 dgettext(TEXT_DOMAIN
,
356 "socket: protocol failure in circuit setup.\n"));
360 (void) write(s
, locuser
, strlen(locuser
)+1);
361 (void) write(s
, remuser
, strlen(remuser
)+1);
362 (void) write(s
, cmd
, strlen(cmd
)+1);
363 retval
= read(s
, &c
, 1);
366 (void) fprintf(stderr
,
367 dgettext(TEXT_DOMAIN
,
368 "Protocol error, %s closed connection\n"),
370 } else if (retval
< 0) {
373 (void) fprintf(stderr
,
374 dgettext(TEXT_DOMAIN
,
375 "Protocol error, %s sent %d bytes\n"),
381 while (read(s
, &c
, 1) == 1) {
382 (void) write(2, &c
, 1);
389 /* restore original SIGPIPE handler */
390 (void) sigaction(SIGPIPE
, &oldaction
, (struct sigaction
*)0);
392 /* restore original signal mask */
393 (void) sigprocmask(SIG_SETMASK
, &oldmask
, (sigset_t
*)0);
405 /* restore original SIGPIPE handler */
406 (void) sigaction(SIGPIPE
, &oldaction
, (struct sigaction
*)0);
408 /* restore original signal mask */
409 (void) sigprocmask(SIG_SETMASK
, &oldmask
, (sigset_t
*)0);
418 _rresvport_addr(int *alport
, struct sockaddr_storage
*addr
)
420 struct sockaddr_in
*sin
;
421 struct sockaddr_in6
*sin6
;
427 if (addr
->ss_family
== AF_INET
) {
428 sin
= (struct sockaddr_in
*)addr
;
429 len
= sizeof (struct sockaddr_in
);
430 } else if (addr
->ss_family
== AF_INET6
) {
431 sin6
= (struct sockaddr_in6
*)addr
;
432 len
= sizeof (struct sockaddr_in6
);
434 errno
= EAFNOSUPPORT
;
437 s
= socket(addr
->ss_family
, SOCK_STREAM
, 0);
442 * Set SO_EXCLBIND to get a "unique" port, which is not bound
443 * to any other sockets.
445 if (setsockopt(s
, SOL_SOCKET
, SO_EXCLBIND
, &on
, sizeof (on
)) < 0) {
450 /* Try to bind() to the given port first. */
452 if (addr
->ss_family
== AF_INET
) {
453 sin
->sin_port
= htons((ushort_t
)*alport
);
455 sin6
->sin6_port
= htons((ushort_t
)*alport
);
457 if (bind(s
, (struct sockaddr
*)addr
, len
) >= 0) {
458 /* To be safe, need to turn off SO_EXCLBIND. */
459 (void) setsockopt(s
, SOL_SOCKET
, SO_EXCLBIND
, &off
,
463 if (errno
!= EADDRINUSE
) {
470 * If no port is given or the above bind() does not succeed, set
471 * TCP_ANONPRIVBIND option to ask the kernel to pick a port in the
472 * priviledged range for us.
474 if (setsockopt(s
, IPPROTO_TCP
, TCP_ANONPRIVBIND
, &on
,
479 if (addr
->ss_family
== AF_INET
) {
484 if (bind(s
, (struct sockaddr
*)addr
, len
) >= 0) {
486 * We need to tell the caller what the port is.
488 if (getsockname(s
, (struct sockaddr
*)addr
, &len
) < 0) {
492 switch (addr
->ss_family
) {
494 sin6
= (struct sockaddr_in6
*)addr
;
495 *alport
= ntohs(sin6
->sin6_port
);
498 sin
= (struct sockaddr_in
*)addr
;
499 *alport
= ntohs(sin
->sin_port
);
504 * To be safe, always turn off these options when we are done.
506 (void) setsockopt(s
, IPPROTO_TCP
, TCP_ANONPRIVBIND
, &off
,
508 (void) setsockopt(s
, SOL_SOCKET
, SO_EXCLBIND
, &off
,
517 rresvport_addr(int *alport
, struct sockaddr_storage
*addr
)
521 (void) __priv_bracket(PRIV_ON
);
523 res
= _rresvport_addr(alport
, addr
);
526 (void) __priv_bracket(PRIV_OFF
);
533 rresvport_af(int *alport
, int af
)
535 struct sockaddr_storage laddr
;
537 bzero(&laddr
, sizeof (laddr
));
538 if (af
== AF_INET
|| af
== AF_INET6
) {
539 laddr
.ss_family
= (sa_family_t
)af
;
541 errno
= EAFNOSUPPORT
;
544 return (rresvport_addr(alport
, &laddr
));
548 rresvport(int *alport
)
550 return (rresvport_af(alport
, AF_INET
));
554 ruserok(const char *rhost
, int superuser
, const char *ruser
, const char *luser
)
557 char fhost
[MAXHOSTNAMELEN
];
564 char pbuf
[MAXPATHLEN
];
565 uid_t uid
= (uid_t
)-1;
566 gid_t gid
= (gid_t
)-1;
567 int maxgrp
= getgroups(0, NULL
);
568 gid_t
*grouplist
= alloca(maxgrp
* sizeof (gid_t
));
576 baselen
= (int)(sp
- rhost
);
579 *p
++ = isupper(*sp
) ? tolower(*sp
++) : *sp
++;
584 /* check /etc/hosts.equiv */
586 if ((hostf
= fopen("/etc/hosts.equiv", "rF")) != NULL
) {
587 if (!_validuser(hostf
, fhost
, luser
, ruser
, baselen
)) {
588 (void) fclose(hostf
);
591 (void) fclose(hostf
);
595 /* check ~/.rhosts */
597 if ((pwd
= getpwnam(luser
)) == NULL
)
599 (void) strcpy(pbuf
, pwd
->pw_dir
);
600 (void) strcat(pbuf
, "/.rhosts");
603 * Read .rhosts as the local user to avoid NFS mapping the root uid
604 * to something that can't read .rhosts.
608 if ((ngroups
= getgroups(maxgrp
, grouplist
)) == -1)
611 (void) setegid(pwd
->pw_gid
);
612 initgroups(pwd
->pw_name
, pwd
->pw_gid
);
613 (void) seteuid(pwd
->pw_uid
);
614 if ((hostf
= fopen(pbuf
, "rF")) == NULL
) {
615 if (gid
!= (gid_t
)-1)
617 if (uid
!= (uid_t
)-1)
619 setgroups(ngroups
, grouplist
);
622 (void) fstat64(fileno(hostf
), &sbuf
);
623 if (sbuf
.st_uid
&& sbuf
.st_uid
!= pwd
->pw_uid
) {
624 (void) fclose(hostf
);
625 if (gid
!= (gid_t
)-1)
627 if (uid
!= (uid_t
)-1)
629 setgroups(ngroups
, grouplist
);
633 if (!_validuser(hostf
, fhost
, luser
, ruser
, baselen
)) {
634 (void) fclose(hostf
);
635 if (gid
!= (gid_t
)-1)
637 if (uid
!= (uid_t
)-1)
639 setgroups(ngroups
, grouplist
);
643 (void) fclose(hostf
);
644 if (gid
!= (gid_t
)-1)
646 if (uid
!= (uid_t
)-1)
648 setgroups(ngroups
, grouplist
);
653 _validuser(FILE *hostf
, char *rhost
, const char *luser
,
654 const char *ruser
, int baselen
)
658 char *uchost
= (char *)NULL
;
659 int hostmatch
, usermatch
;
663 if (domain
== NULL
) {
664 (void) usingypmap(&domain
, NULL
);
668 while (fgets(ahost
, (int)sizeof (ahost
), hostf
)) {
669 uchost
= (char *)NULL
;
670 hostmatch
= usermatch
= 0;
673 * We can get a line bigger than our buffer. If so we skip
674 * the offending line.
676 if (strchr(p
, '\n') == NULL
) {
677 while (fgets(ahost
, (int)sizeof (ahost
), hostf
) &&
678 strchr(ahost
, '\n') == NULL
)
682 while (*p
!= '\n' && *p
!= ' ' && *p
!= '\t' && *p
!= '\0') {
684 * Both host and user ``names'' can be netgroups,
685 * and must have their case preserved. Case is
686 * preserved for user names because we break out
687 * of this loop when finding a field separator.
688 * To do so for host names, we must make a copy of
689 * the host name field.
692 if (uchost
== (char *)NULL
)
693 uchost
= strdup(ahost
);
698 if (*p
!= '\0' && uchost
!= (char *)NULL
)
699 uchost
[p
- ahost
] = '\0';
700 if (*p
== ' ' || *p
== '\t') {
702 while (*p
== ' ' || *p
== '\t')
705 while (*p
!= '\n' && *p
!= ' ' && *p
!= '\t' &&
711 if (ahost
[0] == '+' && ahost
[1] == 0)
714 else if (ahost
[0] == '+' && ahost
[1] == '@')
715 if (uchost
!= (char *)NULL
)
716 hostmatch
= innetgr(uchost
+ 2, rhost
,
719 hostmatch
= innetgr(ahost
+ 2, rhost
,
721 else if (ahost
[0] == '-' && ahost
[1] == '@') {
722 if (uchost
!= (char *)NULL
) {
723 if (innetgr(uchost
+ 2, rhost
, NULL
, domain
))
726 if (innetgr(ahost
+ 2, rhost
, NULL
, domain
))
731 else if (ahost
[0] == '-') {
732 if (_checkhost(rhost
, ahost
+1, baselen
))
736 hostmatch
= _checkhost(rhost
, ahost
, baselen
);
738 if (user
[0] == '+' && user
[1] == 0)
741 else if (user
[0] == '+' && user
[1] == '@')
742 usermatch
= innetgr(user
+2, NULL
,
744 else if (user
[0] == '-' && user
[1] == '@') {
746 innetgr(user
+2, NULL
, ruser
, domain
))
750 else if (user
[0] == '-') {
751 if (hostmatch
&& (strcmp(user
+1, ruser
) == 0))
755 usermatch
= (strcmp(user
, ruser
) == 0);
758 usermatch
= (strcmp(ruser
, luser
) == 0);
759 if (uchost
!= (char *)NULL
)
761 if (hostmatch
&& usermatch
)
765 if (uchost
!= (char *)NULL
)
771 _checkhost(char *rhost
, char *lhost
, int len
)
773 static char *ldomain
;
774 static char *domainp
;
778 if (ldomain
== NULL
) {
779 ldomain
= (char *)malloc(MAXHOSTNAMELEN
+1);
785 return (strcmp(rhost
, lhost
) == 0);
786 if (strncmp(rhost
, lhost
, len
))
788 if (strcmp(rhost
, lhost
) == 0)
790 if (*(lhost
+ len
) != '\0')
796 * "domainp" points after the first dot in the host name
798 if (gethostname(ldomain
, MAXHOSTNAMELEN
) == -1) {
802 ldomain
[MAXHOSTNAMELEN
] = NULL
;
803 if ((domainp
= index(ldomain
, '.')) == (char *)NULL
) {
810 *cp
= isupper(*cp
) ? tolower(*cp
) : *cp
;
814 return (strcmp(domainp
, rhost
+ len
+ 1) == 0);