1 /* $NetBSD: rcmd.c,v 1.30 1999/03/16 18:15:13 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Matthew R. Green. 5 * Copyright (c) 1983, 1993, 1994 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 #if defined(LIBC_SCCS) && !defined(lint) 39 #if 0 40 static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; 41 #else 42 __RCSID("$NetBSD: rcmd.c,v 1.30 1999/03/16 18:15:13 christos Exp $"); 43 #endif 44 #endif /* LIBC_SCCS and not lint */ 45 46 #include "namespace.h" 47 #include <sys/param.h> 48 #include <sys/socket.h> 49 #include <sys/stat.h> 50 #include <sys/poll.h> 51 #include <sys/wait.h> 52 53 #include <netinet/in.h> 54 #include <rpc/rpc.h> 55 #include <arpa/inet.h> 56 #include <netgroup.h> 57 58 #include <signal.h> 59 #include <fcntl.h> 60 #include <netdb.h> 61 #include <unistd.h> 62 #include <pwd.h> 63 #include <grp.h> 64 #include <errno.h> 65 #include <stdio.h> 66 #include <ctype.h> 67 #include <string.h> 68 #include <syslog.h> 69 #include <stdlib.h> 70 #include <paths.h> 71 #include <err.h> 72 73 #include "pathnames.h" 74 75 int orcmd __P((char **, u_int, const char *, const char *, const char *, 76 int *)); 77 int __ivaliduser __P((FILE *, u_int32_t, const char *, const char *)); 78 static int rshrcmd __P((char **, u_int32_t, const char *, const char *, 79 const char *, int *, const char *)); 80 static int hprcmd __P((struct hostent *, char **, u_int32_t, const char *, 81 const char *, const char *, int *)); 82 static int __icheckhost __P((u_int32_t, const char *)); 83 static char *__gethostloop __P((u_int32_t)); 84 85 int 86 rcmd(ahost, rport, locuser, remuser, cmd, fd2p) 87 char **ahost; 88 u_short rport; 89 const char *locuser, *remuser, *cmd; 90 int *fd2p; 91 { 92 struct hostent *hp; 93 struct servent *sp; 94 95 /* 96 * Canonicalise hostname. 97 * XXX: Should we really do this? 98 */ 99 hp = gethostbyname(*ahost); 100 if (hp == NULL) { 101 herror(*ahost); 102 return (-1); 103 } 104 *ahost = hp->h_name; 105 106 /* 107 * Check if rport is the same as the shell port, and that the fd2p. If 108 * it is not, the program isn't expecting 'rsh' and so we can't use the 109 * RCMD_CMD environment. 110 */ 111 sp = getservbyname("shell", "tcp"); 112 if (sp != NULL && sp->s_port == rport) 113 return (rshrcmd(ahost, (u_int32_t)rport, 114 locuser, remuser, cmd, fd2p, getenv("RCMD_CMD"))); 115 else 116 return (hprcmd(hp, ahost, (u_int32_t)rport, 117 locuser, remuser, cmd, fd2p)); 118 } 119 120 /* this is simply a wrapper around hprcmd() that handles ahost first */ 121 int 122 orcmd(ahost, rport, locuser, remuser, cmd, fd2p) 123 char **ahost; 124 u_int rport; 125 const char *locuser, *remuser, *cmd; 126 int *fd2p; 127 { 128 struct hostent *hp; 129 130 hp = gethostbyname(*ahost); 131 if (hp == NULL) { 132 herror(*ahost); 133 return (-1); 134 } 135 *ahost = hp->h_name; 136 137 return (hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p)); 138 } 139 140 static int 141 hprcmd(hp, ahost, rport, locuser, remuser, cmd, fd2p) 142 struct hostent *hp; 143 char **ahost; 144 u_int32_t rport; 145 const char *locuser, *remuser, *cmd; 146 int *fd2p; 147 { 148 struct sockaddr_in sin, from; 149 struct pollfd reads[2]; 150 sigset_t nmask, omask; 151 pid_t pid; 152 int s, lport, timo; 153 int pollr; 154 char c; 155 156 pid = getpid(); 157 sigemptyset(&nmask); 158 sigaddset(&nmask, SIGURG); 159 if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1) 160 return -1; 161 for (timo = 1, lport = IPPORT_RESERVED - 1;;) { 162 s = rresvport(&lport); 163 if (s < 0) { 164 if (errno == EAGAIN) 165 warnx("rcmd: socket: All ports in use"); 166 else 167 warn("rcmd: socket"); 168 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 169 return (-1); 170 } 171 fcntl(s, F_SETOWN, pid); 172 #ifdef BSD4_4 173 sin.sin_len = sizeof(struct sockaddr_in); 174 #endif 175 sin.sin_family = hp->h_addrtype; 176 sin.sin_port = rport; 177 memmove(&sin.sin_addr, 178 hp->h_addr_list[0], (size_t)hp->h_length); 179 if (connect(s, (struct sockaddr *)(void *)&sin, sizeof(sin)) >= 0) 180 break; 181 (void)close(s); 182 if (errno == EADDRINUSE) { 183 lport--; 184 continue; 185 } 186 if (errno == ECONNREFUSED && timo <= 16) { 187 (void)sleep((unsigned int)timo); 188 timo *= 2; 189 continue; 190 } 191 if (hp->h_addr_list[1] != NULL) { 192 int oerrno = errno; 193 194 warnx("rcmd: connect to address %s", 195 inet_ntoa(sin.sin_addr)); 196 errno = oerrno; 197 perror(0); 198 hp->h_addr_list++; 199 memmove(&sin.sin_addr, hp->h_addr_list[0], 200 (size_t)hp->h_length); 201 (void)fprintf(stderr, "Trying %s...\n", 202 inet_ntoa(sin.sin_addr)); 203 continue; 204 } 205 (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno)); 206 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 207 return (-1); 208 } 209 lport--; 210 if (fd2p == 0) { 211 write(s, "", 1); 212 lport = 0; 213 } else { 214 char num[8]; 215 int s2 = rresvport(&lport), s3; 216 int len = sizeof(from); 217 218 if (s2 < 0) 219 goto bad; 220 listen(s2, 1); 221 (void)snprintf(num, sizeof(num), "%d", lport); 222 if (write(s, num, strlen(num) + 1) != strlen(num) + 1) { 223 warn("rcmd: write (setting up stderr)"); 224 (void)close(s2); 225 goto bad; 226 } 227 reads[0].fd = s; 228 reads[0].events = POLLIN; 229 reads[1].fd = s2; 230 reads[1].events = POLLIN; 231 errno = 0; 232 pollr = poll(reads, 2, INFTIM); 233 if (pollr < 1 || (reads[1].revents & POLLIN) == 0) { 234 if (errno != 0) 235 warn("poll: setting up stderr"); 236 else 237 warnx("poll: protocol failure in circuit setup"); 238 (void)close(s2); 239 goto bad; 240 } 241 s3 = accept(s2, (struct sockaddr *)(void *)&from, &len); 242 (void)close(s2); 243 if (s3 < 0) { 244 warn("rcmd: accept"); 245 lport = 0; 246 goto bad; 247 } 248 *fd2p = s3; 249 from.sin_port = ntohs(from.sin_port); 250 if (from.sin_family != AF_INET || 251 from.sin_port >= IPPORT_RESERVED || 252 from.sin_port < IPPORT_RESERVED / 2) { 253 warnx("rcmd: protocol failure in circuit setup."); 254 goto bad2; 255 } 256 } 257 258 (void)write(s, locuser, strlen(locuser)+1); 259 (void)write(s, remuser, strlen(remuser)+1); 260 (void)write(s, cmd, strlen(cmd)+1); 261 if (read(s, &c, 1) != 1) { 262 warn("%s", *ahost); 263 goto bad2; 264 } 265 if (c != 0) { 266 while (read(s, &c, 1) == 1) { 267 (void)write(STDERR_FILENO, &c, 1); 268 if (c == '\n') 269 break; 270 } 271 goto bad2; 272 } 273 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 274 return (s); 275 bad2: 276 if (lport) 277 (void)close(*fd2p); 278 bad: 279 (void)close(s); 280 (void)sigprocmask(SIG_SETMASK, &omask, NULL); 281 return (-1); 282 } 283 284 /* 285 * based on code written by Chris Siebenmann <cks@utcc.utoronto.ca> 286 */ 287 /* ARGSUSED */ 288 static int 289 rshrcmd(ahost, rport, locuser, remuser, cmd, fd2p, rshcmd) 290 char **ahost; 291 u_int32_t rport; 292 const char *locuser, *remuser, *cmd; 293 int *fd2p; 294 const char *rshcmd; 295 { 296 pid_t pid; 297 int sp[2], ep[2]; 298 char *p; 299 struct passwd *pw; 300 301 /* What rsh/shell to use. */ 302 if (rshcmd == NULL) 303 rshcmd = _PATH_BIN_RCMD; 304 305 /* locuser must exist on this host. */ 306 if ((pw = getpwnam(locuser)) == NULL) { 307 warnx("rshrcmd: unknown user: %s", locuser); 308 return(-1); 309 } 310 311 /* get a socketpair we'll use for stdin and stdout. */ 312 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sp) < 0) { 313 warn("rshrcmd: socketpair"); 314 return (-1); 315 } 316 /* we will use this for the fd2 pointer */ 317 if (fd2p) { 318 if (socketpair(AF_LOCAL, SOCK_STREAM, 0, ep) < 0) { 319 warn("rshrcmd: socketpair"); 320 return (-1); 321 } 322 *fd2p = ep[0]; 323 } 324 325 pid = fork(); 326 if (pid < 0) { 327 warn("rshrcmd: fork"); 328 return (-1); 329 } 330 if (pid == 0) { 331 /* 332 * child 333 * - we use sp[1] to be stdin/stdout, and close sp[0] 334 * - with fd2p, we use ep[1] for stderr, and close ep[0] 335 */ 336 (void)close(sp[0]); 337 if (dup2(sp[1], 0) < 0 || dup2(0, 1) < 0) { 338 warn("rshrcmd: dup2"); 339 _exit(1); 340 } 341 if (fd2p) { 342 if (dup2(ep[1], 2) < 0) { 343 warn("rshrcmd: dup2"); 344 _exit(1); 345 } 346 (void)close(ep[0]); 347 (void)close(ep[1]); 348 } else if (dup2(0, 2) < 0) { 349 warn("rshrcmd: dup2"); 350 _exit(1); 351 } 352 /* fork again to lose parent. */ 353 pid = fork(); 354 if (pid < 0) { 355 warn("rshrcmd: second fork"); 356 _exit(1); 357 } 358 if (pid > 0) 359 _exit(0); 360 361 /* Orphan. Become local user for rshprog. */ 362 if (setuid(pw->pw_uid)) { 363 warn("rshrcmd: setuid(%lu)", (u_long)pw->pw_uid); 364 _exit(1); 365 } 366 367 /* 368 * If we are rcmd'ing to "localhost" as the same user as we are, 369 * then avoid running remote shell for efficiency. 370 */ 371 if (strcmp(*ahost, "localhost") == 0 && 372 strcmp(locuser, remuser) == 0) { 373 if (pw->pw_shell[0] == '\0') 374 rshcmd = _PATH_BSHELL; 375 else 376 rshcmd = pw->pw_shell; 377 p = strrchr(rshcmd, '/'); 378 execlp(rshcmd, p ? p + 1 : rshcmd, "-c", cmd, NULL); 379 } else { 380 p = strrchr(rshcmd, '/'); 381 execlp(rshcmd, p ? p + 1 : rshcmd, *ahost, "-l", 382 remuser, cmd, NULL); 383 } 384 warn("rshrcmd: exec %s", rshcmd); 385 _exit(1); 386 } 387 /* Parent */ 388 (void)close(sp[1]); 389 if (fd2p) 390 (void)close(ep[1]); 391 392 (void)waitpid(pid, NULL, 0); 393 return (sp[0]); 394 } 395 396 int 397 rresvport(alport) 398 int *alport; 399 { 400 struct sockaddr_in sin; 401 int s; 402 403 #ifdef BSD4_4 404 sin.sin_len = sizeof(struct sockaddr_in); 405 #endif 406 sin.sin_family = AF_INET; 407 sin.sin_addr.s_addr = INADDR_ANY; 408 s = socket(AF_INET, SOCK_STREAM, 0); 409 if (s < 0) 410 return (-1); 411 #ifndef BSD4_4 412 for (;;) { 413 sin.sin_port = htons((u_short)*alport); 414 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 415 return (s); 416 if (errno != EADDRINUSE) { 417 (void)close(s); 418 return (-1); 419 } 420 (*alport)--; 421 if (*alport == IPPORT_RESERVED/2) { 422 (void)close(s); 423 errno = EAGAIN; /* close */ 424 return (-1); 425 } 426 } 427 #else 428 sin.sin_port = 0; 429 if (bindresvport(s, &sin) < 0) { 430 int sverr = errno; 431 432 (void)close(s); 433 errno = sverr; 434 return (-1); 435 } 436 *alport = (int)ntohs(sin.sin_port); 437 return (s); 438 #endif 439 } 440 441 int __check_rhosts_file = 1; 442 char *__rcmd_errstr; 443 444 int 445 ruserok(rhost, superuser, ruser, luser) 446 const char *rhost, *ruser, *luser; 447 int superuser; 448 { 449 struct hostent *hp; 450 char **ap; 451 int i; 452 #define MAXADDRS 35 453 u_int32_t addrs[MAXADDRS + 1]; 454 455 if ((hp = gethostbyname(rhost)) == NULL) 456 return (-1); 457 for (i = 0, ap = hp->h_addr_list; *ap && i < MAXADDRS; ++ap, ++i) 458 memmove(&addrs[i], *ap, sizeof(addrs[i])); 459 addrs[i] = 0; 460 461 for (i = 0; i < MAXADDRS && addrs[i]; i++) 462 if (iruserok(addrs[i], superuser, ruser, luser) == 0) 463 return (0); 464 return (-1); 465 } 466 467 /* 468 * New .rhosts strategy: We are passed an ip address. We spin through 469 * hosts.equiv and .rhosts looking for a match. When the .rhosts only 470 * has ip addresses, we don't have to trust a nameserver. When it 471 * contains hostnames, we spin through the list of addresses the nameserver 472 * gives us and look for a match. 473 * 474 * Returns 0 if ok, -1 if not ok. 475 */ 476 int 477 iruserok(raddr, superuser, ruser, luser) 478 u_int32_t raddr; 479 int superuser; 480 const char *ruser, *luser; 481 { 482 register char *cp; 483 struct stat sbuf; 484 struct passwd *pwd; 485 FILE *hostf; 486 uid_t uid; 487 gid_t gid; 488 int first; 489 char pbuf[MAXPATHLEN]; 490 491 first = 1; 492 hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); 493 again: 494 if (hostf) { 495 if (__ivaliduser(hostf, raddr, luser, ruser) == 0) { 496 (void)fclose(hostf); 497 return (0); 498 } 499 (void)fclose(hostf); 500 } 501 if (first == 1 && (__check_rhosts_file || superuser)) { 502 first = 0; 503 if ((pwd = getpwnam(luser)) == NULL) 504 return (-1); 505 (void)strncpy(pbuf, pwd->pw_dir, sizeof(pbuf) - 1); 506 (void)strncat(pbuf, "/.rhosts", sizeof(pbuf) - strlen(pbuf) - 1); 507 508 /* 509 * Change effective uid while opening .rhosts. If root and 510 * reading an NFS mounted file system, can't read files that 511 * are protected read/write owner only. 512 */ 513 uid = geteuid(); 514 gid = getegid(); 515 (void)setegid(pwd->pw_gid); 516 initgroups(pwd->pw_name, pwd->pw_gid); 517 (void)seteuid(pwd->pw_uid); 518 hostf = fopen(pbuf, "r"); 519 (void)seteuid(uid); 520 (void)setegid(gid); 521 522 if (hostf == NULL) 523 return (-1); 524 /* 525 * If not a regular file, or is owned by someone other than 526 * user or root or if writeable by anyone but the owner, quit. 527 */ 528 cp = NULL; 529 if (lstat(pbuf, &sbuf) < 0) 530 cp = ".rhosts lstat failed"; 531 else if (!S_ISREG(sbuf.st_mode)) 532 cp = ".rhosts not regular file"; 533 else if (fstat(fileno(hostf), &sbuf) < 0) 534 cp = ".rhosts fstat failed"; 535 else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) 536 cp = "bad .rhosts owner"; 537 else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) 538 cp = ".rhosts writeable by other than owner"; 539 /* If there were any problems, quit. */ 540 if (cp) { 541 __rcmd_errstr = cp; 542 (void)fclose(hostf); 543 return (-1); 544 } 545 goto again; 546 } 547 return (-1); 548 } 549 550 /* 551 * XXX 552 * Don't make static, used by lpd(8). 553 * 554 * Returns 0 if ok, -1 if not ok. 555 */ 556 int 557 __ivaliduser(hostf, raddr, luser, ruser) 558 FILE *hostf; 559 u_int32_t raddr; 560 const char *luser, *ruser; 561 { 562 register char *user, *p; 563 int ch; 564 char buf[MAXHOSTNAMELEN + 128]; /* host + login */ 565 const char *auser, *ahost; 566 int hostok, userok; 567 char *rhost = NULL; 568 int firsttime = 1; 569 char domain[MAXHOSTNAMELEN]; 570 571 getdomainname(domain, sizeof(domain)); 572 573 while (fgets(buf, sizeof(buf), hostf)) { 574 p = buf; 575 /* Skip lines that are too long. */ 576 if (strchr(p, '\n') == NULL) { 577 while ((ch = getc(hostf)) != '\n' && ch != EOF) 578 ; 579 continue; 580 } 581 while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { 582 *p = isupper((unsigned char)*p) ? tolower(*p) : *p; 583 p++; 584 } 585 if (*p == ' ' || *p == '\t') { 586 *p++ = '\0'; 587 while (*p == ' ' || *p == '\t') 588 p++; 589 user = p; 590 while (*p != '\n' && *p != ' ' && 591 *p != '\t' && *p != '\0') 592 p++; 593 } else 594 user = p; 595 *p = '\0'; 596 597 if (p == buf) 598 continue; 599 600 auser = *user ? user : luser; 601 ahost = buf; 602 603 if (ahost[0] == '+') 604 switch (ahost[1]) { 605 case '\0': 606 hostok = 1; 607 break; 608 609 case '@': 610 if (firsttime) { 611 rhost = __gethostloop(raddr); 612 firsttime = 0; 613 } 614 if (rhost) 615 hostok = innetgr(&ahost[2], rhost, 616 NULL, domain); 617 else 618 hostok = 0; 619 break; 620 621 default: 622 hostok = __icheckhost(raddr, &ahost[1]); 623 break; 624 } 625 else if (ahost[0] == '-') 626 switch (ahost[1]) { 627 case '\0': 628 hostok = -1; 629 break; 630 631 case '@': 632 if (firsttime) { 633 rhost = __gethostloop(raddr); 634 firsttime = 0; 635 } 636 if (rhost) 637 hostok = -innetgr(&ahost[2], rhost, 638 NULL, domain); 639 else 640 hostok = 0; 641 break; 642 643 default: 644 hostok = -__icheckhost(raddr, &ahost[1]); 645 break; 646 } 647 else 648 hostok = __icheckhost(raddr, ahost); 649 650 651 if (auser[0] == '+') 652 switch (auser[1]) { 653 case '\0': 654 userok = 1; 655 break; 656 657 case '@': 658 userok = innetgr(&auser[2], NULL, ruser, 659 domain); 660 break; 661 662 default: 663 userok = strcmp(ruser, &auser[1]) == 0; 664 break; 665 } 666 else if (auser[0] == '-') 667 switch (auser[1]) { 668 case '\0': 669 userok = -1; 670 break; 671 672 case '@': 673 userok = -innetgr(&auser[2], NULL, ruser, 674 domain); 675 break; 676 677 default: 678 userok = 679 -(strcmp(ruser, &auser[1]) == 0 ? 1 : 0); 680 break; 681 } 682 else 683 userok = strcmp(ruser, auser) == 0; 684 685 /* Check if one component did not match */ 686 if (hostok == 0 || userok == 0) 687 continue; 688 689 /* Check if we got a forbidden pair */ 690 if (userok == -1 || hostok == -1) 691 return -1; 692 693 /* Check if we got a valid pair */ 694 if (hostok == 1 && userok == 1) 695 return 0; 696 } 697 return -1; 698 } 699 700 /* 701 * Returns "true" if match, 0 if no match. 702 */ 703 static int 704 __icheckhost(raddr, lhost) 705 u_int32_t raddr; 706 const char *lhost; 707 { 708 struct hostent *hp; 709 struct in_addr laddr; 710 char **pp; 711 712 /* Try for raw ip address first. */ 713 if (isdigit((unsigned char)*lhost) && inet_aton(lhost, &laddr) != 0) 714 return (raddr == laddr.s_addr); 715 716 /* Better be a hostname. */ 717 if ((hp = gethostbyname(lhost)) == NULL) 718 return (0); 719 720 /* Spin through ip addresses. */ 721 for (pp = hp->h_addr_list; *pp; ++pp) 722 if (!memcmp(&raddr, *pp, sizeof(u_int32_t))) 723 return (1); 724 725 /* No match. */ 726 return (0); 727 } 728 729 /* 730 * Return the hostname associated with the supplied address. 731 * Do a reverse lookup as well for security. If a loop cannot 732 * be found, pack the result of inet_ntoa() into the string. 733 */ 734 static char * 735 __gethostloop(raddr) 736 u_int32_t raddr; 737 { 738 static char remotehost[MAXHOSTNAMELEN]; 739 struct hostent *hp; 740 struct in_addr in; 741 742 hp = gethostbyaddr((char *)(void *)&raddr, sizeof(raddr), AF_INET); 743 if (hp == NULL) 744 return (NULL); 745 746 /* 747 * Look up the name and check that the supplied 748 * address is in the list 749 */ 750 strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 751 remotehost[sizeof(remotehost) - 1] = '\0'; 752 hp = gethostbyname(remotehost); 753 if (hp == NULL) 754 return (NULL); 755 756 for (; hp->h_addr_list[0] != NULL; hp->h_addr_list++) 757 if (!memcmp(hp->h_addr_list[0], &raddr, sizeof(raddr))) 758 return (remotehost); 759 760 /* 761 * either the DNS adminstrator has made a configuration 762 * mistake, or someone has attempted to spoof us 763 */ 764 in.s_addr = raddr; 765 syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s", 766 inet_ntoa(in), hp->h_name); 767 return (NULL); 768 } 769