1 /* $NetBSD: rcmd.c,v 1.64 2006/11/03 20:21:16 christos 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.64 2006/11/03 20:21:16 christos 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>
52 #include <arpa/inet.h>
71 #include "pathnames.h"
73 int orcmd
__P((char **, u_int
, const char *, const char *, const char *,
75 int orcmd_af
__P((char **, u_int
, const char *, const char *, const char *,
77 int __ivaliduser
__P((FILE *, u_int32_t
, const char *, const char *));
78 int __ivaliduser_sa
__P((FILE *, const struct sockaddr
*, socklen_t
,
79 const char *, const char *));
80 static int rshrcmd
__P((char **, u_int32_t
, const char *, const char *,
81 const char *, int *, const char *));
82 static int resrcmd
__P((struct addrinfo
*, char **, u_int32_t
, const char *,
83 const char *, const char *, int *));
84 static int __icheckhost
__P((const struct sockaddr
*, socklen_t
,
86 static char *__gethostloop
__P((const struct sockaddr
*, socklen_t
));
89 rcmd(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
)
92 const char *locuser
, *remuser
, *cmd
;
96 return rcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
100 rcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, af
)
103 const char *locuser
, *remuser
, *cmd
;
107 static char hbuf
[MAXHOSTNAMELEN
];
108 char pbuf
[NI_MAXSERV
];
109 struct addrinfo hints
, *res
;
113 _DIAGASSERT(ahost
!= NULL
);
114 _DIAGASSERT(locuser
!= NULL
);
115 _DIAGASSERT(remuser
!= NULL
);
116 _DIAGASSERT(cmd
!= NULL
);
117 /* fd2p may be NULL */
119 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(rport
));
120 memset(&hints
, 0, sizeof(hints
));
121 hints
.ai_family
= af
;
122 hints
.ai_socktype
= SOCK_STREAM
;
123 hints
.ai_flags
= AI_CANONNAME
;
124 error
= getaddrinfo(*ahost
, pbuf
, &hints
, &res
);
126 warnx("%s: %s", *ahost
, gai_strerror(error
)); /*XXX*/
129 if (res
->ai_canonname
) {
131 * Canonicalise hostname.
132 * XXX: Should we really do this?
134 strlcpy(hbuf
, res
->ai_canonname
, sizeof(hbuf
));
139 * Check if rport is the same as the shell port, and that the fd2p. If
140 * it is not, the program isn't expecting 'rsh' and so we can't use the
141 * RCMD_CMD environment.
143 sp
= getservbyname("shell", "tcp");
144 if (sp
!= NULL
&& sp
->s_port
== rport
)
145 error
= rshrcmd(ahost
, (u_int32_t
)rport
,
146 locuser
, remuser
, cmd
, fd2p
, getenv("RCMD_CMD"));
148 error
= resrcmd(res
, ahost
, (u_int32_t
)rport
,
149 locuser
, remuser
, cmd
, fd2p
);
154 /* this is simply a wrapper around hprcmd() that handles ahost first */
156 orcmd(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
)
159 const char *locuser
, *remuser
, *cmd
;
162 return orcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, AF_INET
);
166 orcmd_af(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, af
)
169 const char *locuser
, *remuser
, *cmd
;
173 static char hbuf
[MAXHOSTNAMELEN
];
174 char pbuf
[NI_MAXSERV
];
175 struct addrinfo hints
, *res
;
178 _DIAGASSERT(ahost
!= NULL
);
179 _DIAGASSERT(locuser
!= NULL
);
180 _DIAGASSERT(remuser
!= NULL
);
181 _DIAGASSERT(cmd
!= NULL
);
182 /* fd2p may be NULL */
184 snprintf(pbuf
, sizeof(pbuf
), "%u", ntohs(rport
));
185 memset(&hints
, 0, sizeof(hints
));
186 hints
.ai_family
= af
;
187 hints
.ai_socktype
= SOCK_STREAM
;
188 hints
.ai_flags
= AI_CANONNAME
;
189 error
= getaddrinfo(*ahost
, pbuf
, &hints
, &res
);
191 warnx("%s: %s", *ahost
, gai_strerror(error
)); /*XXX*/
194 if (res
->ai_canonname
) {
195 strlcpy(hbuf
, res
->ai_canonname
, sizeof(hbuf
));
199 error
= resrcmd(res
, ahost
, rport
, locuser
, remuser
, cmd
, fd2p
);
206 resrcmd(res
, ahost
, rport
, locuser
, remuser
, cmd
, fd2p
)
207 struct addrinfo
*res
;
210 const char *locuser
, *remuser
, *cmd
;
214 struct sockaddr_storage from
;
215 struct pollfd reads
[2];
216 sigset_t nmask
, omask
;
223 _DIAGASSERT(res
!= NULL
);
224 _DIAGASSERT(ahost
!= NULL
);
225 _DIAGASSERT(locuser
!= NULL
);
226 _DIAGASSERT(remuser
!= NULL
);
227 _DIAGASSERT(cmd
!= NULL
);
228 /* fd2p may be NULL */
234 sigaddset(&nmask
, SIGURG
);
235 if (sigprocmask(SIG_BLOCK
, &nmask
, &omask
) == -1)
237 for (timo
= 1, lport
= IPPORT_RESERVED
- 1;;) {
238 s
= rresvport_af(&lport
, r
->ai_family
);
241 warnx("rcmd: socket: All ports in use");
243 warn("rcmd: socket");
248 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
252 fcntl(s
, F_SETOWN
, pid
);
253 if (connect(s
, r
->ai_addr
, r
->ai_addrlen
) >= 0)
256 if (errno
== EADDRINUSE
) {
259 } else if (errno
== ECONNREFUSED
)
263 char hbuf
[NI_MAXHOST
];
264 const int niflags
= NI_NUMERICHOST
;
267 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
,
268 hbuf
, sizeof(hbuf
), NULL
, 0, niflags
) != 0)
269 strlcpy(hbuf
, "(invalid)", sizeof(hbuf
));
271 warn("rcmd: connect to address %s", hbuf
);
274 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
,
275 hbuf
, sizeof(hbuf
), NULL
, 0, niflags
) != 0)
276 strlcpy(hbuf
, "(invalid)", sizeof(hbuf
));
277 (void)fprintf(stderr
, "Trying %s...\n", hbuf
);
280 if (refused
&& timo
<= 16) {
281 (void)sleep((unsigned int)timo
);
287 (void)fprintf(stderr
, "%s: %s\n", res
->ai_canonname
,
289 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
298 int s2
= rresvport_af(&lport
, r
->ai_family
), s3
;
299 socklen_t len
= sizeof(from
);
304 (void)snprintf(num
, sizeof(num
), "%d", lport
);
305 if (write(s
, num
, strlen(num
) + 1) !=
306 (ssize_t
) (strlen(num
) + 1)) {
307 warn("rcmd: write (setting up stderr)");
312 reads
[0].events
= POLLIN
;
314 reads
[1].events
= POLLIN
;
316 pollr
= poll(reads
, 2, INFTIM
);
317 if (pollr
< 1 || (reads
[1].revents
& POLLIN
) == 0) {
319 warn("poll: setting up stderr");
321 warnx("poll: protocol failure in circuit setup");
325 s3
= accept(s2
, (struct sockaddr
*)(void *)&from
, &len
);
328 warn("rcmd: accept");
333 switch (((struct sockaddr
*)(void *)&from
)->sa_family
) {
338 if (getnameinfo((struct sockaddr
*)(void *)&from
, len
,
339 NULL
, 0, num
, sizeof(num
), NI_NUMERICSERV
) != 0 ||
340 (atoi(num
) >= IPPORT_RESERVED
||
341 atoi(num
) < IPPORT_RESERVED
/ 2)) {
342 warnx("rcmd: protocol failure in circuit setup.");
351 (void)write(s
, locuser
, strlen(locuser
)+1);
352 (void)write(s
, remuser
, strlen(remuser
)+1);
353 (void)write(s
, cmd
, strlen(cmd
)+1);
354 if (read(s
, &c
, 1) != 1) {
359 while (read(s
, &c
, 1) == 1) {
360 (void)write(STDERR_FILENO
, &c
, 1);
366 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
373 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
378 * based on code written by Chris Siebenmann <cks@utcc.utoronto.ca>
382 rshrcmd(ahost
, rport
, locuser
, remuser
, cmd
, fd2p
, rshcmd
)
385 const char *locuser
, *remuser
, *cmd
;
392 struct passwd
*pw
, pwres
;
395 _DIAGASSERT(ahost
!= NULL
);
396 _DIAGASSERT(locuser
!= NULL
);
397 _DIAGASSERT(remuser
!= NULL
);
398 _DIAGASSERT(cmd
!= NULL
);
399 /* fd2p may be NULL */
401 /* What rsh/shell to use. */
403 rshcmd
= _PATH_BIN_RCMD
;
405 /* locuser must exist on this host. */
406 if (getpwnam_r(locuser
, &pwres
, pwbuf
, sizeof(pwbuf
), &pw
) != 0 ||
408 warnx("rshrcmd: unknown user: %s", locuser
);
412 /* get a socketpair we'll use for stdin and stdout. */
413 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, sp
) < 0) {
414 warn("rshrcmd: socketpair");
417 /* we will use this for the fd2 pointer */
419 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, ep
) < 0) {
420 warn("rshrcmd: socketpair");
428 warn("rshrcmd: fork");
434 * - we use sp[1] to be stdin/stdout, and close sp[0]
435 * - with fd2p, we use ep[1] for stderr, and close ep[0]
438 if (dup2(sp
[1], 0) < 0 || dup2(0, 1) < 0) {
439 warn("rshrcmd: dup2");
444 if (dup2(ep
[1], 2) < 0) {
445 warn("rshrcmd: dup2");
450 } else if (dup2(0, 2) < 0) {
451 warn("rshrcmd: dup2");
454 /* fork again to lose parent. */
457 warn("rshrcmd: second fork");
463 /* Orphan. Become local user for rshprog. */
464 if (setuid(pw
->pw_uid
)) {
465 warn("rshrcmd: setuid(%lu)", (u_long
)pw
->pw_uid
);
470 * If we are rcmd'ing to "localhost" as the same user as we are,
471 * then avoid running remote shell for efficiency.
473 if (strcmp(*ahost
, "localhost") == 0 &&
474 strcmp(locuser
, remuser
) == 0) {
475 if (pw
->pw_shell
[0] == '\0')
476 rshcmd
= _PATH_BSHELL
;
478 rshcmd
= pw
->pw_shell
;
479 p
= strrchr(rshcmd
, '/');
480 execlp(rshcmd
, p
? p
+ 1 : rshcmd
, "-c", cmd
, NULL
);
482 p
= strrchr(rshcmd
, '/');
483 execlp(rshcmd
, p
? p
+ 1 : rshcmd
, *ahost
, "-l",
486 warn("rshrcmd: exec %s", rshcmd
);
494 (void)waitpid(pid
, NULL
, 0);
503 _DIAGASSERT(alport
!= NULL
);
505 return rresvport_af(alport
, AF_INET
);
509 rresvport_af(alport
, family
)
513 struct sockaddr_storage ss
;
519 _DIAGASSERT(alport
!= NULL
);
521 memset(&ss
, 0, sizeof(ss
));
522 sa
= (struct sockaddr
*)(void *)&ss
;
528 salen
= sizeof(struct sockaddr_in
);
529 portp
= &((struct sockaddr_in
*)(void *)sa
)->sin_port
;
536 salen
= sizeof(struct sockaddr_in6
);
537 portp
= &((struct sockaddr_in6
*)(void *)sa
)->sin6_port
;
541 errno
= EAFNOSUPPORT
;
544 sa
->sa_family
= family
;
545 s
= socket(family
, SOCK_STREAM
, 0);
553 if (bindresvport(s
, (struct sockaddr_in
*)(void *)sa
) < 0) {
560 *alport
= (int)ntohs(*portp
);
563 /* is it necessary to try keep code for other AFs? */
568 *portp
= htons((u_short
)*alport
);
569 if (bind(s
, sa
, (socklen_t
)salen
) >= 0)
571 if (errno
!= EADDRINUSE
) {
576 if (*alport
== IPPORT_RESERVED
/2) {
578 errno
= EAGAIN
; /* close */
584 int __check_rhosts_file
= 1;
585 const char *__rcmd_errstr
;
588 ruserok(rhost
, superuser
, ruser
, luser
)
589 const char *rhost
, *ruser
, *luser
;
592 struct addrinfo hints
, *res
, *r
;
595 _DIAGASSERT(rhost
!= NULL
);
596 _DIAGASSERT(ruser
!= NULL
);
597 _DIAGASSERT(luser
!= NULL
);
599 memset(&hints
, 0, sizeof(hints
));
600 hints
.ai_family
= PF_UNSPEC
;
601 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
602 error
= getaddrinfo(rhost
, "0", &hints
, &res
);
606 for (r
= res
; r
; r
= r
->ai_next
) {
607 if (iruserok_sa(r
->ai_addr
, (int)r
->ai_addrlen
, superuser
,
608 ruser
, luser
) == 0) {
618 * New .rhosts strategy: We are passed an ip address. We spin through
619 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
620 * has ip addresses, we don't have to trust a nameserver. When it
621 * contains hostnames, we spin through the list of addresses the nameserver
622 * gives us and look for a match.
624 * Returns 0 if ok, -1 if not ok.
627 iruserok(raddr
, superuser
, ruser
, luser
)
630 const char *ruser
, *luser
;
632 struct sockaddr_in irsin
;
634 memset(&irsin
, 0, sizeof(irsin
));
635 irsin
.sin_family
= AF_INET
;
637 irsin
.sin_len
= sizeof(struct sockaddr_in
);
639 memcpy(&irsin
.sin_addr
, &raddr
, sizeof(irsin
.sin_addr
));
640 return iruserok_sa(&irsin
, sizeof(struct sockaddr_in
), superuser
, ruser
,
645 * 2nd and 3rd arguments are typed like this, to avoid dependency between
646 * unistd.h and sys/socket.h. There's no better way.
649 iruserok_sa(raddr
, rlen
, superuser
, ruser
, luser
)
653 const char *ruser
, *luser
;
655 const struct sockaddr
*sa
;
657 struct passwd
*pwd
, pwres
;
662 char pbuf
[MAXPATHLEN
];
665 _DIAGASSERT(raddr
!= NULL
);
666 _DIAGASSERT(ruser
!= NULL
);
667 _DIAGASSERT(luser
!= NULL
);
671 __rcmd_errstr
= NULL
;
673 hostf
= superuser
? NULL
: fopen(_PATH_HEQUIV
, "r");
676 if (__ivaliduser_sa(hostf
, sa
, (socklen_t
)rlen
, luser
,
685 if (__check_rhosts_file
|| superuser
) {
687 if (getpwnam_r(luser
, &pwres
, pwbuf
, sizeof(pwbuf
), &pwd
) != 0
690 (void)strlcpy(pbuf
, pwd
->pw_dir
, sizeof(pbuf
));
691 (void)strlcat(pbuf
, "/.rhosts", sizeof(pbuf
));
694 * Change effective uid while opening and reading .rhosts.
695 * If root and reading an NFS mounted file system, can't
696 * read files that are protected read/write owner only.
700 (void)setegid(pwd
->pw_gid
);
701 initgroups(pwd
->pw_name
, pwd
->pw_gid
);
702 (void)seteuid(pwd
->pw_uid
);
703 hostf
= fopen(pbuf
, "r");
707 * If not a regular file, or is owned by someone other
708 * than user or root or if writable by anyone but the
711 if (lstat(pbuf
, &sbuf
) < 0)
712 __rcmd_errstr
= ".rhosts lstat failed";
713 else if (!S_ISREG(sbuf
.st_mode
))
714 __rcmd_errstr
= ".rhosts not regular file";
715 else if (fstat(fileno(hostf
), &sbuf
) < 0)
716 __rcmd_errstr
= ".rhosts fstat failed";
717 else if (sbuf
.st_uid
&& sbuf
.st_uid
!= pwd
->pw_uid
)
718 __rcmd_errstr
= "bad .rhosts owner";
719 else if (sbuf
.st_mode
& (S_IWGRP
|S_IWOTH
))
721 ".rhosts writable by other than owner";
724 __ivaliduser_sa(hostf
, sa
, (socklen_t
)rlen
,
733 return (isvaliduser
);
738 * Don't make static, used by lpd(8). We will be able to change the function
739 * into static function, when we bump libc major #.
741 * Returns 0 if ok, -1 if not ok.
743 #ifdef notdef /*_LIBC*/
747 __ivaliduser(hostf
, raddr
, luser
, ruser
)
750 const char *luser
, *ruser
;
752 struct sockaddr_in ivusin
;
754 memset(&ivusin
, 0, sizeof(ivusin
));
755 ivusin
.sin_family
= AF_INET
;
757 ivusin
.sin_len
= sizeof(struct sockaddr_in
);
759 memcpy(&ivusin
.sin_addr
, &raddr
, sizeof(ivusin
.sin_addr
));
760 return __ivaliduser_sa(hostf
, (struct sockaddr
*)(void *)&ivusin
,
761 sizeof(struct sockaddr_in
), luser
, ruser
);
764 #ifdef notdef /*_LIBC*/
768 __ivaliduser_sa(hostf
, raddr
, salen
, luser
, ruser
)
770 const struct sockaddr
*raddr
;
772 const char *luser
, *ruser
;
774 register char *user
, *p
;
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
, 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
,
861 hostok
= -__icheckhost(raddr
, salen
, &ahost
[1]);
865 hostok
= __icheckhost(raddr
, salen
, ahost
);
875 userok
= innetgr(&auser
[2], NULL
, ruser
,
880 userok
= strcmp(ruser
, &auser
[1]) == 0;
883 else if (auser
[0] == '-')
890 userok
= -innetgr(&auser
[2], NULL
, ruser
,
896 -(strcmp(ruser
, &auser
[1]) == 0 ? 1 : 0);
900 userok
= strcmp(ruser
, auser
) == 0;
902 /* Check if one component did not match */
903 if (hostok
== 0 || userok
== 0)
906 /* Check if we got a forbidden pair */
907 if (userok
== -1 || hostok
== -1)
910 /* Check if we got a valid pair */
911 if (hostok
== 1 && userok
== 1)
918 * Returns "true" if match, 0 if no match.
921 __icheckhost(raddr
, salen
, lhost
)
922 const struct sockaddr
*raddr
;
926 struct addrinfo hints
, *res
, *r
;
927 char h1
[NI_MAXHOST
], h2
[NI_MAXHOST
];
929 const int niflags
= NI_NUMERICHOST
;
931 _DIAGASSERT(raddr
!= NULL
);
932 _DIAGASSERT(lhost
!= NULL
);
935 if (getnameinfo(raddr
, salen
, h1
, sizeof(h1
), NULL
, 0,
939 /* Resolve laddr into sockaddr */
940 memset(&hints
, 0, sizeof(hints
));
941 hints
.ai_family
= raddr
->sa_family
;
942 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
944 error
= getaddrinfo(lhost
, "0", &hints
, &res
);
949 * Try string comparisons between raddr and laddr.
951 for (r
= res
; r
; r
= r
->ai_next
) {
953 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
, h2
, sizeof(h2
),
954 NULL
, 0, niflags
) != 0)
956 if (strcmp(h1
, h2
) == 0) {
968 * Return the hostname associated with the supplied address.
969 * Do a reverse lookup as well for security. If a loop cannot
970 * be found, pack the numeric IP address into the string.
973 __gethostloop(raddr
, salen
)
974 const struct sockaddr
*raddr
;
977 static char remotehost
[NI_MAXHOST
];
978 char h1
[NI_MAXHOST
], h2
[NI_MAXHOST
];
979 struct addrinfo hints
, *res
, *r
;
981 const int niflags
= NI_NUMERICHOST
;
983 _DIAGASSERT(raddr
!= NULL
);
985 h1
[0] = remotehost
[0] = '\0';
986 if (getnameinfo(raddr
, salen
, remotehost
, sizeof(remotehost
),
987 NULL
, 0, NI_NAMEREQD
) != 0)
989 if (getnameinfo(raddr
, salen
, h1
, sizeof(h1
), NULL
, 0,
994 * Look up the name and check that the supplied
995 * address is in the list
997 memset(&hints
, 0, sizeof(hints
));
998 hints
.ai_family
= raddr
->sa_family
;
999 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
1000 hints
.ai_flags
= AI_CANONNAME
;
1002 error
= getaddrinfo(remotehost
, "0", &hints
, &res
);
1006 for (r
= res
; r
; r
= r
->ai_next
) {
1008 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
, h2
, sizeof(h2
),
1009 NULL
, 0, niflags
) != 0)
1011 if (strcmp(h1
, h2
) == 0) {
1013 return (remotehost
);
1018 * either the DNS adminstrator has made a configuration
1019 * mistake, or someone has attempted to spoof us
1021 syslog(LOG_NOTICE
, "rcmd: address %s not listed for host %s",
1022 h1
, res
->ai_canonname
? res
->ai_canonname
: remotehost
);