1 /* $NetBSD: rcmd.c,v 1.71 2014/11/26 23:44:21 enami Exp $ */
4 * Copyright (c) 1983, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
33 #if defined(LIBC_SCCS) && !defined(lint)
35 static char sccsid
[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
37 __RCSID("$NetBSD: rcmd.c,v 1.71 2014/11/26 23:44:21 enami Exp $");
39 #endif /* LIBC_SCCS and not lint */
42 #include "namespace.h"
44 #include <sys/param.h>
45 #include <sys/socket.h>
50 #include <netinet/in.h>
53 #endif /* !defined(__minix) */
54 #include <arpa/inet.h>
73 #include "pathnames.h"
75 int orcmd(char **, u_int
, const char *, const char *, const char *, int *);
76 int orcmd_af(char **, u_int
, const char *, const char *, const char *,
78 int __ivaliduser(FILE *, u_int32_t
, const char *, const char *);
79 int __ivaliduser_sa(FILE *, const struct sockaddr
*, socklen_t
,
80 const char *, const char *);
81 static int rshrcmd(int, char **, u_int32_t
, const char *,
82 const char *, const char *, int *, const char *);
83 static int resrcmd(struct addrinfo
*, char **, u_int32_t
, const char *,
84 const char *, const char *, int *);
85 static int __icheckhost(const struct sockaddr
*, socklen_t
,
87 static char *__gethostloop(const struct sockaddr
*, socklen_t
);
90 rcmd(char **ahost
, int rport
, const char *locuser
, const char *remuser
,
91 const char *cmd
, int *fd2p
)
94 return rcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
98 rcmd_af(char **ahost
, int rport
, const char *locuser
, const char *remuser
,
99 const char *cmd
, int *fd2p
, int af
)
101 static char hbuf
[MAXHOSTNAMELEN
];
102 char pbuf
[NI_MAXSERV
];
103 struct addrinfo hints
, *res
;
107 _DIAGASSERT(ahost
!= NULL
);
108 _DIAGASSERT(locuser
!= NULL
);
109 _DIAGASSERT(remuser
!= NULL
);
110 _DIAGASSERT(cmd
!= NULL
);
111 /* fd2p may be NULL */
113 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(rport
));
114 memset(&hints
, 0, sizeof(hints
));
115 hints
.ai_family
= af
;
116 hints
.ai_socktype
= SOCK_STREAM
;
117 hints
.ai_flags
= AI_CANONNAME
;
118 error
= getaddrinfo(*ahost
, pbuf
, &hints
, &res
);
120 warnx("%s: %s", *ahost
, gai_strerror(error
)); /*XXX*/
123 if (res
->ai_canonname
) {
125 * Canonicalise hostname.
126 * XXX: Should we really do this?
128 strlcpy(hbuf
, res
->ai_canonname
, sizeof(hbuf
));
133 * Check if rport is the same as the shell port, and that the fd2p. If
134 * it is not, the program isn't expecting 'rsh' and so we can't use the
135 * RCMD_CMD environment.
137 sp
= getservbyname("shell", "tcp");
138 if (sp
!= NULL
&& sp
->s_port
== rport
)
139 error
= rshrcmd(af
, ahost
, (u_int32_t
)rport
,
140 locuser
, remuser
, cmd
, fd2p
, getenv("RCMD_CMD"));
142 error
= resrcmd(res
, ahost
, (u_int32_t
)rport
,
143 locuser
, remuser
, cmd
, fd2p
);
148 /* this is simply a wrapper around hprcmd() that handles ahost first */
150 orcmd(char **ahost
, u_int rport
, const char *locuser
, const char *remuser
,
151 const char *cmd
, int *fd2p
)
153 return orcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
157 orcmd_af(char **ahost
, u_int rport
, const char *locuser
, const char *remuser
,
158 const char *cmd
, int *fd2p
, int af
)
160 static char hbuf
[MAXHOSTNAMELEN
];
161 char pbuf
[NI_MAXSERV
];
162 struct addrinfo hints
, *res
;
165 _DIAGASSERT(ahost
!= NULL
);
166 _DIAGASSERT(locuser
!= NULL
);
167 _DIAGASSERT(remuser
!= NULL
);
168 _DIAGASSERT(cmd
!= NULL
);
169 /* fd2p may be NULL */
171 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(rport
));
172 memset(&hints
, 0, sizeof(hints
));
173 hints
.ai_family
= af
;
174 hints
.ai_socktype
= SOCK_STREAM
;
175 hints
.ai_flags
= AI_CANONNAME
;
176 error
= getaddrinfo(*ahost
, pbuf
, &hints
, &res
);
178 warnx("%s: %s", *ahost
, gai_strerror(error
)); /*XXX*/
181 if (res
->ai_canonname
) {
182 strlcpy(hbuf
, res
->ai_canonname
, sizeof(hbuf
));
186 error
= resrcmd(res
, ahost
, rport
, locuser
, remuser
, cmd
, fd2p
);
193 resrcmd(struct addrinfo
*res
, char **ahost
, u_int32_t rport
,
194 const char *locuser
, const char *remuser
, const char *cmd
, int *fd2p
)
197 struct sockaddr_storage from
;
198 struct pollfd reads
[2];
199 sigset_t nmask
, omask
;
206 _DIAGASSERT(res
!= NULL
);
207 _DIAGASSERT(ahost
!= NULL
);
208 _DIAGASSERT(locuser
!= NULL
);
209 _DIAGASSERT(remuser
!= NULL
);
210 _DIAGASSERT(cmd
!= NULL
);
211 /* fd2p may be NULL */
217 sigaddset(&nmask
, SIGURG
);
218 if (sigprocmask(SIG_BLOCK
, &nmask
, &omask
) == -1)
220 for (timo
= 1, lport
= IPPORT_RESERVED
- 1;;) {
221 s
= rresvport_af(&lport
, r
->ai_family
);
224 warnx("rcmd: socket: All ports in use");
226 warn("rcmd: socket");
231 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
235 fcntl(s
, F_SETOWN
, pid
);
236 if (connect(s
, r
->ai_addr
, r
->ai_addrlen
) >= 0)
239 if (errno
== EADDRINUSE
) {
242 } else if (errno
== ECONNREFUSED
)
246 char hbuf
[NI_MAXHOST
];
247 const int niflags
= NI_NUMERICHOST
;
250 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
,
251 hbuf
, (socklen_t
)sizeof(hbuf
), NULL
, 0, niflags
) !=
253 strlcpy(hbuf
, "(invalid)", sizeof(hbuf
));
255 warn("rcmd: connect to address %s", hbuf
);
258 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
,
259 hbuf
, (socklen_t
)sizeof(hbuf
), NULL
, 0, niflags
) !=
261 strlcpy(hbuf
, "(invalid)", sizeof(hbuf
));
262 (void)fprintf(stderr
, "Trying %s...\n", hbuf
);
265 if (refused
&& timo
<= 16) {
266 (void)sleep((unsigned int)timo
);
272 (void)fprintf(stderr
, "%s: %s\n", res
->ai_canonname
,
274 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
283 int s2
= rresvport_af(&lport
, r
->ai_family
), s3
;
284 socklen_t len
= sizeof(from
);
289 (void)snprintf(num
, sizeof(num
), "%d", lport
);
290 if (write(s
, num
, strlen(num
) + 1) !=
291 (ssize_t
) (strlen(num
) + 1)) {
292 warn("rcmd: write (setting up stderr)");
297 reads
[0].events
= POLLIN
;
299 reads
[1].events
= POLLIN
;
301 pollr
= poll(reads
, 2, INFTIM
);
302 if (pollr
< 1 || (reads
[1].revents
& POLLIN
) == 0) {
304 warn("poll: setting up stderr");
307 "poll: protocol failure in circuit setup");
311 s3
= accept(s2
, (struct sockaddr
*)(void *)&from
, &len
);
314 warn("rcmd: accept");
319 switch (((struct sockaddr
*)(void *)&from
)->sa_family
) {
324 if (getnameinfo((struct sockaddr
*)(void *)&from
, len
,
325 NULL
, 0, num
, (socklen_t
)sizeof(num
),
326 NI_NUMERICSERV
) != 0 ||
327 (atoi(num
) >= IPPORT_RESERVED
||
328 atoi(num
) < IPPORT_RESERVED
/ 2)) {
330 "rcmd: protocol failure in circuit setup.");
339 (void)write(s
, locuser
, strlen(locuser
)+1);
340 (void)write(s
, remuser
, strlen(remuser
)+1);
341 (void)write(s
, cmd
, strlen(cmd
)+1);
342 if (read(s
, &c
, 1) != 1) {
347 while (read(s
, &c
, 1) == 1) {
348 (void)write(STDERR_FILENO
, &c
, 1);
354 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
361 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
366 * based on code written by Chris Siebenmann <cks@utcc.utoronto.ca>
370 rshrcmd(int af
, char **ahost
, u_int32_t rport
, const char *locuser
,
371 const char *remuser
, const char *cmd
, int *fd2p
, const char *rshcmd
)
376 struct passwd
*pw
, pwres
;
379 _DIAGASSERT(ahost
!= NULL
);
380 _DIAGASSERT(locuser
!= NULL
);
381 _DIAGASSERT(remuser
!= NULL
);
382 _DIAGASSERT(cmd
!= NULL
);
383 /* fd2p may be NULL */
385 /* What rsh/shell to use. */
387 rshcmd
= _PATH_BIN_RCMD
;
389 /* locuser must exist on this host. */
390 if (getpwnam_r(locuser
, &pwres
, pwbuf
, sizeof(pwbuf
), &pw
) != 0 ||
392 warnx("%s: unknown user: %s", __func__
, locuser
);
396 /* get a socketpair we'll use for stdin and stdout. */
397 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, sp
) < 0) {
398 warn("%s: socketpair", __func__
);
401 /* we will use this for the fd2 pointer */
403 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, ep
) < 0) {
404 warn("%s: socketpair", __func__
);
412 warn("%s: fork", __func__
);
418 * - we use sp[1] to be stdin/stdout, and close sp[0]
419 * - with fd2p, we use ep[1] for stderr, and close ep[0]
422 if (dup2(sp
[1], 0) < 0 || dup2(0, 1) < 0) {
423 warn("%s: dup2", __func__
);
428 if (dup2(ep
[1], 2) < 0) {
429 warn("%s: dup2", __func__
);
434 } else if (dup2(0, 2) < 0) {
435 warn("%s: dup2", __func__
);
438 /* fork again to lose parent. */
441 warn("%s: second fork", __func__
);
447 /* Orphan. Become local user for rshprog. */
448 if (setuid(pw
->pw_uid
)) {
449 warn("%s: setuid(%lu)", __func__
, (u_long
)pw
->pw_uid
);
454 * If we are rcmd'ing to "localhost" as the same user as we
455 * are, then avoid running remote shell for efficiency.
457 if (strcmp(*ahost
, "localhost") == 0 &&
458 strcmp(locuser
, remuser
) == 0) {
459 if (pw
->pw_shell
[0] == '\0')
460 rshcmd
= _PATH_BSHELL
;
462 rshcmd
= pw
->pw_shell
;
463 p
= strrchr(rshcmd
, '/');
464 execlp(rshcmd
, p
? p
+ 1 : rshcmd
, "-c", cmd
, NULL
);
467 program
= strrchr(rshcmd
, '/');
468 program
= program
? program
+ 1 : rshcmd
;
470 /* ask rcmd to relay signal information */
471 setenv("RCMD_RELAY_SIGNAL", "YES", 1);
474 execlp(rshcmd
, program
, "-4", "-l", remuser
,
479 execlp(rshcmd
, program
, "-6", "-l", remuser
,
484 /* typically AF_UNSPEC, plus whatever */
485 execlp(rshcmd
, program
, "-l", remuser
,
490 warn("%s: exec %s", __func__
, rshcmd
);
498 (void)waitpid(pid
, NULL
, 0);
503 rresvport(int *alport
)
506 _DIAGASSERT(alport
!= NULL
);
508 return rresvport_af(alport
, AF_INET
);
512 rresvport_af(int *alport
, int family
)
514 return rresvport_af_addr(alport
, family
, NULL
);
518 rresvport_af_addr(int *alport
, int family
, void *addr
)
520 struct sockaddr_storage ss
;
526 _DIAGASSERT(alport
!= NULL
);
528 memset(&ss
, 0, sizeof(ss
));
529 sa
= (struct sockaddr
*)(void *)&ss
;
535 salen
= sizeof(struct sockaddr_in
);
537 ((struct sockaddr_in
*)(void *)sa
)->sin_addr
=
538 ((struct sockaddr_in
*)addr
)->sin_addr
;
539 portp
= &((struct sockaddr_in
*)(void *)sa
)->sin_port
;
546 salen
= sizeof(struct sockaddr_in6
);
548 ((struct sockaddr_in6
*)(void *)sa
)->sin6_addr
=
549 ((struct sockaddr_in6
*)addr
)->sin6_addr
;
550 portp
= &((struct sockaddr_in6
*)(void *)sa
)->sin6_port
;
554 errno
= EAFNOSUPPORT
;
557 sa
->sa_family
= family
;
558 s
= socket(family
, SOCK_STREAM
, 0);
561 #if defined(BSD4_4) && !defined(__minix)
566 if (bindresvport(s
, (struct sockaddr_in
*)(void *)sa
) < 0) {
573 *alport
= (int)ntohs(*portp
);
576 /* is it necessary to try keep code for other AFs? */
581 *portp
= htons((u_short
)*alport
);
582 if (bind(s
, sa
, salen
) >= 0)
584 if (errno
!= EADDRINUSE
) {
589 if (*alport
== IPPORT_RESERVED
/2) {
591 errno
= EAGAIN
; /* close */
597 int __check_rhosts_file
= 1;
598 const char *__rcmd_errstr
;
601 ruserok(const char *rhost
, int superuser
, const char *ruser
, const char *luser
)
603 struct addrinfo hints
, *res
, *r
;
606 _DIAGASSERT(rhost
!= NULL
);
607 _DIAGASSERT(ruser
!= NULL
);
608 _DIAGASSERT(luser
!= NULL
);
610 memset(&hints
, 0, sizeof(hints
));
611 hints
.ai_family
= PF_UNSPEC
;
612 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
613 error
= getaddrinfo(rhost
, "0", &hints
, &res
);
617 for (r
= res
; r
; r
= r
->ai_next
) {
618 if (iruserok_sa(r
->ai_addr
, (int)r
->ai_addrlen
, superuser
,
619 ruser
, luser
) == 0) {
629 * New .rhosts strategy: We are passed an ip address. We spin through
630 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
631 * has ip addresses, we don't have to trust a nameserver. When it
632 * contains hostnames, we spin through the list of addresses the nameserver
633 * gives us and look for a match.
635 * Returns 0 if ok, -1 if not ok.
638 iruserok(u_int32_t raddr
, int superuser
, const char *ruser
, const char *luser
)
640 struct sockaddr_in irsin
;
642 memset(&irsin
, 0, sizeof(irsin
));
643 irsin
.sin_family
= AF_INET
;
645 irsin
.sin_len
= sizeof(irsin
);
647 memcpy(&irsin
.sin_addr
, &raddr
, sizeof(irsin
.sin_addr
));
648 return iruserok_sa(&irsin
, (socklen_t
)sizeof(irsin
), superuser
, ruser
,
653 * 2nd and 3rd arguments are typed like this, to avoid dependency between
654 * unistd.h and sys/socket.h. There's no better way.
657 iruserok_sa(const void *raddr
, int rlen
, int superuser
, const char *ruser
,
660 const struct sockaddr
*sa
;
662 struct passwd
*pwd
, pwres
;
667 char pbuf
[MAXPATHLEN
];
670 _DIAGASSERT(raddr
!= NULL
);
671 _DIAGASSERT(ruser
!= NULL
);
672 _DIAGASSERT(luser
!= NULL
);
676 __rcmd_errstr
= NULL
;
678 hostf
= superuser
? NULL
: fopen(_PATH_HEQUIV
, "re");
681 if (__ivaliduser_sa(hostf
, sa
, (socklen_t
)rlen
, luser
,
690 if (__check_rhosts_file
|| superuser
) {
692 if (getpwnam_r(luser
, &pwres
, pwbuf
, sizeof(pwbuf
), &pwd
) != 0
695 (void)strlcpy(pbuf
, pwd
->pw_dir
, sizeof(pbuf
));
696 (void)strlcat(pbuf
, "/.rhosts", sizeof(pbuf
));
699 * Change effective uid while opening and reading .rhosts.
700 * If root and reading an NFS mounted file system, can't
701 * read files that are protected read/write owner only.
705 (void)setegid(pwd
->pw_gid
);
706 (void)initgroups(pwd
->pw_name
, pwd
->pw_gid
);
707 (void)seteuid(pwd
->pw_uid
);
708 hostf
= fopen(pbuf
, "re");
712 * If not a regular file, or is owned by someone other
713 * than user or root or if writable by anyone but the
716 if (lstat(pbuf
, &sbuf
) < 0)
717 __rcmd_errstr
= ".rhosts lstat failed";
718 else if (!S_ISREG(sbuf
.st_mode
))
719 __rcmd_errstr
= ".rhosts not regular file";
720 else if (fstat(fileno(hostf
), &sbuf
) < 0)
721 __rcmd_errstr
= ".rhosts fstat failed";
722 else if (sbuf
.st_uid
&& sbuf
.st_uid
!= pwd
->pw_uid
)
723 __rcmd_errstr
= "bad .rhosts owner";
724 else if (sbuf
.st_mode
& (S_IWGRP
|S_IWOTH
))
726 ".rhosts writable by other than owner";
729 __ivaliduser_sa(hostf
, sa
, (socklen_t
)rlen
,
743 * Don't make static, used by lpd(8). We will be able to change the function
744 * into static function, when we bump libc major #.
746 * Returns 0 if ok, -1 if not ok.
748 #ifdef notdef /*_LIBC*/
752 __ivaliduser(FILE *hostf
, u_int32_t raddr
, const char *luser
,
755 struct sockaddr_in ivusin
;
757 memset(&ivusin
, 0, sizeof(ivusin
));
758 ivusin
.sin_family
= AF_INET
;
760 ivusin
.sin_len
= sizeof(ivusin
);
762 memcpy(&ivusin
.sin_addr
, &raddr
, sizeof(ivusin
.sin_addr
));
763 return __ivaliduser_sa(hostf
, (struct sockaddr
*)(void *)&ivusin
,
764 (socklen_t
)sizeof(ivusin
), luser
, ruser
);
767 #ifdef notdef /*_LIBC*/
771 __ivaliduser_sa(FILE *hostf
, const struct sockaddr
*raddr
, socklen_t salen
,
772 const char *luser
, const char *ruser
)
776 char buf
[MAXHOSTNAMELEN
+ 128]; /* host + login */
777 const char *auser
, *ahost
;
781 char domain
[MAXHOSTNAMELEN
];
783 getdomainname(domain
, sizeof(domain
));
785 _DIAGASSERT(hostf
!= NULL
);
786 _DIAGASSERT(luser
!= NULL
);
787 _DIAGASSERT(ruser
!= NULL
);
789 while (fgets(buf
, (int)sizeof(buf
), hostf
)) {
791 /* Skip lines that are too long. */
792 if (strchr(p
, '\n') == NULL
) {
793 while ((ch
= getc(hostf
)) != '\n' && ch
!= EOF
)
797 while (*p
!= '\n' && *p
!= ' ' && *p
!= '\t' && *p
!= '\0') {
798 *p
= isupper((unsigned char)*p
) ?
799 tolower((unsigned char)*p
) : *p
;
802 if (*p
== ' ' || *p
== '\t') {
804 while (*p
== ' ' || *p
== '\t')
807 while (*p
!= '\n' && *p
!= ' ' &&
808 *p
!= '\t' && *p
!= '\0')
817 auser
= *user
? user
: luser
;
828 rhost
= __gethostloop(raddr
, salen
);
832 hostok
= innetgr(&ahost
[2], rhost
,
839 hostok
= __icheckhost(raddr
, salen
, &ahost
[1]);
842 else if (ahost
[0] == '-')
850 rhost
= __gethostloop(raddr
, salen
);
854 hostok
= -innetgr(&ahost
[2], rhost
,
862 -__icheckhost(raddr
, salen
, &ahost
[1]);
866 hostok
= __icheckhost(raddr
, salen
, ahost
);
876 userok
= innetgr(&auser
[2], NULL
, ruser
,
881 userok
= strcmp(ruser
, &auser
[1]) == 0;
884 else if (auser
[0] == '-')
891 userok
= -innetgr(&auser
[2], NULL
, ruser
,
897 -(strcmp(ruser
, &auser
[1]) == 0 ? 1 : 0);
901 userok
= strcmp(ruser
, auser
) == 0;
903 /* Check if one component did not match */
904 if (hostok
== 0 || userok
== 0)
907 /* Check if we got a forbidden pair */
908 if (userok
== -1 || hostok
== -1)
911 /* Check if we got a valid pair */
912 if (hostok
== 1 && userok
== 1)
919 * Returns "true" if match, 0 if no match.
922 __icheckhost(const struct sockaddr
*raddr
, socklen_t salen
, const char *lhost
)
924 struct addrinfo hints
, *res
, *r
;
925 char h1
[NI_MAXHOST
], h2
[NI_MAXHOST
];
927 const int niflags
= NI_NUMERICHOST
;
929 _DIAGASSERT(raddr
!= NULL
);
930 _DIAGASSERT(lhost
!= NULL
);
933 if (getnameinfo(raddr
, salen
, h1
, (socklen_t
)sizeof(h1
), NULL
, 0,
937 /* Resolve laddr into sockaddr */
938 memset(&hints
, 0, sizeof(hints
));
939 hints
.ai_family
= raddr
->sa_family
;
940 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
942 error
= getaddrinfo(lhost
, "0", &hints
, &res
);
947 * Try string comparisons between raddr and laddr.
949 for (r
= res
; r
; r
= r
->ai_next
) {
951 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
, h2
,
952 (socklen_t
)sizeof(h2
), NULL
, 0, niflags
) != 0)
954 if (strcmp(h1
, h2
) == 0) {
966 * Return the hostname associated with the supplied address.
967 * Do a reverse lookup as well for security. If a loop cannot
968 * be found, pack the numeric IP address into the string.
971 __gethostloop(const struct sockaddr
*raddr
, socklen_t salen
)
973 static char remotehost
[NI_MAXHOST
];
974 char h1
[NI_MAXHOST
], h2
[NI_MAXHOST
];
975 struct addrinfo hints
, *res
, *r
;
977 const int niflags
= NI_NUMERICHOST
;
979 _DIAGASSERT(raddr
!= NULL
);
981 h1
[0] = remotehost
[0] = '\0';
982 if (getnameinfo(raddr
, salen
, remotehost
, (socklen_t
)sizeof(remotehost
),
983 NULL
, 0, NI_NAMEREQD
) != 0)
985 if (getnameinfo(raddr
, salen
, h1
, (socklen_t
)sizeof(h1
), NULL
, 0,
990 * Look up the name and check that the supplied
991 * address is in the list
993 memset(&hints
, 0, sizeof(hints
));
994 hints
.ai_family
= raddr
->sa_family
;
995 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
996 hints
.ai_flags
= AI_CANONNAME
;
998 error
= getaddrinfo(remotehost
, "0", &hints
, &res
);
1002 for (r
= res
; r
; r
= r
->ai_next
) {
1004 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
, h2
,
1005 (socklen_t
)sizeof(h2
), NULL
, 0, niflags
) != 0)
1007 if (strcmp(h1
, h2
) == 0) {
1014 * either the DNS adminstrator has made a configuration
1015 * mistake, or someone has attempted to spoof us
1017 syslog(LOG_NOTICE
, "rcmd: address %s not listed for host %s",
1018 h1
, res
->ai_canonname
? res
->ai_canonname
: remotehost
);