1 /* $NetBSD: rcmd.c,v 1.65 2007/01/03 11:46:22 ws 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.65 2007/01/03 11:46:22 ws 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>
54 #include <arpa/inet.h>
73 #include "pathnames.h"
75 int orcmd
__P((char **, u_int
, const char *, const char *, const char *,
77 int orcmd_af
__P((char **, u_int
, const char *, const char *, const char *,
79 int __ivaliduser
__P((FILE *, u_int32_t
, const char *, const char *));
80 int __ivaliduser_sa
__P((FILE *, const struct sockaddr
*, socklen_t
,
81 const char *, const char *));
82 static int rshrcmd
__P((char **, u_int32_t
, const char *, const char *,
83 const char *, int *, const char *));
84 static int resrcmd
__P((struct addrinfo
*, char **, u_int32_t
, const char *,
85 const char *, const char *, int *));
86 static int __icheckhost
__P((const struct sockaddr
*, socklen_t
,
88 static char *__gethostloop
__P((const struct sockaddr
*, socklen_t
));
91 rcmd(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
)
94 const char *locuser
, *remuser
, *cmd
;
98 return rcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
102 rcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, af
)
105 const char *locuser
, *remuser
, *cmd
;
109 static char hbuf
[MAXHOSTNAMELEN
];
110 char pbuf
[NI_MAXSERV
];
111 struct addrinfo hints
, *res
;
115 _DIAGASSERT(ahost
!= NULL
);
116 _DIAGASSERT(locuser
!= NULL
);
117 _DIAGASSERT(remuser
!= NULL
);
118 _DIAGASSERT(cmd
!= NULL
);
119 /* fd2p may be NULL */
121 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(rport
));
122 memset(&hints
, 0, sizeof(hints
));
123 hints
.ai_family
= af
;
124 hints
.ai_socktype
= SOCK_STREAM
;
125 hints
.ai_flags
= AI_CANONNAME
;
126 error
= getaddrinfo(*ahost
, pbuf
, &hints
, &res
);
128 warnx("%s: %s", *ahost
, gai_strerror(error
)); /*XXX*/
131 if (res
->ai_canonname
) {
133 * Canonicalise hostname.
134 * XXX: Should we really do this?
136 strlcpy(hbuf
, res
->ai_canonname
, sizeof(hbuf
));
141 * Check if rport is the same as the shell port, and that the fd2p. If
142 * it is not, the program isn't expecting 'rsh' and so we can't use the
143 * RCMD_CMD environment.
145 sp
= getservbyname("shell", "tcp");
146 if (sp
!= NULL
&& sp
->s_port
== rport
)
147 error
= rshrcmd(ahost
, (u_int32_t
)rport
,
148 locuser
, remuser
, cmd
, fd2p
, getenv("RCMD_CMD"));
150 error
= resrcmd(res
, ahost
, (u_int32_t
)rport
,
151 locuser
, remuser
, cmd
, fd2p
);
156 /* this is simply a wrapper around hprcmd() that handles ahost first */
158 orcmd(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
)
161 const char *locuser
, *remuser
, *cmd
;
164 return orcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
168 orcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, af
)
171 const char *locuser
, *remuser
, *cmd
;
175 static char hbuf
[MAXHOSTNAMELEN
];
176 char pbuf
[NI_MAXSERV
];
177 struct addrinfo hints
, *res
;
180 _DIAGASSERT(ahost
!= NULL
);
181 _DIAGASSERT(locuser
!= NULL
);
182 _DIAGASSERT(remuser
!= NULL
);
183 _DIAGASSERT(cmd
!= NULL
);
184 /* fd2p may be NULL */
186 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(rport
));
187 memset(&hints
, 0, sizeof(hints
));
188 hints
.ai_family
= af
;
189 hints
.ai_socktype
= SOCK_STREAM
;
190 hints
.ai_flags
= AI_CANONNAME
;
191 error
= getaddrinfo(*ahost
, pbuf
, &hints
, &res
);
193 warnx("%s: %s", *ahost
, gai_strerror(error
)); /*XXX*/
196 if (res
->ai_canonname
) {
197 strlcpy(hbuf
, res
->ai_canonname
, sizeof(hbuf
));
201 error
= resrcmd(res
, ahost
, rport
, locuser
, remuser
, cmd
, fd2p
);
208 resrcmd(res
, ahost
, rport
, locuser
, remuser
, cmd
, fd2p
)
209 struct addrinfo
*res
;
212 const char *locuser
, *remuser
, *cmd
;
216 struct sockaddr_storage from
;
217 struct pollfd reads
[2];
219 /* No support for OOB data in Minix. */
221 sigset_t nmask
, omask
;
222 #endif /* !__minix */
229 _DIAGASSERT(res
!= NULL
);
230 _DIAGASSERT(ahost
!= NULL
);
231 _DIAGASSERT(locuser
!= NULL
);
232 _DIAGASSERT(remuser
!= NULL
);
233 _DIAGASSERT(cmd
!= NULL
);
234 /* fd2p may be NULL */
240 /* Minix has no support for OOB data,
241 no need to block SIGURG. */
243 sigaddset(&nmask
, SIGURG
);
244 if (sigprocmask(SIG_BLOCK
, &nmask
, &omask
) == -1)
246 #endif /* !__minix */
247 for (timo
= 1, lport
= IPPORT_RESERVED
- 1;;) {
248 s
= rresvport_af(&lport
, r
->ai_family
);
251 warnx("rcmd: socket: All ports in use");
253 warn("rcmd: socket");
259 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
260 #endif /* !__minix */
265 /* No OOB support in Minix. */
266 fcntl(s
, F_SETOWN
, pid
);
267 #endif /* !__minix */
268 if (connect(s
, r
->ai_addr
, r
->ai_addrlen
) >= 0)
271 if (errno
== EADDRINUSE
) {
274 } else if (errno
== ECONNREFUSED
)
278 char hbuf
[NI_MAXHOST
];
279 const int niflags
= NI_NUMERICHOST
;
282 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
,
283 hbuf
, sizeof(hbuf
), NULL
, 0, niflags
) != 0)
284 strlcpy(hbuf
, "(invalid)", sizeof(hbuf
));
286 warn("rcmd: connect to address %s", hbuf
);
289 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
,
290 hbuf
, sizeof(hbuf
), NULL
, 0, niflags
) != 0)
291 strlcpy(hbuf
, "(invalid)", sizeof(hbuf
));
292 (void)fprintf(stderr
, "Trying %s...\n", hbuf
);
295 if (refused
&& timo
<= 16) {
296 (void)sleep((unsigned int)timo
);
302 (void)fprintf(stderr
, "%s: %s\n", res
->ai_canonname
,
305 /* No OOB support in Minix. */
306 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
307 #endif /* !__minix */
316 int s2
= rresvport_af(&lport
, r
->ai_family
), s3
;
317 socklen_t len
= sizeof(from
);
322 (void)snprintf(num
, sizeof(num
), "%d", lport
);
323 if (write(s
, num
, strlen(num
) + 1) !=
324 (ssize_t
) (strlen(num
) + 1)) {
325 warn("rcmd: write (setting up stderr)");
330 reads
[0].events
= POLLIN
;
332 reads
[1].events
= POLLIN
;
334 pollr
= poll(reads
, 2, INFTIM
);
335 if (pollr
< 1 || (reads
[1].revents
& POLLIN
) == 0) {
337 warn("poll: setting up stderr");
339 warnx("poll: protocol failure in circuit setup");
343 s3
= accept(s2
, (struct sockaddr
*)(void *)&from
, &len
);
346 warn("rcmd: accept");
351 switch (((struct sockaddr
*)(void *)&from
)->sa_family
) {
356 if (getnameinfo((struct sockaddr
*)(void *)&from
, len
,
357 NULL
, 0, num
, sizeof(num
), NI_NUMERICSERV
) != 0 ||
358 (atoi(num
) >= IPPORT_RESERVED
||
359 atoi(num
) < IPPORT_RESERVED
/ 2)) {
360 warnx("rcmd: protocol failure in circuit setup.");
369 (void)write(s
, locuser
, strlen(locuser
)+1);
370 (void)write(s
, remuser
, strlen(remuser
)+1);
371 (void)write(s
, cmd
, strlen(cmd
)+1);
372 if (read(s
, &c
, 1) != 1) {
377 while (read(s
, &c
, 1) == 1) {
378 (void)write(STDERR_FILENO
, &c
, 1);
385 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
394 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
400 * based on code written by Chris Siebenmann <cks@utcc.utoronto.ca>
404 rshrcmd(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, rshcmd
)
407 const char *locuser
, *remuser
, *cmd
;
414 struct passwd
*pw
, pwres
;
417 _DIAGASSERT(ahost
!= NULL
);
418 _DIAGASSERT(locuser
!= NULL
);
419 _DIAGASSERT(remuser
!= NULL
);
420 _DIAGASSERT(cmd
!= NULL
);
421 /* fd2p may be NULL */
423 /* What rsh/shell to use. */
425 rshcmd
= _PATH_BIN_RCMD
;
427 /* locuser must exist on this host. */
428 if (getpwnam_r(locuser
, &pwres
, pwbuf
, sizeof(pwbuf
), &pw
) != 0 ||
430 warnx("rshrcmd: unknown user: %s", locuser
);
434 /* get a socketpair we'll use for stdin and stdout. */
435 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, sp
) < 0) {
436 warn("rshrcmd: socketpair");
439 /* we will use this for the fd2 pointer */
441 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, ep
) < 0) {
442 warn("rshrcmd: socketpair");
450 warn("rshrcmd: fork");
456 * - we use sp[1] to be stdin/stdout, and close sp[0]
457 * - with fd2p, we use ep[1] for stderr, and close ep[0]
460 if (dup2(sp
[1], 0) < 0 || dup2(0, 1) < 0) {
461 warn("rshrcmd: dup2");
466 if (dup2(ep
[1], 2) < 0) {
467 warn("rshrcmd: dup2");
472 } else if (dup2(0, 2) < 0) {
473 warn("rshrcmd: dup2");
476 /* fork again to lose parent. */
479 warn("rshrcmd: second fork");
485 /* Orphan. Become local user for rshprog. */
486 if (setuid(pw
->pw_uid
)) {
487 warn("rshrcmd: setuid(%lu)", (u_long
)pw
->pw_uid
);
492 * If we are rcmd'ing to "localhost" as the same user as we are,
493 * then avoid running remote shell for efficiency.
495 if (strcmp(*ahost
, "localhost") == 0 &&
496 strcmp(locuser
, remuser
) == 0) {
497 if (pw
->pw_shell
[0] == '\0')
498 rshcmd
= _PATH_BSHELL
;
500 rshcmd
= pw
->pw_shell
;
501 p
= strrchr(rshcmd
, '/');
502 execlp(rshcmd
, p
? p
+ 1 : rshcmd
, "-c", cmd
, NULL
);
504 p
= strrchr(rshcmd
, '/');
505 execlp(rshcmd
, p
? p
+ 1 : rshcmd
, *ahost
, "-l",
508 warn("rshrcmd: exec %s", rshcmd
);
516 (void)waitpid(pid
, NULL
, 0);
525 _DIAGASSERT(alport
!= NULL
);
527 return rresvport_af(alport
, AF_INET
);
531 rresvport_af(alport
, family
)
535 struct sockaddr_storage ss
;
541 _DIAGASSERT(alport
!= NULL
);
543 memset(&ss
, 0, sizeof(ss
));
544 sa
= (struct sockaddr
*)(void *)&ss
;
550 salen
= sizeof(struct sockaddr_in
);
551 portp
= &((struct sockaddr_in
*)(void *)sa
)->sin_port
;
558 salen
= sizeof(struct sockaddr_in6
);
559 portp
= &((struct sockaddr_in6
*)(void *)sa
)->sin6_port
;
563 errno
= EAFNOSUPPORT
;
566 sa
->sa_family
= family
;
567 s
= socket(family
, SOCK_STREAM
, 0);
575 if (bindresvport(s
, (struct sockaddr_in
*)(void *)sa
) < 0) {
582 *alport
= (int)ntohs(*portp
);
585 /* is it necessary to try keep code for other AFs? */
590 *portp
= htons((u_short
)*alport
);
591 if (bind(s
, sa
, (socklen_t
)salen
) >= 0)
593 if (errno
!= EADDRINUSE
) {
598 if (*alport
== IPPORT_RESERVED
/2) {
600 errno
= EAGAIN
; /* close */
606 int __check_rhosts_file
= 1;
607 const char *__rcmd_errstr
;
610 ruserok(rhost
, superuser
, ruser
, luser
)
611 const char *rhost
, *ruser
, *luser
;
614 struct addrinfo hints
, *res
, *r
;
617 _DIAGASSERT(rhost
!= NULL
);
618 _DIAGASSERT(ruser
!= NULL
);
619 _DIAGASSERT(luser
!= NULL
);
621 memset(&hints
, 0, sizeof(hints
));
622 hints
.ai_family
= PF_UNSPEC
;
623 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
624 error
= getaddrinfo(rhost
, "0", &hints
, &res
);
628 for (r
= res
; r
; r
= r
->ai_next
) {
629 if (iruserok_sa(r
->ai_addr
, (int)r
->ai_addrlen
, superuser
,
630 ruser
, luser
) == 0) {
640 * New .rhosts strategy: We are passed an ip address. We spin through
641 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
642 * has ip addresses, we don't have to trust a nameserver. When it
643 * contains hostnames, we spin through the list of addresses the nameserver
644 * gives us and look for a match.
646 * Returns 0 if ok, -1 if not ok.
649 iruserok(raddr
, superuser
, ruser
, luser
)
652 const char *ruser
, *luser
;
654 struct sockaddr_in irsin
;
656 memset(&irsin
, 0, sizeof(irsin
));
657 irsin
.sin_family
= AF_INET
;
659 irsin
.sin_len
= sizeof(struct sockaddr_in
);
661 memcpy(&irsin
.sin_addr
, &raddr
, sizeof(irsin
.sin_addr
));
662 return iruserok_sa(&irsin
, sizeof(struct sockaddr_in
), superuser
, ruser
,
667 * 2nd and 3rd arguments are typed like this, to avoid dependency between
668 * unistd.h and sys/socket.h. There's no better way.
671 iruserok_sa(raddr
, rlen
, superuser
, ruser
, luser
)
675 const char *ruser
, *luser
;
677 const struct sockaddr
*sa
;
679 struct passwd
*pwd
, pwres
;
684 char pbuf
[MAXPATHLEN
];
687 _DIAGASSERT(raddr
!= NULL
);
688 _DIAGASSERT(ruser
!= NULL
);
689 _DIAGASSERT(luser
!= NULL
);
693 __rcmd_errstr
= NULL
;
695 hostf
= superuser
? NULL
: fopen(_PATH_HEQUIV
, "r");
698 if (__ivaliduser_sa(hostf
, sa
, (socklen_t
)rlen
, luser
,
707 if (__check_rhosts_file
|| superuser
) {
709 if (getpwnam_r(luser
, &pwres
, pwbuf
, sizeof(pwbuf
), &pwd
) != 0
712 (void)strlcpy(pbuf
, pwd
->pw_dir
, sizeof(pbuf
));
713 (void)strlcat(pbuf
, "/.rhosts", sizeof(pbuf
));
716 * Change effective uid while opening and reading .rhosts.
717 * If root and reading an NFS mounted file system, can't
718 * read files that are protected read/write owner only.
722 (void)setegid(pwd
->pw_gid
);
723 initgroups(pwd
->pw_name
, pwd
->pw_gid
);
724 (void)seteuid(pwd
->pw_uid
);
725 hostf
= fopen(pbuf
, "r");
729 * If not a regular file, or is owned by someone other
730 * than user or root or if writable by anyone but the
733 if (lstat(pbuf
, &sbuf
) < 0)
734 __rcmd_errstr
= ".rhosts lstat failed";
735 else if (!S_ISREG(sbuf
.st_mode
))
736 __rcmd_errstr
= ".rhosts not regular file";
737 else if (fstat(fileno(hostf
), &sbuf
) < 0)
738 __rcmd_errstr
= ".rhosts fstat failed";
739 else if (sbuf
.st_uid
&& sbuf
.st_uid
!= pwd
->pw_uid
)
740 __rcmd_errstr
= "bad .rhosts owner";
741 else if (sbuf
.st_mode
& (S_IWGRP
|S_IWOTH
))
743 ".rhosts writable by other than owner";
746 __ivaliduser_sa(hostf
, sa
, (socklen_t
)rlen
,
755 return (isvaliduser
);
760 * Don't make static, used by lpd(8). We will be able to change the function
761 * into static function, when we bump libc major #.
763 * Returns 0 if ok, -1 if not ok.
765 #ifdef notdef /*_LIBC*/
769 __ivaliduser(hostf
, raddr
, luser
, ruser
)
772 const char *luser
, *ruser
;
774 struct sockaddr_in ivusin
;
776 memset(&ivusin
, 0, sizeof(ivusin
));
777 ivusin
.sin_family
= AF_INET
;
779 ivusin
.sin_len
= sizeof(struct sockaddr_in
);
781 memcpy(&ivusin
.sin_addr
, &raddr
, sizeof(ivusin
.sin_addr
));
782 return __ivaliduser_sa(hostf
, (struct sockaddr
*)(void *)&ivusin
,
783 sizeof(struct sockaddr_in
), luser
, ruser
);
786 #ifdef notdef /*_LIBC*/
790 __ivaliduser_sa(hostf
, raddr
, salen
, luser
, ruser
)
792 const struct sockaddr
*raddr
;
794 const char *luser
, *ruser
;
796 register char *user
, *p
;
798 char buf
[MAXHOSTNAMELEN
+ 128]; /* host + login */
799 const char *auser
, *ahost
;
803 char domain
[MAXHOSTNAMELEN
];
805 getdomainname(domain
, sizeof(domain
));
807 _DIAGASSERT(hostf
!= NULL
);
808 _DIAGASSERT(luser
!= NULL
);
809 _DIAGASSERT(ruser
!= NULL
);
811 while (fgets(buf
, sizeof(buf
), hostf
)) {
813 /* Skip lines that are too long. */
814 if (strchr(p
, '\n') == NULL
) {
815 while ((ch
= getc(hostf
)) != '\n' && ch
!= EOF
)
819 while (*p
!= '\n' && *p
!= ' ' && *p
!= '\t' && *p
!= '\0') {
820 *p
= isupper((unsigned char)*p
) ?
821 tolower((unsigned char)*p
) : *p
;
824 if (*p
== ' ' || *p
== '\t') {
826 while (*p
== ' ' || *p
== '\t')
829 while (*p
!= '\n' && *p
!= ' ' &&
830 *p
!= '\t' && *p
!= '\0')
839 auser
= *user
? user
: luser
;
850 rhost
= __gethostloop(raddr
, salen
);
854 hostok
= innetgr(&ahost
[2], rhost
,
861 hostok
= __icheckhost(raddr
, salen
, &ahost
[1]);
864 else if (ahost
[0] == '-')
872 rhost
= __gethostloop(raddr
, salen
);
876 hostok
= -innetgr(&ahost
[2], rhost
,
883 hostok
= -__icheckhost(raddr
, salen
, &ahost
[1]);
887 hostok
= __icheckhost(raddr
, salen
, ahost
);
897 userok
= innetgr(&auser
[2], NULL
, ruser
,
902 userok
= strcmp(ruser
, &auser
[1]) == 0;
905 else if (auser
[0] == '-')
912 userok
= -innetgr(&auser
[2], NULL
, ruser
,
918 -(strcmp(ruser
, &auser
[1]) == 0 ? 1 : 0);
922 userok
= strcmp(ruser
, auser
) == 0;
924 /* Check if one component did not match */
925 if (hostok
== 0 || userok
== 0)
928 /* Check if we got a forbidden pair */
929 if (userok
== -1 || hostok
== -1)
932 /* Check if we got a valid pair */
933 if (hostok
== 1 && userok
== 1)
940 * Returns "true" if match, 0 if no match.
943 __icheckhost(raddr
, salen
, lhost
)
944 const struct sockaddr
*raddr
;
948 struct addrinfo hints
, *res
, *r
;
949 char h1
[NI_MAXHOST
], h2
[NI_MAXHOST
];
951 const int niflags
= NI_NUMERICHOST
;
953 _DIAGASSERT(raddr
!= NULL
);
954 _DIAGASSERT(lhost
!= NULL
);
957 if (getnameinfo(raddr
, salen
, h1
, sizeof(h1
), NULL
, 0,
961 /* Resolve laddr into sockaddr */
962 memset(&hints
, 0, sizeof(hints
));
963 hints
.ai_family
= raddr
->sa_family
;
964 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
966 error
= getaddrinfo(lhost
, "0", &hints
, &res
);
971 * Try string comparisons between raddr and laddr.
973 for (r
= res
; r
; r
= r
->ai_next
) {
975 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
, h2
, sizeof(h2
),
976 NULL
, 0, niflags
) != 0)
978 if (strcmp(h1
, h2
) == 0) {
990 * Return the hostname associated with the supplied address.
991 * Do a reverse lookup as well for security. If a loop cannot
992 * be found, pack the numeric IP address into the string.
995 __gethostloop(raddr
, salen
)
996 const struct sockaddr
*raddr
;
999 static char remotehost
[NI_MAXHOST
];
1000 char h1
[NI_MAXHOST
], h2
[NI_MAXHOST
];
1001 struct addrinfo hints
, *res
, *r
;
1003 const int niflags
= NI_NUMERICHOST
;
1005 _DIAGASSERT(raddr
!= NULL
);
1007 h1
[0] = remotehost
[0] = '\0';
1008 if (getnameinfo(raddr
, salen
, remotehost
, sizeof(remotehost
),
1009 NULL
, 0, NI_NAMEREQD
) != 0)
1011 if (getnameinfo(raddr
, salen
, h1
, sizeof(h1
), NULL
, 0,
1016 * Look up the name and check that the supplied
1017 * address is in the list
1019 memset(&hints
, 0, sizeof(hints
));
1020 hints
.ai_family
= raddr
->sa_family
;
1021 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
1022 hints
.ai_flags
= AI_CANONNAME
;
1024 error
= getaddrinfo(remotehost
, "0", &hints
, &res
);
1028 for (r
= res
; r
; r
= r
->ai_next
) {
1030 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
, h2
, sizeof(h2
),
1031 NULL
, 0, niflags
) != 0)
1033 if (strcmp(h1
, h2
) == 0) {
1035 return (remotehost
);
1040 * either the DNS adminstrator has made a configuration
1041 * mistake, or someone has attempted to spoof us
1043 syslog(LOG_NOTICE
, "rcmd: address %s not listed for host %s",
1044 h1
, res
->ai_canonname
? res
->ai_canonname
: remotehost
);