rcmd.c revision 56590
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. 3252859Sache * 3352859Sache * $FreeBSD: head/lib/libc/net/rcmd.c 56590 2000-01-25 14:52:10Z shin $ 341573Srgrimes */ 351573Srgrimes 361573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 371573Srgrimesstatic char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; 381573Srgrimes#endif /* LIBC_SCCS and not lint */ 391573Srgrimes 401573Srgrimes#include <sys/param.h> 411573Srgrimes#include <sys/socket.h> 421573Srgrimes#include <sys/stat.h> 431573Srgrimes 441573Srgrimes#include <netinet/in.h> 451573Srgrimes#include <arpa/inet.h> 461573Srgrimes 471573Srgrimes#include <signal.h> 481573Srgrimes#include <fcntl.h> 491573Srgrimes#include <netdb.h> 501573Srgrimes#include <unistd.h> 511573Srgrimes#include <pwd.h> 521573Srgrimes#include <errno.h> 531573Srgrimes#include <stdio.h> 541573Srgrimes#include <ctype.h> 551573Srgrimes#include <string.h> 569978Swpaul#ifdef YP 579978Swpaul#include <rpc/rpc.h> 589978Swpaul#include <rpcsvc/yp_prot.h> 599978Swpaul#include <rpcsvc/ypclnt.h> 609978Swpaul#endif 611573Srgrimes 6255918Sshin/* wrapper for KAME-special getnameinfo() */ 6355918Sshin#ifndef NI_WITHSCOPEID 6455918Sshin#define NI_WITHSCOPEID 0 6555918Sshin#endif 6655918Sshin 6717141Sjkhextern int innetgr __P(( const char *, const char *, const char *, const char * )); 6817141Sjkh 692592Scsgr#define max(a, b) ((a > b) ? a : b) 702592Scsgr 7139979Sdfrint __ivaliduser __P((FILE *, u_int32_t, const char *, const char *)); 7255918Sshinstatic int __icheckhost __P((void *, char *, int, int)); 731573Srgrimes 7455918Sshinchar paddr[INET6_ADDRSTRLEN]; 7555918Sshin 761573Srgrimesint 771573Srgrimesrcmd(ahost, rport, locuser, remuser, cmd, fd2p) 781573Srgrimes char **ahost; 791573Srgrimes u_short rport; 801573Srgrimes const char *locuser, *remuser, *cmd; 811573Srgrimes int *fd2p; 821573Srgrimes{ 8356590Sshin return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); 8456590Sshin} 8556590Sshin 8656590Sshinint 8756590Sshinrcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af) 8856590Sshin char **ahost; 8956590Sshin u_short rport; 9056590Sshin const char *locuser, *remuser, *cmd; 9156590Sshin int *fd2p; 9256590Sshin int af; 9356590Sshin{ 9455918Sshin struct addrinfo hints, *res, *ai; 9555918Sshin struct sockaddr_storage from; 961573Srgrimes fd_set reads; 971573Srgrimes long oldmask; 981573Srgrimes pid_t pid; 9955918Sshin int s, aport, lport, timo, error; 1001573Srgrimes char c; 10155918Sshin int refused; 10255918Sshin char num[8]; 1031573Srgrimes 1041573Srgrimes pid = getpid(); 10555918Sshin 10655918Sshin memset(&hints, 0, sizeof(hints)); 10755918Sshin hints.ai_flags = AI_CANONNAME; 10856590Sshin hints.ai_family = af; 10955918Sshin hints.ai_socktype = SOCK_STREAM; 11055918Sshin hints.ai_protocol = 0; 11155918Sshin (void)snprintf(num, sizeof(num), "%d", ntohs(rport)); 11255918Sshin error = getaddrinfo(*ahost, num, &hints, &res); 11355918Sshin if (error) { 11455918Sshin fprintf(stderr, "rcmd: getaddrinfo: %s\n", 11555918Sshin gai_strerror(error)); 11655918Sshin if (error == EAI_SYSTEM) 11755918Sshin fprintf(stderr, "rcmd: getaddrinfo: %s\n", 11855918Sshin strerror(errno)); 1191573Srgrimes return (-1); 1201573Srgrimes } 12155918Sshin if (res->ai_canonname) 12255918Sshin *ahost = res->ai_canonname; 12355918Sshin ai = res; 12455918Sshin refused = 0; 1251573Srgrimes oldmask = sigblock(sigmask(SIGURG)); 1261573Srgrimes for (timo = 1, lport = IPPORT_RESERVED - 1;;) { 12755918Sshin s = rresvport_af(&lport, ai->ai_family); 1281573Srgrimes if (s < 0) { 1291573Srgrimes if (errno == EAGAIN) 1301573Srgrimes (void)fprintf(stderr, 1311573Srgrimes "rcmd: socket: All ports in use\n"); 1321573Srgrimes else 1331573Srgrimes (void)fprintf(stderr, "rcmd: socket: %s\n", 1341573Srgrimes strerror(errno)); 1351573Srgrimes sigsetmask(oldmask); 13655918Sshin freeaddrinfo(res); 1371573Srgrimes return (-1); 1381573Srgrimes } 13955837Sjasone _libc_fcntl(s, F_SETOWN, pid); 14055918Sshin if (connect(s, ai->ai_addr, ai->ai_addrlen) >= 0) 1411573Srgrimes break; 14255837Sjasone (void)_libc_close(s); 1431573Srgrimes if (errno == EADDRINUSE) { 1441573Srgrimes lport--; 1451573Srgrimes continue; 1461573Srgrimes } 14755918Sshin if (errno == ECONNREFUSED) 14855918Sshin refused = 1; 14955918Sshin if (ai->ai_next != NULL) { 1501573Srgrimes int oerrno = errno; 1511573Srgrimes 15255918Sshin getnameinfo(ai->ai_addr, ai->ai_addrlen, 15355918Sshin paddr, sizeof(paddr), 15455918Sshin NULL, 0, 15555918Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 1561573Srgrimes (void)fprintf(stderr, "connect to address %s: ", 15755918Sshin paddr); 1581573Srgrimes errno = oerrno; 1591573Srgrimes perror(0); 16055918Sshin ai = ai->ai_next; 16155918Sshin getnameinfo(ai->ai_addr, ai->ai_addrlen, 16255918Sshin paddr, sizeof(paddr), 16355918Sshin NULL, 0, 16455918Sshin NI_NUMERICHOST|NI_WITHSCOPEID); 16555918Sshin fprintf(stderr, "Trying %s...\n", paddr); 1661573Srgrimes continue; 1671573Srgrimes } 16855918Sshin if (refused && timo <= 16) { 16955918Sshin (void)_libc_sleep(timo); 17055918Sshin timo *= 2; 17155918Sshin ai = res; 17255918Sshin refused = 0; 17355918Sshin continue; 17455918Sshin } 17555918Sshin freeaddrinfo(res); 17655918Sshin (void)fprintf(stderr, "%s: %s\n", *ahost, strerror(errno)); 1771573Srgrimes sigsetmask(oldmask); 1781573Srgrimes return (-1); 1791573Srgrimes } 1801573Srgrimes lport--; 1811573Srgrimes if (fd2p == 0) { 18255837Sjasone _libc_write(s, "", 1); 1831573Srgrimes lport = 0; 1841573Srgrimes } else { 1851573Srgrimes char num[8]; 18655918Sshin int s2 = rresvport_af(&lport, ai->ai_family), s3; 18755918Sshin int len = ai->ai_addrlen; 1882592Scsgr int nfds; 1891573Srgrimes 1901573Srgrimes if (s2 < 0) 1911573Srgrimes goto bad; 1921573Srgrimes listen(s2, 1); 1931573Srgrimes (void)snprintf(num, sizeof(num), "%d", lport); 19455837Sjasone if (_libc_write(s, num, strlen(num)+1) != strlen(num)+1) { 1951573Srgrimes (void)fprintf(stderr, 1961573Srgrimes "rcmd: write (setting up stderr): %s\n", 1971573Srgrimes strerror(errno)); 19855837Sjasone (void)_libc_close(s2); 1991573Srgrimes goto bad; 2001573Srgrimes } 2012592Scsgr nfds = max(s, s2)+1; 2022592Scsgr if(nfds > FD_SETSIZE) { 2032592Scsgr fprintf(stderr, "rcmd: too many files\n"); 20455837Sjasone (void)_libc_close(s2); 2052592Scsgr goto bad; 2062592Scsgr } 20717543Speteragain: 2081573Srgrimes FD_ZERO(&reads); 2091573Srgrimes FD_SET(s, &reads); 2101573Srgrimes FD_SET(s2, &reads); 2111573Srgrimes errno = 0; 2122592Scsgr if (select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){ 2131573Srgrimes if (errno != 0) 2141573Srgrimes (void)fprintf(stderr, 2151573Srgrimes "rcmd: select (setting up stderr): %s\n", 2161573Srgrimes strerror(errno)); 2171573Srgrimes else 2181573Srgrimes (void)fprintf(stderr, 2191573Srgrimes "select: protocol failure in circuit setup\n"); 22055837Sjasone (void)_libc_close(s2); 2211573Srgrimes goto bad; 2221573Srgrimes } 2231573Srgrimes s3 = accept(s2, (struct sockaddr *)&from, &len); 22455918Sshin switch (from.ss_family) { 22555918Sshin case AF_INET: 22655918Sshin aport = ntohs(((struct sockaddr_in *)&from)->sin_port); 22755918Sshin break; 22855918Sshin#ifdef INET6 22955918Sshin case AF_INET6: 23055918Sshin aport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port); 23155918Sshin break; 23255918Sshin#endif 23355918Sshin default: 23455918Sshin aport = 0; /* error */ 23555918Sshin break; 23655918Sshin } 23717543Speter /* 23817543Speter * XXX careful for ftp bounce attacks. If discovered, shut them 23917543Speter * down and check for the real auxiliary channel to connect. 24017543Speter */ 24155918Sshin if (aport == 20) { 24255837Sjasone _libc_close(s3); 24317543Speter goto again; 24417543Speter } 24555837Sjasone (void)_libc_close(s2); 2461573Srgrimes if (s3 < 0) { 2471573Srgrimes (void)fprintf(stderr, 2481573Srgrimes "rcmd: accept: %s\n", strerror(errno)); 2491573Srgrimes lport = 0; 2501573Srgrimes goto bad; 2511573Srgrimes } 2521573Srgrimes *fd2p = s3; 25355918Sshin if (aport >= IPPORT_RESERVED || aport < IPPORT_RESERVED / 2) { 2541573Srgrimes (void)fprintf(stderr, 2551573Srgrimes "socket: protocol failure in circuit setup.\n"); 2561573Srgrimes goto bad2; 2571573Srgrimes } 2581573Srgrimes } 25955837Sjasone (void)_libc_write(s, locuser, strlen(locuser)+1); 26055837Sjasone (void)_libc_write(s, remuser, strlen(remuser)+1); 26155837Sjasone (void)_libc_write(s, cmd, strlen(cmd)+1); 26255837Sjasone if (_libc_read(s, &c, 1) != 1) { 2631573Srgrimes (void)fprintf(stderr, 2641573Srgrimes "rcmd: %s: %s\n", *ahost, strerror(errno)); 2651573Srgrimes goto bad2; 2661573Srgrimes } 2671573Srgrimes if (c != 0) { 26855837Sjasone while (_libc_read(s, &c, 1) == 1) { 26955837Sjasone (void)_libc_write(STDERR_FILENO, &c, 1); 2701573Srgrimes if (c == '\n') 2711573Srgrimes break; 2721573Srgrimes } 2731573Srgrimes goto bad2; 2741573Srgrimes } 2751573Srgrimes sigsetmask(oldmask); 27655918Sshin freeaddrinfo(res); 2771573Srgrimes return (s); 2781573Srgrimesbad2: 2791573Srgrimes if (lport) 28055837Sjasone (void)_libc_close(*fd2p); 2811573Srgrimesbad: 28255837Sjasone (void)_libc_close(s); 2831573Srgrimes sigsetmask(oldmask); 28455918Sshin freeaddrinfo(res); 2851573Srgrimes return (-1); 2861573Srgrimes} 2871573Srgrimes 2881573Srgrimesint 28955918Sshinrresvport(port) 29055918Sshin int *port; 2911573Srgrimes{ 29255918Sshin return rresvport_af(port, AF_INET); 29355918Sshin} 2941573Srgrimes 29555918Sshinint 29655918Sshinrresvport_af(alport, family) 29755918Sshin int *alport, family; 29855918Sshin{ 29955918Sshin int i, s, len, err; 30055918Sshin struct sockaddr_storage ss; 30155918Sshin u_short *sport; 30255918Sshin 30355918Sshin memset(&ss, 0, sizeof(ss)); 30455918Sshin ss.ss_family = family; 30555918Sshin switch (family) { 30655918Sshin case AF_INET: 30755918Sshin ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in); 30855918Sshin sport = &((struct sockaddr_in *)&ss)->sin_port; 30955918Sshin ((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY; 31055918Sshin break; 31155918Sshin#ifdef INET6 31255918Sshin case AF_INET6: 31355918Sshin ((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in6); 31455918Sshin sport = &((struct sockaddr_in6 *)&ss)->sin6_port; 31555918Sshin ((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any; 31655918Sshin break; 31755918Sshin#endif 31855918Sshin default: 31955918Sshin errno = EAFNOSUPPORT; 32055918Sshin return -1; 32155918Sshin } 32255918Sshin 32355918Sshin s = socket(ss.ss_family, SOCK_STREAM, 0); 3241573Srgrimes if (s < 0) 3251573Srgrimes return (-1); 32617543Speter#if 0 /* compat_exact_traditional_rresvport_semantics */ 32717543Speter sin.sin_port = htons((u_short)*alport); 32817543Speter if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) 32917543Speter return (s); 33017543Speter if (errno != EADDRINUSE) { 33155837Sjasone (void)_libc_close(s); 33217543Speter return (-1); 33316034Speter } 33417543Speter#endif 33555918Sshin *sport = 0; 33655918Sshin if (bindresvport2(s, (struct sockaddr *)&ss, 33755918Sshin ((struct sockaddr *)&ss)->sa_len) == -1) { 33855837Sjasone (void)_libc_close(s); 33917543Speter return (-1); 3401573Srgrimes } 34155918Sshin *alport = (int)ntohs(*sport); 34217543Speter return (s); 3431573Srgrimes} 3441573Srgrimes 3451573Srgrimesint __check_rhosts_file = 1; 3461573Srgrimeschar *__rcmd_errstr; 3471573Srgrimes 3481573Srgrimesint 3491573Srgrimesruserok(rhost, superuser, ruser, luser) 3501573Srgrimes const char *rhost, *ruser, *luser; 3511573Srgrimes int superuser; 3521573Srgrimes{ 35355918Sshin return ruserok_af(rhost, superuser, ruser, luser, AF_INET); 35455918Sshin} 35555918Sshin 35655918Sshinint 35755918Sshinruserok_af(rhost, superuser, ruser, luser, af) 35855918Sshin const char *rhost, *ruser, *luser; 35955918Sshin int superuser, af; 36055918Sshin{ 3611573Srgrimes struct hostent *hp; 36255918Sshin union { 36355918Sshin struct in_addr addr_in; 36455918Sshin struct in6_addr addr_in6; 36555918Sshin } addr; 3661573Srgrimes char **ap; 36755918Sshin int ret, h_error; 3681573Srgrimes 36955918Sshin if ((hp = getipnodebyname(rhost, af, AI_DEFAULT, &h_error)) == NULL) 3701573Srgrimes return (-1); 37155918Sshin ret = -1; 3721573Srgrimes for (ap = hp->h_addr_list; *ap; ++ap) { 37355918Sshin bcopy(*ap, &addr, hp->h_length); 37455918Sshin if (iruserok_af(&addr, superuser, ruser, luser, af) == 0) { 37555918Sshin ret = 0; 37655918Sshin break; 37755918Sshin } 3781573Srgrimes } 37955918Sshin freehostent(hp); 38055918Sshin return (ret); 3811573Srgrimes} 3821573Srgrimes 3831573Srgrimes/* 3841573Srgrimes * New .rhosts strategy: We are passed an ip address. We spin through 3851573Srgrimes * hosts.equiv and .rhosts looking for a match. When the .rhosts only 3861573Srgrimes * has ip addresses, we don't have to trust a nameserver. When it 3871573Srgrimes * contains hostnames, we spin through the list of addresses the nameserver 3881573Srgrimes * gives us and look for a match. 3891573Srgrimes * 3901573Srgrimes * Returns 0 if ok, -1 if not ok. 3911573Srgrimes */ 3921573Srgrimesint 3931573Srgrimesiruserok(raddr, superuser, ruser, luser) 39439979Sdfr unsigned long raddr; 3951573Srgrimes int superuser; 3961573Srgrimes const char *ruser, *luser; 3971573Srgrimes{ 39855918Sshin return iruserok_af(&raddr, superuser, ruser, luser, AF_INET); 39955918Sshin} 40055918Sshin 40155918Sshinint 40255918Sshiniruserok_af(raddr, superuser, ruser, luser, af) 40355918Sshin void *raddr; 40455918Sshin int superuser; 40555918Sshin const char *ruser, *luser; 40655918Sshin int af; 40755918Sshin{ 4081573Srgrimes register char *cp; 4091573Srgrimes struct stat sbuf; 4101573Srgrimes struct passwd *pwd; 4111573Srgrimes FILE *hostf; 4121573Srgrimes uid_t uid; 4131573Srgrimes int first; 4141573Srgrimes char pbuf[MAXPATHLEN]; 41555918Sshin int len = 0; 4161573Srgrimes 41755918Sshin switch (af) { 41855918Sshin case AF_INET: 41955918Sshin len = sizeof(struct in_addr); 42055918Sshin break; 42155918Sshin#ifdef INET6 42255918Sshin case AF_INET6: 42355918Sshin len = sizeof(struct in6_addr); 42455918Sshin break; 42555918Sshin#endif 42655918Sshin } 42755918Sshin 4281573Srgrimes first = 1; 4291573Srgrimes hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); 4301573Srgrimesagain: 4311573Srgrimes if (hostf) { 43255918Sshin if (__ivaliduser_af(hostf, raddr, luser, ruser, af, len) 43355918Sshin == 0) { 4341573Srgrimes (void)fclose(hostf); 4351573Srgrimes return (0); 4361573Srgrimes } 4371573Srgrimes (void)fclose(hostf); 4381573Srgrimes } 4391573Srgrimes if (first == 1 && (__check_rhosts_file || superuser)) { 4401573Srgrimes first = 0; 4411573Srgrimes if ((pwd = getpwnam(luser)) == NULL) 4421573Srgrimes return (-1); 4431573Srgrimes (void)strcpy(pbuf, pwd->pw_dir); 4441573Srgrimes (void)strcat(pbuf, "/.rhosts"); 4451573Srgrimes 4461573Srgrimes /* 4471573Srgrimes * Change effective uid while opening .rhosts. If root and 4481573Srgrimes * reading an NFS mounted file system, can't read files that 4491573Srgrimes * are protected read/write owner only. 4501573Srgrimes */ 4511573Srgrimes uid = geteuid(); 4521573Srgrimes (void)seteuid(pwd->pw_uid); 4531573Srgrimes hostf = fopen(pbuf, "r"); 4541573Srgrimes (void)seteuid(uid); 4551573Srgrimes 4561573Srgrimes if (hostf == NULL) 4571573Srgrimes return (-1); 4581573Srgrimes /* 4591573Srgrimes * If not a regular file, or is owned by someone other than 4601573Srgrimes * user or root or if writeable by anyone but the owner, quit. 4611573Srgrimes */ 4621573Srgrimes cp = NULL; 4631573Srgrimes if (lstat(pbuf, &sbuf) < 0) 4641573Srgrimes cp = ".rhosts lstat failed"; 4651573Srgrimes else if (!S_ISREG(sbuf.st_mode)) 4661573Srgrimes cp = ".rhosts not regular file"; 4671573Srgrimes else if (fstat(fileno(hostf), &sbuf) < 0) 4681573Srgrimes cp = ".rhosts fstat failed"; 4691573Srgrimes else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) 4701573Srgrimes cp = "bad .rhosts owner"; 4711573Srgrimes else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) 4721573Srgrimes cp = ".rhosts writeable by other than owner"; 4731573Srgrimes /* If there were any problems, quit. */ 4741573Srgrimes if (cp) { 4751573Srgrimes __rcmd_errstr = cp; 4761573Srgrimes (void)fclose(hostf); 4771573Srgrimes return (-1); 4781573Srgrimes } 4791573Srgrimes goto again; 4801573Srgrimes } 4811573Srgrimes return (-1); 4821573Srgrimes} 4831573Srgrimes 4841573Srgrimes/* 4851573Srgrimes * XXX 4861573Srgrimes * Don't make static, used by lpd(8). 4871573Srgrimes * 4881573Srgrimes * Returns 0 if ok, -1 if not ok. 4891573Srgrimes */ 4901573Srgrimesint 4911573Srgrimes__ivaliduser(hostf, raddr, luser, ruser) 4921573Srgrimes FILE *hostf; 49339979Sdfr u_int32_t raddr; 4941573Srgrimes const char *luser, *ruser; 4951573Srgrimes{ 49655918Sshin return __ivaliduser_af(hostf, &raddr, luser, ruser, AF_INET, 49755918Sshin sizeof(raddr)); 49855918Sshin} 49955918Sshin 50055918Sshinint 50155918Sshin__ivaliduser_af(hostf, raddr, luser, ruser, af, len) 50255918Sshin FILE *hostf; 50355918Sshin void *raddr; 50455918Sshin const char *luser, *ruser; 50555918Sshin int af, len; 50655918Sshin{ 5071573Srgrimes register char *user, *p; 5081573Srgrimes int ch; 5091573Srgrimes char buf[MAXHOSTNAMELEN + 128]; /* host + login */ 51010059Swpaul char hname[MAXHOSTNAMELEN]; 5117183Swpaul struct hostent *hp; 5127183Swpaul /* Presumed guilty until proven innocent. */ 5137183Swpaul int userok = 0, hostok = 0; 51455918Sshin int h_error; 5159978Swpaul#ifdef YP 5169978Swpaul char *ypdomain; 5171573Srgrimes 5189978Swpaul if (yp_get_default_domain(&ypdomain)) 5199978Swpaul ypdomain = NULL; 5209978Swpaul#else 5219978Swpaul#define ypdomain NULL 5229978Swpaul#endif 5237183Swpaul /* We need to get the damn hostname back for netgroup matching. */ 52455918Sshin if ((hp = getipnodebyaddr((char *)raddr, len, af, &h_error)) == NULL) 5257183Swpaul return (-1); 52623128Simp strncpy(hname, hp->h_name, sizeof(hname)); 52723128Simp hname[sizeof(hname) - 1] = '\0'; 52855918Sshin freehostent(hp); 5297183Swpaul 5301573Srgrimes while (fgets(buf, sizeof(buf), hostf)) { 5311573Srgrimes p = buf; 5321573Srgrimes /* Skip lines that are too long. */ 5331573Srgrimes if (strchr(p, '\n') == NULL) { 5341573Srgrimes while ((ch = getc(hostf)) != '\n' && ch != EOF); 5351573Srgrimes continue; 5361573Srgrimes } 5379552Speter if (*p == '\n' || *p == '#') { 5389552Speter /* comment... */ 5399552Speter continue; 5409552Speter } 5411573Srgrimes while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { 54252859Sache *p = isupper((unsigned char)*p) ? tolower((unsigned char)*p) : *p; 5431573Srgrimes p++; 5441573Srgrimes } 5451573Srgrimes if (*p == ' ' || *p == '\t') { 5461573Srgrimes *p++ = '\0'; 5471573Srgrimes while (*p == ' ' || *p == '\t') 5481573Srgrimes p++; 5491573Srgrimes user = p; 5501573Srgrimes while (*p != '\n' && *p != ' ' && 5511573Srgrimes *p != '\t' && *p != '\0') 5521573Srgrimes p++; 5531573Srgrimes } else 5541573Srgrimes user = p; 5551573Srgrimes *p = '\0'; 5567183Swpaul /* 5577183Swpaul * Do +/- and +@/-@ checking. This looks really nasty, 5587183Swpaul * but it matches SunOS's behavior so far as I can tell. 5597183Swpaul */ 5607183Swpaul switch(buf[0]) { 5617183Swpaul case '+': 5627183Swpaul if (!buf[1]) { /* '+' matches all hosts */ 5637183Swpaul hostok = 1; 5647183Swpaul break; 5657183Swpaul } 5667183Swpaul if (buf[1] == '@') /* match a host by netgroup */ 56710059Swpaul hostok = innetgr((char *)&buf[2], 56810059Swpaul (char *)&hname, NULL, ypdomain); 5697183Swpaul else /* match a host by addr */ 57055918Sshin hostok = __icheckhost(raddr,(char *)&buf[1], 57155918Sshin af, len); 5727183Swpaul break; 5737183Swpaul case '-': /* reject '-' hosts and all their users */ 5747183Swpaul if (buf[1] == '@') { 5757183Swpaul if (innetgr((char *)&buf[2], 57610059Swpaul (char *)&hname, NULL, ypdomain)) 5777183Swpaul return(-1); 5787183Swpaul } else { 57955918Sshin if (__icheckhost(raddr,(char *)&buf[1],af,len)) 5807183Swpaul return(-1); 5817183Swpaul } 5827183Swpaul break; 5837183Swpaul default: /* if no '+' or '-', do a simple match */ 58455918Sshin hostok = __icheckhost(raddr, buf, af, len); 5857183Swpaul break; 5861573Srgrimes } 5877183Swpaul switch(*user) { 5887183Swpaul case '+': 5897183Swpaul if (!*(user+1)) { /* '+' matches all users */ 5907183Swpaul userok = 1; 5917183Swpaul break; 5927183Swpaul } 5937183Swpaul if (*(user+1) == '@') /* match a user by netgroup */ 5949978Swpaul userok = innetgr(user+2, NULL, ruser, ypdomain); 5957183Swpaul else /* match a user by direct specification */ 5967183Swpaul userok = !(strcmp(ruser, user+1)); 5977183Swpaul break; 5987183Swpaul case '-': /* if we matched a hostname, */ 5997183Swpaul if (hostok) { /* check for user field rejections */ 6007183Swpaul if (!*(user+1)) 6017183Swpaul return(-1); 6027183Swpaul if (*(user+1) == '@') { 6037183Swpaul if (innetgr(user+2, NULL, 6049978Swpaul ruser, ypdomain)) 6057183Swpaul return(-1); 6067183Swpaul } else { 6077183Swpaul if (!strcmp(ruser, user+1)) 6087183Swpaul return(-1); 6097183Swpaul } 6107183Swpaul } 6117183Swpaul break; 6127183Swpaul default: /* no rejections: try to match the user */ 6137183Swpaul if (hostok) 6147183Swpaul userok = !(strcmp(ruser,*user ? user : luser)); 6157183Swpaul break; 6167183Swpaul } 6177183Swpaul if (hostok && userok) 6187183Swpaul return(0); 6191573Srgrimes } 6201573Srgrimes return (-1); 6211573Srgrimes} 6221573Srgrimes 6231573Srgrimes/* 6241573Srgrimes * Returns "true" if match, 0 if no match. 6251573Srgrimes */ 6261573Srgrimesstatic int 62755918Sshin__icheckhost(raddr, lhost, af, len) 62855918Sshin void *raddr; 6291573Srgrimes register char *lhost; 63055918Sshin int af, len; 6311573Srgrimes{ 6321573Srgrimes register struct hostent *hp; 63355918Sshin char laddr[BUFSIZ]; /* xxx */ 6341573Srgrimes register char **pp; 63555918Sshin int h_error; 63655918Sshin int match; 6371573Srgrimes 6381573Srgrimes /* Try for raw ip address first. */ 63955918Sshin if (inet_pton(af, lhost, laddr) == 1) { 64055918Sshin if (memcmp(raddr, laddr, len) == 0) 64155918Sshin return (1); 64255918Sshin else 64355918Sshin return (0); 64455918Sshin } 6451573Srgrimes 6461573Srgrimes /* Better be a hostname. */ 64755918Sshin if ((hp = getipnodebyname(lhost, af, AI_DEFAULT, &h_error)) == NULL) 6481573Srgrimes return (0); 6491573Srgrimes 6501573Srgrimes /* Spin through ip addresses. */ 65155918Sshin match = 0; 6521573Srgrimes for (pp = hp->h_addr_list; *pp; ++pp) 65355918Sshin if (!bcmp(raddr, *pp, len)) { 65455918Sshin match = 1; 65555918Sshin break; 65655918Sshin } 6571573Srgrimes 65855918Sshin freehostent(hp); 65955918Sshin return (match); 6601573Srgrimes} 661