1 /* $NetBSD: rcmd.c,v 1.68 2012/07/14 15:06:26 darrenr 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.68 2012/07/14 15:06:26 darrenr 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];
200 /* No support for OOB data in Minix. */
202 sigset_t nmask
, omask
;
203 #endif /* defined(__minix) */
210 _DIAGASSERT(res
!= NULL
);
211 _DIAGASSERT(ahost
!= NULL
);
212 _DIAGASSERT(locuser
!= NULL
);
213 _DIAGASSERT(remuser
!= NULL
);
214 _DIAGASSERT(cmd
!= NULL
);
215 /* fd2p may be NULL */
220 #if !defined(__minix)
221 /* Minix has no support for OOB data,
222 no need to block SIGURG. */
224 sigaddset(&nmask
, SIGURG
);
225 if (sigprocmask(SIG_BLOCK
, &nmask
, &omask
) == -1)
227 #endif /* !defined(__minix) */
228 for (timo
= 1, lport
= IPPORT_RESERVED
- 1;;) {
229 s
= rresvport_af(&lport
, r
->ai_family
);
232 warnx("rcmd: socket: All ports in use");
234 warn("rcmd: socket");
239 #if !defined(__minix)
240 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
241 #endif /* !defined(__minix) */
245 #if !defined(__minix)
246 /* No OOB support in Minix. */
247 fcntl(s
, F_SETOWN
, pid
);
248 #endif /* !defined(__minix) */
249 if (connect(s
, r
->ai_addr
, r
->ai_addrlen
) >= 0)
252 if (errno
== EADDRINUSE
) {
255 } else if (errno
== ECONNREFUSED
)
259 char hbuf
[NI_MAXHOST
];
260 const int niflags
= NI_NUMERICHOST
;
263 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
,
264 hbuf
, (socklen_t
)sizeof(hbuf
), NULL
, 0, niflags
) !=
266 strlcpy(hbuf
, "(invalid)", sizeof(hbuf
));
268 warn("rcmd: connect to address %s", hbuf
);
271 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
,
272 hbuf
, (socklen_t
)sizeof(hbuf
), NULL
, 0, niflags
) !=
274 strlcpy(hbuf
, "(invalid)", sizeof(hbuf
));
275 (void)fprintf(stderr
, "Trying %s...\n", hbuf
);
278 if (refused
&& timo
<= 16) {
279 (void)sleep((unsigned int)timo
);
285 (void)fprintf(stderr
, "%s: %s\n", res
->ai_canonname
,
287 #if !defined(__minix)
288 /* No OOB support in Minix. */
289 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
290 #endif /* !defined(__minix) */
299 int s2
= rresvport_af(&lport
, r
->ai_family
), s3
;
300 socklen_t len
= sizeof(from
);
305 (void)snprintf(num
, sizeof(num
), "%d", lport
);
306 if (write(s
, num
, strlen(num
) + 1) !=
307 (ssize_t
) (strlen(num
) + 1)) {
308 warn("rcmd: write (setting up stderr)");
313 reads
[0].events
= POLLIN
;
315 reads
[1].events
= POLLIN
;
317 pollr
= poll(reads
, 2, INFTIM
);
318 if (pollr
< 1 || (reads
[1].revents
& POLLIN
) == 0) {
320 warn("poll: setting up stderr");
323 "poll: protocol failure in circuit setup");
327 s3
= accept(s2
, (struct sockaddr
*)(void *)&from
, &len
);
330 warn("rcmd: accept");
335 switch (((struct sockaddr
*)(void *)&from
)->sa_family
) {
340 if (getnameinfo((struct sockaddr
*)(void *)&from
, len
,
341 NULL
, 0, num
, (socklen_t
)sizeof(num
),
342 NI_NUMERICSERV
) != 0 ||
343 (atoi(num
) >= IPPORT_RESERVED
||
344 atoi(num
) < IPPORT_RESERVED
/ 2)) {
346 "rcmd: protocol failure in circuit setup.");
355 (void)write(s
, locuser
, strlen(locuser
)+1);
356 (void)write(s
, remuser
, strlen(remuser
)+1);
357 (void)write(s
, cmd
, strlen(cmd
)+1);
358 if (read(s
, &c
, 1) != 1) {
363 while (read(s
, &c
, 1) == 1) {
364 (void)write(STDERR_FILENO
, &c
, 1);
370 #if !defined(__minix)
371 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
372 #endif /* !defined(__minix) */
379 #if !defined(__minix)
380 (void)sigprocmask(SIG_SETMASK
, &omask
, NULL
);
381 #endif /* !defined(__minix) */
386 * based on code written by Chris Siebenmann <cks@utcc.utoronto.ca>
390 rshrcmd(int af
, char **ahost
, u_int32_t rport
, const char *locuser
,
391 const char *remuser
, const char *cmd
, int *fd2p
, const char *rshcmd
)
396 struct passwd
*pw
, pwres
;
399 _DIAGASSERT(ahost
!= NULL
);
400 _DIAGASSERT(locuser
!= NULL
);
401 _DIAGASSERT(remuser
!= NULL
);
402 _DIAGASSERT(cmd
!= NULL
);
403 /* fd2p may be NULL */
405 /* What rsh/shell to use. */
407 rshcmd
= _PATH_BIN_RCMD
;
409 /* locuser must exist on this host. */
410 if (getpwnam_r(locuser
, &pwres
, pwbuf
, sizeof(pwbuf
), &pw
) != 0 ||
412 warnx("%s: unknown user: %s", __func__
, locuser
);
416 /* get a socketpair we'll use for stdin and stdout. */
417 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, sp
) < 0) {
418 warn("%s: socketpair", __func__
);
421 /* we will use this for the fd2 pointer */
423 if (socketpair(AF_LOCAL
, SOCK_STREAM
, 0, ep
) < 0) {
424 warn("%s: socketpair", __func__
);
432 warn("%s: fork", __func__
);
438 * - we use sp[1] to be stdin/stdout, and close sp[0]
439 * - with fd2p, we use ep[1] for stderr, and close ep[0]
442 if (dup2(sp
[1], 0) < 0 || dup2(0, 1) < 0) {
443 warn("%s: dup2", __func__
);
448 if (dup2(ep
[1], 2) < 0) {
449 warn("%s: dup2", __func__
);
454 } else if (dup2(0, 2) < 0) {
455 warn("%s: dup2", __func__
);
458 /* fork again to lose parent. */
461 warn("%s: second fork", __func__
);
467 /* Orphan. Become local user for rshprog. */
468 if (setuid(pw
->pw_uid
)) {
469 warn("%s: setuid(%lu)", __func__
, (u_long
)pw
->pw_uid
);
474 * If we are rcmd'ing to "localhost" as the same user as we
475 * are, then avoid running remote shell for efficiency.
477 if (strcmp(*ahost
, "localhost") == 0 &&
478 strcmp(locuser
, remuser
) == 0) {
479 if (pw
->pw_shell
[0] == '\0')
480 rshcmd
= _PATH_BSHELL
;
482 rshcmd
= pw
->pw_shell
;
483 p
= strrchr(rshcmd
, '/');
484 execlp(rshcmd
, p
? p
+ 1 : rshcmd
, "-c", cmd
, NULL
);
487 program
= strrchr(rshcmd
, '/');
488 program
= program
? program
+ 1 : rshcmd
;
491 execlp(rshcmd
, program
, "-4", "-l", remuser
,
496 execlp(rshcmd
, program
, "-6", "-l", remuser
,
501 /* typically AF_UNSPEC, plus whatever */
502 execlp(rshcmd
, program
, "-l", remuser
,
507 warn("%s: exec %s", __func__
, rshcmd
);
515 (void)waitpid(pid
, NULL
, 0);
520 rresvport(int *alport
)
523 _DIAGASSERT(alport
!= NULL
);
525 return rresvport_af(alport
, AF_INET
);
529 rresvport_af(int *alport
, int family
)
531 return rresvport_af_addr(alport
, family
, NULL
);
535 rresvport_af_addr(int *alport
, int family
, void *addr
)
537 struct sockaddr_storage ss
;
543 _DIAGASSERT(alport
!= NULL
);
545 memset(&ss
, 0, sizeof(ss
));
546 sa
= (struct sockaddr
*)(void *)&ss
;
552 salen
= sizeof(struct sockaddr_in
);
554 ((struct sockaddr_in
*)(void *)sa
)->sin_addr
=
555 ((struct sockaddr_in
*)addr
)->sin_addr
;
556 portp
= &((struct sockaddr_in
*)(void *)sa
)->sin_port
;
563 salen
= sizeof(struct sockaddr_in6
);
565 ((struct sockaddr_in6
*)(void *)sa
)->sin6_addr
=
566 ((struct sockaddr_in6
*)addr
)->sin6_addr
;
567 portp
= &((struct sockaddr_in6
*)(void *)sa
)->sin6_port
;
571 errno
= EAFNOSUPPORT
;
574 sa
->sa_family
= family
;
575 s
= socket(family
, SOCK_STREAM
, 0);
578 #if defined(BSD4_4) && !defined(__minix)
583 if (bindresvport(s
, (struct sockaddr_in
*)(void *)sa
) < 0) {
590 *alport
= (int)ntohs(*portp
);
593 /* is it necessary to try keep code for other AFs? */
598 *portp
= htons((u_short
)*alport
);
599 if (bind(s
, sa
, salen
) >= 0)
601 if (errno
!= EADDRINUSE
) {
606 if (*alport
== IPPORT_RESERVED
/2) {
608 errno
= EAGAIN
; /* close */
614 int __check_rhosts_file
= 1;
615 const char *__rcmd_errstr
;
618 ruserok(const char *rhost
, int superuser
, const char *ruser
, const char *luser
)
620 struct addrinfo hints
, *res
, *r
;
623 _DIAGASSERT(rhost
!= NULL
);
624 _DIAGASSERT(ruser
!= NULL
);
625 _DIAGASSERT(luser
!= NULL
);
627 memset(&hints
, 0, sizeof(hints
));
628 hints
.ai_family
= PF_UNSPEC
;
629 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
630 error
= getaddrinfo(rhost
, "0", &hints
, &res
);
634 for (r
= res
; r
; r
= r
->ai_next
) {
635 if (iruserok_sa(r
->ai_addr
, (int)r
->ai_addrlen
, superuser
,
636 ruser
, luser
) == 0) {
646 * New .rhosts strategy: We are passed an ip address. We spin through
647 * hosts.equiv and .rhosts looking for a match. When the .rhosts only
648 * has ip addresses, we don't have to trust a nameserver. When it
649 * contains hostnames, we spin through the list of addresses the nameserver
650 * gives us and look for a match.
652 * Returns 0 if ok, -1 if not ok.
655 iruserok(u_int32_t raddr
, int superuser
, const char *ruser
, const char *luser
)
657 struct sockaddr_in irsin
;
659 memset(&irsin
, 0, sizeof(irsin
));
660 irsin
.sin_family
= AF_INET
;
662 irsin
.sin_len
= sizeof(irsin
);
664 memcpy(&irsin
.sin_addr
, &raddr
, sizeof(irsin
.sin_addr
));
665 return iruserok_sa(&irsin
, (socklen_t
)sizeof(irsin
), superuser
, ruser
,
670 * 2nd and 3rd arguments are typed like this, to avoid dependency between
671 * unistd.h and sys/socket.h. There's no better way.
674 iruserok_sa(const void *raddr
, int rlen
, int superuser
, const char *ruser
,
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
,
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(FILE *hostf
, u_int32_t raddr
, const char *luser
,
772 struct sockaddr_in ivusin
;
774 memset(&ivusin
, 0, sizeof(ivusin
));
775 ivusin
.sin_family
= AF_INET
;
777 ivusin
.sin_len
= sizeof(ivusin
);
779 memcpy(&ivusin
.sin_addr
, &raddr
, sizeof(ivusin
.sin_addr
));
780 return __ivaliduser_sa(hostf
, (struct sockaddr
*)(void *)&ivusin
,
781 (socklen_t
)sizeof(ivusin
), luser
, ruser
);
784 #ifdef notdef /*_LIBC*/
788 __ivaliduser_sa(FILE *hostf
, const struct sockaddr
*raddr
, socklen_t salen
,
789 const char *luser
, const char *ruser
)
793 char buf
[MAXHOSTNAMELEN
+ 128]; /* host + login */
794 const char *auser
, *ahost
;
798 char domain
[MAXHOSTNAMELEN
];
800 getdomainname(domain
, sizeof(domain
));
802 _DIAGASSERT(hostf
!= NULL
);
803 _DIAGASSERT(luser
!= NULL
);
804 _DIAGASSERT(ruser
!= NULL
);
806 while (fgets(buf
, (int)sizeof(buf
), hostf
)) {
808 /* Skip lines that are too long. */
809 if (strchr(p
, '\n') == NULL
) {
810 while ((ch
= getc(hostf
)) != '\n' && ch
!= EOF
)
814 while (*p
!= '\n' && *p
!= ' ' && *p
!= '\t' && *p
!= '\0') {
815 *p
= isupper((unsigned char)*p
) ?
816 tolower((unsigned char)*p
) : *p
;
819 if (*p
== ' ' || *p
== '\t') {
821 while (*p
== ' ' || *p
== '\t')
824 while (*p
!= '\n' && *p
!= ' ' &&
825 *p
!= '\t' && *p
!= '\0')
834 auser
= *user
? user
: luser
;
845 rhost
= __gethostloop(raddr
, salen
);
849 hostok
= innetgr(&ahost
[2], rhost
,
856 hostok
= __icheckhost(raddr
, salen
, &ahost
[1]);
859 else if (ahost
[0] == '-')
867 rhost
= __gethostloop(raddr
, salen
);
871 hostok
= -innetgr(&ahost
[2], rhost
,
879 -__icheckhost(raddr
, salen
, &ahost
[1]);
883 hostok
= __icheckhost(raddr
, salen
, ahost
);
893 userok
= innetgr(&auser
[2], NULL
, ruser
,
898 userok
= strcmp(ruser
, &auser
[1]) == 0;
901 else if (auser
[0] == '-')
908 userok
= -innetgr(&auser
[2], NULL
, ruser
,
914 -(strcmp(ruser
, &auser
[1]) == 0 ? 1 : 0);
918 userok
= strcmp(ruser
, auser
) == 0;
920 /* Check if one component did not match */
921 if (hostok
== 0 || userok
== 0)
924 /* Check if we got a forbidden pair */
925 if (userok
== -1 || hostok
== -1)
928 /* Check if we got a valid pair */
929 if (hostok
== 1 && userok
== 1)
936 * Returns "true" if match, 0 if no match.
939 __icheckhost(const struct sockaddr
*raddr
, socklen_t salen
, const char *lhost
)
941 struct addrinfo hints
, *res
, *r
;
942 char h1
[NI_MAXHOST
], h2
[NI_MAXHOST
];
944 const int niflags
= NI_NUMERICHOST
;
946 _DIAGASSERT(raddr
!= NULL
);
947 _DIAGASSERT(lhost
!= NULL
);
950 if (getnameinfo(raddr
, salen
, h1
, (socklen_t
)sizeof(h1
), NULL
, 0,
954 /* Resolve laddr into sockaddr */
955 memset(&hints
, 0, sizeof(hints
));
956 hints
.ai_family
= raddr
->sa_family
;
957 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
959 error
= getaddrinfo(lhost
, "0", &hints
, &res
);
964 * Try string comparisons between raddr and laddr.
966 for (r
= res
; r
; r
= r
->ai_next
) {
968 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
, h2
,
969 (socklen_t
)sizeof(h2
), NULL
, 0, niflags
) != 0)
971 if (strcmp(h1
, h2
) == 0) {
983 * Return the hostname associated with the supplied address.
984 * Do a reverse lookup as well for security. If a loop cannot
985 * be found, pack the numeric IP address into the string.
988 __gethostloop(const struct sockaddr
*raddr
, socklen_t salen
)
990 static char remotehost
[NI_MAXHOST
];
991 char h1
[NI_MAXHOST
], h2
[NI_MAXHOST
];
992 struct addrinfo hints
, *res
, *r
;
994 const int niflags
= NI_NUMERICHOST
;
996 _DIAGASSERT(raddr
!= NULL
);
998 h1
[0] = remotehost
[0] = '\0';
999 if (getnameinfo(raddr
, salen
, remotehost
, (socklen_t
)sizeof(remotehost
),
1000 NULL
, 0, NI_NAMEREQD
) != 0)
1002 if (getnameinfo(raddr
, salen
, h1
, (socklen_t
)sizeof(h1
), NULL
, 0,
1007 * Look up the name and check that the supplied
1008 * address is in the list
1010 memset(&hints
, 0, sizeof(hints
));
1011 hints
.ai_family
= raddr
->sa_family
;
1012 hints
.ai_socktype
= SOCK_DGRAM
; /*dummy*/
1013 hints
.ai_flags
= AI_CANONNAME
;
1015 error
= getaddrinfo(remotehost
, "0", &hints
, &res
);
1019 for (r
= res
; r
; r
= r
->ai_next
) {
1021 if (getnameinfo(r
->ai_addr
, r
->ai_addrlen
, h2
,
1022 (socklen_t
)sizeof(h2
), NULL
, 0, niflags
) != 0)
1024 if (strcmp(h1
, h2
) == 0) {
1031 * either the DNS adminstrator has made a configuration
1032 * mistake, or someone has attempted to spoof us
1034 syslog(LOG_NOTICE
, "rcmd: address %s not listed for host %s",
1035 h1
, res
->ai_canonname
? res
->ai_canonname
: remotehost
);