rcmd.c revision 9978
11573Srgrimes/* 21573Srgrimes * Copyright (c) 1983, 1993, 1994 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 131573Srgrimes * 3. All advertising materials mentioning features or use of this software 141573Srgrimes * must display the following acknowledgement: 151573Srgrimes * This product includes software developed by the University of 161573Srgrimes * California, Berkeley and its contributors. 171573Srgrimes * 4. Neither the name of the University nor the names of its contributors 181573Srgrimes * may be used to endorse or promote products derived from this software 191573Srgrimes * without specific prior written permission. 201573Srgrimes * 211573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311573Srgrimes * SUCH DAMAGE. 321573Srgrimes */ 331573Srgrimes 341573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 351573Srgrimesstatic char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; 361573Srgrimes#endif /* LIBC_SCCS and not lint */ 371573Srgrimes 381573Srgrimes#include <sys/param.h> 391573Srgrimes#include <sys/socket.h> 401573Srgrimes#include <sys/stat.h> 411573Srgrimes 421573Srgrimes#include <netinet/in.h> 431573Srgrimes#include <arpa/inet.h> 441573Srgrimes 451573Srgrimes#include <signal.h> 461573Srgrimes#include <fcntl.h> 471573Srgrimes#include <netdb.h> 481573Srgrimes#include <unistd.h> 491573Srgrimes#include <pwd.h> 501573Srgrimes#include <errno.h> 511573Srgrimes#include <stdio.h> 521573Srgrimes#include <ctype.h> 531573Srgrimes#include <string.h> 549978Swpaul#ifdef YP 559978Swpaul#include <rpc/rpc.h> 569978Swpaul#include <rpcsvc/yp_prot.h> 579978Swpaul#include <rpcsvc/ypclnt.h> 589978Swpaul#endif 591573Srgrimes 602592Scsgr#define max(a, b) ((a > b) ? a : b) 612592Scsgr 621573Srgrimesint __ivaliduser __P((FILE *, u_long, const char *, const char *)); 631573Srgrimesstatic int __icheckhost __P((u_long, char *)); 641573Srgrimes 651573Srgrimesint 661573Srgrimesrcmd(ahost, rport, locuser, remuser, cmd, fd2p) 671573Srgrimes char **ahost; 681573Srgrimes u_short rport; 691573Srgrimes const char *locuser, *remuser, *cmd; 701573Srgrimes int *fd2p; 711573Srgrimes{ 721573Srgrimes struct hostent *hp; 731573Srgrimes struct sockaddr_in sin, from; 741573Srgrimes fd_set reads; 751573Srgrimes long oldmask; 761573Srgrimes pid_t pid; 771573Srgrimes int s, lport, timo; 781573Srgrimes char c; 791573Srgrimes 801573Srgrimes pid = getpid(); 811573Srgrimes hp = gethostbyname(*ahost); 821573Srgrimes if (hp == NULL) { 831573Srgrimes herror(*ahost); 841573Srgrimes return (-1); 851573Srgrimes } 861573Srgrimes *ahost = hp->h_name; 871573Srgrimes oldmask = sigblock(sigmask(SIGURG)); 881573Srgrimes for (timo = 1, lport = IPPORT_RESERVED - 1;;) { 891573Srgrimes s = rresvport(&lport); 901573Srgrimes if (s < 0) { 911573Srgrimes if (errno == EAGAIN) 921573Srgrimes (void)fprintf(stderr, 931573Srgrimes "rcmd: socket: All ports in use\n"); 941573Srgrimes else 951573Srgrimes (void)fprintf(stderr, "rcmd: socket: %s\n", 961573Srgrimes strerror(errno)); 971573Srgrimes sigsetmask(oldmask); 981573Srgrimes return (-1); 991573Srgrimes } 1001573Srgrimes fcntl(s, F_SETOWN, pid); 1011573Srgrimes sin.sin_family = hp->h_addrtype; 1021573Srgrimes bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); 1031573Srgrimes sin.sin_port = rport; 1041573Srgrimes if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 1051573Srgrimes break; 1061573Srgrimes (void)close(s); 1071573Srgrimes if (errno == EADDRINUSE) { 1081573Srgrimes lport--; 1091573Srgrimes continue; 1101573Srgrimes } 1111573Srgrimes if (errno == ECONNREFUSED && timo <= 16) { 1121573Srgrimes (void)sleep(timo); 1131573Srgrimes timo *= 2; 1141573Srgrimes continue; 1151573Srgrimes } 1161573Srgrimes if (hp->h_addr_list[1] != NULL) { 1171573Srgrimes int oerrno = errno; 1181573Srgrimes 1191573Srgrimes (void)fprintf(stderr, "connect to address %s: ", 1201573Srgrimes inet_ntoa(sin.sin_addr)); 1211573Srgrimes errno = oerrno; 1221573Srgrimes perror(0); 1231573Srgrimes hp->h_addr_list++; 1241573Srgrimes bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); 1251573Srgrimes (void)fprintf(stderr, "Trying %s...\n", 1261573Srgrimes inet_ntoa(sin.sin_addr)); 1271573Srgrimes continue; 1281573Srgrimes } 1291573Srgrimes (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno)); 1301573Srgrimes sigsetmask(oldmask); 1311573Srgrimes return (-1); 1321573Srgrimes } 1331573Srgrimes lport--; 1341573Srgrimes if (fd2p == 0) { 1351573Srgrimes write(s, "", 1); 1361573Srgrimes lport = 0; 1371573Srgrimes } else { 1381573Srgrimes char num[8]; 1391573Srgrimes int s2 = rresvport(&lport), s3; 1401573Srgrimes int len = sizeof(from); 1412592Scsgr int nfds; 1421573Srgrimes 1431573Srgrimes if (s2 < 0) 1441573Srgrimes goto bad; 1451573Srgrimes listen(s2, 1); 1461573Srgrimes (void)snprintf(num, sizeof(num), "%d", lport); 1471573Srgrimes if (write(s, num, strlen(num)+1) != strlen(num)+1) { 1481573Srgrimes (void)fprintf(stderr, 1491573Srgrimes "rcmd: write (setting up stderr): %s\n", 1501573Srgrimes strerror(errno)); 1511573Srgrimes (void)close(s2); 1521573Srgrimes goto bad; 1531573Srgrimes } 1542592Scsgr nfds = max(s, s2)+1; 1552592Scsgr if(nfds > FD_SETSIZE) { 1562592Scsgr fprintf(stderr, "rcmd: too many files\n"); 1572592Scsgr (void)close(s2); 1582592Scsgr goto bad; 1592592Scsgr } 1601573Srgrimes FD_ZERO(&reads); 1611573Srgrimes FD_SET(s, &reads); 1621573Srgrimes FD_SET(s2, &reads); 1631573Srgrimes errno = 0; 1642592Scsgr if (select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){ 1651573Srgrimes if (errno != 0) 1661573Srgrimes (void)fprintf(stderr, 1671573Srgrimes "rcmd: select (setting up stderr): %s\n", 1681573Srgrimes strerror(errno)); 1691573Srgrimes else 1701573Srgrimes (void)fprintf(stderr, 1711573Srgrimes "select: protocol failure in circuit setup\n"); 1721573Srgrimes (void)close(s2); 1731573Srgrimes goto bad; 1741573Srgrimes } 1751573Srgrimes s3 = accept(s2, (struct sockaddr *)&from, &len); 1761573Srgrimes (void)close(s2); 1771573Srgrimes if (s3 < 0) { 1781573Srgrimes (void)fprintf(stderr, 1791573Srgrimes "rcmd: accept: %s\n", strerror(errno)); 1801573Srgrimes lport = 0; 1811573Srgrimes goto bad; 1821573Srgrimes } 1831573Srgrimes *fd2p = s3; 1841573Srgrimes from.sin_port = ntohs((u_short)from.sin_port); 1851573Srgrimes if (from.sin_family != AF_INET || 1861573Srgrimes from.sin_port >= IPPORT_RESERVED || 1871573Srgrimes from.sin_port < IPPORT_RESERVED / 2) { 1881573Srgrimes (void)fprintf(stderr, 1891573Srgrimes "socket: protocol failure in circuit setup.\n"); 1901573Srgrimes goto bad2; 1911573Srgrimes } 1921573Srgrimes } 1931573Srgrimes (void)write(s, locuser, strlen(locuser)+1); 1941573Srgrimes (void)write(s, remuser, strlen(remuser)+1); 1951573Srgrimes (void)write(s, cmd, strlen(cmd)+1); 1961573Srgrimes if (read(s, &c, 1) != 1) { 1971573Srgrimes (void)fprintf(stderr, 1981573Srgrimes "rcmd: %s: %s\n", *ahost, strerror(errno)); 1991573Srgrimes goto bad2; 2001573Srgrimes } 2011573Srgrimes if (c != 0) { 2021573Srgrimes while (read(s, &c, 1) == 1) { 2031573Srgrimes (void)write(STDERR_FILENO, &c, 1); 2041573Srgrimes if (c == '\n') 2051573Srgrimes break; 2061573Srgrimes } 2071573Srgrimes goto bad2; 2081573Srgrimes } 2091573Srgrimes sigsetmask(oldmask); 2101573Srgrimes return (s); 2111573Srgrimesbad2: 2121573Srgrimes if (lport) 2131573Srgrimes (void)close(*fd2p); 2141573Srgrimesbad: 2151573Srgrimes (void)close(s); 2161573Srgrimes sigsetmask(oldmask); 2171573Srgrimes return (-1); 2181573Srgrimes} 2191573Srgrimes 2201573Srgrimesint 2211573Srgrimesrresvport(alport) 2221573Srgrimes int *alport; 2231573Srgrimes{ 2241573Srgrimes struct sockaddr_in sin; 2251573Srgrimes int s; 2261573Srgrimes 2271573Srgrimes sin.sin_family = AF_INET; 2281573Srgrimes sin.sin_addr.s_addr = INADDR_ANY; 2291573Srgrimes s = socket(AF_INET, SOCK_STREAM, 0); 2301573Srgrimes if (s < 0) 2311573Srgrimes return (-1); 2321573Srgrimes for (;;) { 2331573Srgrimes sin.sin_port = htons((u_short)*alport); 2341573Srgrimes if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 2351573Srgrimes return (s); 2361573Srgrimes if (errno != EADDRINUSE) { 2371573Srgrimes (void)close(s); 2381573Srgrimes return (-1); 2391573Srgrimes } 2401573Srgrimes (*alport)--; 2411573Srgrimes if (*alport == IPPORT_RESERVED/2) { 2421573Srgrimes (void)close(s); 2431573Srgrimes errno = EAGAIN; /* close */ 2441573Srgrimes return (-1); 2451573Srgrimes } 2461573Srgrimes } 2471573Srgrimes} 2481573Srgrimes 2491573Srgrimesint __check_rhosts_file = 1; 2501573Srgrimeschar *__rcmd_errstr; 2511573Srgrimes 2521573Srgrimesint 2531573Srgrimesruserok(rhost, superuser, ruser, luser) 2541573Srgrimes const char *rhost, *ruser, *luser; 2551573Srgrimes int superuser; 2561573Srgrimes{ 2571573Srgrimes struct hostent *hp; 2581573Srgrimes u_long addr; 2591573Srgrimes char **ap; 2601573Srgrimes 2611573Srgrimes if ((hp = gethostbyname(rhost)) == NULL) 2621573Srgrimes return (-1); 2631573Srgrimes for (ap = hp->h_addr_list; *ap; ++ap) { 2641573Srgrimes bcopy(*ap, &addr, sizeof(addr)); 2651573Srgrimes if (iruserok(addr, superuser, ruser, luser) == 0) 2661573Srgrimes return (0); 2671573Srgrimes } 2681573Srgrimes return (-1); 2691573Srgrimes} 2701573Srgrimes 2711573Srgrimes/* 2721573Srgrimes * New .rhosts strategy: We are passed an ip address. We spin through 2731573Srgrimes * hosts.equiv and .rhosts looking for a match. When the .rhosts only 2741573Srgrimes * has ip addresses, we don't have to trust a nameserver. When it 2751573Srgrimes * contains hostnames, we spin through the list of addresses the nameserver 2761573Srgrimes * gives us and look for a match. 2771573Srgrimes * 2781573Srgrimes * Returns 0 if ok, -1 if not ok. 2791573Srgrimes */ 2801573Srgrimesint 2811573Srgrimesiruserok(raddr, superuser, ruser, luser) 2821573Srgrimes u_long raddr; 2831573Srgrimes int superuser; 2841573Srgrimes const char *ruser, *luser; 2851573Srgrimes{ 2861573Srgrimes register char *cp; 2871573Srgrimes struct stat sbuf; 2881573Srgrimes struct passwd *pwd; 2891573Srgrimes FILE *hostf; 2901573Srgrimes uid_t uid; 2911573Srgrimes int first; 2921573Srgrimes char pbuf[MAXPATHLEN]; 2931573Srgrimes 2941573Srgrimes first = 1; 2951573Srgrimes hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); 2961573Srgrimesagain: 2971573Srgrimes if (hostf) { 2981573Srgrimes if (__ivaliduser(hostf, raddr, luser, ruser) == 0) { 2991573Srgrimes (void)fclose(hostf); 3001573Srgrimes return (0); 3011573Srgrimes } 3021573Srgrimes (void)fclose(hostf); 3031573Srgrimes } 3041573Srgrimes if (first == 1 && (__check_rhosts_file || superuser)) { 3051573Srgrimes first = 0; 3061573Srgrimes if ((pwd = getpwnam(luser)) == NULL) 3071573Srgrimes return (-1); 3081573Srgrimes (void)strcpy(pbuf, pwd->pw_dir); 3091573Srgrimes (void)strcat(pbuf, "/.rhosts"); 3101573Srgrimes 3111573Srgrimes /* 3121573Srgrimes * Change effective uid while opening .rhosts. If root and 3131573Srgrimes * reading an NFS mounted file system, can't read files that 3141573Srgrimes * are protected read/write owner only. 3151573Srgrimes */ 3161573Srgrimes uid = geteuid(); 3171573Srgrimes (void)seteuid(pwd->pw_uid); 3181573Srgrimes hostf = fopen(pbuf, "r"); 3191573Srgrimes (void)seteuid(uid); 3201573Srgrimes 3211573Srgrimes if (hostf == NULL) 3221573Srgrimes return (-1); 3231573Srgrimes /* 3241573Srgrimes * If not a regular file, or is owned by someone other than 3251573Srgrimes * user or root or if writeable by anyone but the owner, quit. 3261573Srgrimes */ 3271573Srgrimes cp = NULL; 3281573Srgrimes if (lstat(pbuf, &sbuf) < 0) 3291573Srgrimes cp = ".rhosts lstat failed"; 3301573Srgrimes else if (!S_ISREG(sbuf.st_mode)) 3311573Srgrimes cp = ".rhosts not regular file"; 3321573Srgrimes else if (fstat(fileno(hostf), &sbuf) < 0) 3331573Srgrimes cp = ".rhosts fstat failed"; 3341573Srgrimes else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) 3351573Srgrimes cp = "bad .rhosts owner"; 3361573Srgrimes else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) 3371573Srgrimes cp = ".rhosts writeable by other than owner"; 3381573Srgrimes /* If there were any problems, quit. */ 3391573Srgrimes if (cp) { 3401573Srgrimes __rcmd_errstr = cp; 3411573Srgrimes (void)fclose(hostf); 3421573Srgrimes return (-1); 3431573Srgrimes } 3441573Srgrimes goto again; 3451573Srgrimes } 3461573Srgrimes return (-1); 3471573Srgrimes} 3481573Srgrimes 3491573Srgrimes/* 3501573Srgrimes * XXX 3511573Srgrimes * Don't make static, used by lpd(8). 3521573Srgrimes * 3531573Srgrimes * Returns 0 if ok, -1 if not ok. 3541573Srgrimes */ 3551573Srgrimesint 3561573Srgrimes__ivaliduser(hostf, raddr, luser, ruser) 3571573Srgrimes FILE *hostf; 3581573Srgrimes u_long raddr; 3591573Srgrimes const char *luser, *ruser; 3601573Srgrimes{ 3611573Srgrimes register char *user, *p; 3621573Srgrimes int ch; 3631573Srgrimes char buf[MAXHOSTNAMELEN + 128]; /* host + login */ 3647183Swpaul struct hostent *hp; 3657183Swpaul /* Presumed guilty until proven innocent. */ 3667183Swpaul int userok = 0, hostok = 0; 3679978Swpaul#ifdef YP 3689978Swpaul char *ypdomain; 3691573Srgrimes 3709978Swpaul if (yp_get_default_domain(&ypdomain)) 3719978Swpaul ypdomain = NULL; 3729978Swpaul#else 3739978Swpaul#define ypdomain NULL 3749978Swpaul#endif 3757183Swpaul /* We need to get the damn hostname back for netgroup matching. */ 3767183Swpaul if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long), 3777183Swpaul AF_INET)) == NULL) 3787183Swpaul return (-1); 3797183Swpaul 3801573Srgrimes while (fgets(buf, sizeof(buf), hostf)) { 3811573Srgrimes p = buf; 3821573Srgrimes /* Skip lines that are too long. */ 3831573Srgrimes if (strchr(p, '\n') == NULL) { 3841573Srgrimes while ((ch = getc(hostf)) != '\n' && ch != EOF); 3851573Srgrimes continue; 3861573Srgrimes } 3879552Speter if (*p == '\n' || *p == '#') { 3889552Speter /* comment... */ 3899552Speter continue; 3909552Speter } 3911573Srgrimes while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { 3921573Srgrimes *p = isupper(*p) ? tolower(*p) : *p; 3931573Srgrimes p++; 3941573Srgrimes } 3951573Srgrimes if (*p == ' ' || *p == '\t') { 3961573Srgrimes *p++ = '\0'; 3971573Srgrimes while (*p == ' ' || *p == '\t') 3981573Srgrimes p++; 3991573Srgrimes user = p; 4001573Srgrimes while (*p != '\n' && *p != ' ' && 4011573Srgrimes *p != '\t' && *p != '\0') 4021573Srgrimes p++; 4031573Srgrimes } else 4041573Srgrimes user = p; 4051573Srgrimes *p = '\0'; 4067183Swpaul /* 4077183Swpaul * Do +/- and +@/-@ checking. This looks really nasty, 4087183Swpaul * but it matches SunOS's behavior so far as I can tell. 4097183Swpaul */ 4107183Swpaul switch(buf[0]) { 4117183Swpaul case '+': 4127183Swpaul if (!buf[1]) { /* '+' matches all hosts */ 4137183Swpaul hostok = 1; 4147183Swpaul break; 4157183Swpaul } 4167183Swpaul if (buf[1] == '@') /* match a host by netgroup */ 4177183Swpaul hostok = innetgr((char *)&buf[2], hp->h_name, 4189978Swpaul NULL, ypdomain); 4197183Swpaul else /* match a host by addr */ 4207183Swpaul hostok = __icheckhost(raddr,(char *)&buf[1]); 4217183Swpaul break; 4227183Swpaul case '-': /* reject '-' hosts and all their users */ 4237183Swpaul if (buf[1] == '@') { 4247183Swpaul if (innetgr((char *)&buf[2], 4259978Swpaul hp->h_name, NULL, ypdomain)) 4267183Swpaul return(-1); 4277183Swpaul } else { 4287183Swpaul if (__icheckhost(raddr,(char *)&buf[1])) 4297183Swpaul return(-1); 4307183Swpaul } 4317183Swpaul break; 4327183Swpaul default: /* if no '+' or '-', do a simple match */ 4337183Swpaul hostok = __icheckhost(raddr, buf); 4347183Swpaul break; 4351573Srgrimes } 4367183Swpaul switch(*user) { 4377183Swpaul case '+': 4387183Swpaul if (!*(user+1)) { /* '+' matches all users */ 4397183Swpaul userok = 1; 4407183Swpaul break; 4417183Swpaul } 4427183Swpaul if (*(user+1) == '@') /* match a user by netgroup */ 4439978Swpaul userok = innetgr(user+2, NULL, ruser, ypdomain); 4447183Swpaul else /* match a user by direct specification */ 4457183Swpaul userok = !(strcmp(ruser, user+1)); 4467183Swpaul break; 4477183Swpaul case '-': /* if we matched a hostname, */ 4487183Swpaul if (hostok) { /* check for user field rejections */ 4497183Swpaul if (!*(user+1)) 4507183Swpaul return(-1); 4517183Swpaul if (*(user+1) == '@') { 4527183Swpaul if (innetgr(user+2, NULL, 4539978Swpaul ruser, ypdomain)) 4547183Swpaul return(-1); 4557183Swpaul } else { 4567183Swpaul if (!strcmp(ruser, user+1)) 4577183Swpaul return(-1); 4587183Swpaul } 4597183Swpaul } 4607183Swpaul break; 4617183Swpaul default: /* no rejections: try to match the user */ 4627183Swpaul if (hostok) 4637183Swpaul userok = !(strcmp(ruser,*user ? user : luser)); 4647183Swpaul break; 4657183Swpaul } 4667183Swpaul if (hostok && userok) 4677183Swpaul return(0); 4681573Srgrimes } 4691573Srgrimes return (-1); 4701573Srgrimes} 4711573Srgrimes 4721573Srgrimes/* 4731573Srgrimes * Returns "true" if match, 0 if no match. 4741573Srgrimes */ 4751573Srgrimesstatic int 4761573Srgrimes__icheckhost(raddr, lhost) 4771573Srgrimes u_long raddr; 4781573Srgrimes register char *lhost; 4791573Srgrimes{ 4801573Srgrimes register struct hostent *hp; 4811573Srgrimes register u_long laddr; 4821573Srgrimes register char **pp; 4831573Srgrimes 4841573Srgrimes /* Try for raw ip address first. */ 4851573Srgrimes if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1) 4861573Srgrimes return (raddr == laddr); 4871573Srgrimes 4881573Srgrimes /* Better be a hostname. */ 4891573Srgrimes if ((hp = gethostbyname(lhost)) == NULL) 4901573Srgrimes return (0); 4911573Srgrimes 4921573Srgrimes /* Spin through ip addresses. */ 4931573Srgrimes for (pp = hp->h_addr_list; *pp; ++pp) 4941573Srgrimes if (!bcmp(&raddr, *pp, sizeof(u_long))) 4951573Srgrimes return (1); 4961573Srgrimes 4971573Srgrimes /* No match. */ 4981573Srgrimes return (0); 4991573Srgrimes} 500