155682Smarkm/* 255682Smarkm * Copyright (c) 1983, 1993, 1994 355682Smarkm * The Regents of the University of California. All rights reserved. 455682Smarkm * 555682Smarkm * Redistribution and use in source and binary forms, with or without 655682Smarkm * modification, are permitted provided that the following conditions 755682Smarkm * are met: 855682Smarkm * 1. Redistributions of source code must retain the above copyright 955682Smarkm * notice, this list of conditions and the following disclaimer. 1055682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer in the 1255682Smarkm * documentation and/or other materials provided with the distribution. 13178825Sdfr * 3. Neither the name of the University nor the names of its contributors 1455682Smarkm * may be used to endorse or promote products derived from this software 1555682Smarkm * without specific prior written permission. 1655682Smarkm * 1755682Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1855682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1955682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2055682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2155682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2255682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2355682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2455682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2555682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2655682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2755682Smarkm * SUCH DAMAGE. 2855682Smarkm */ 2955682Smarkm 3055682Smarkm#include <config.h> 3155682Smarkm 3255682Smarkm#include <stdio.h> 3355682Smarkm#include <ctype.h> 3455682Smarkm#ifdef HAVE_SYS_TYPES_H 3555682Smarkm#include <sys/types.h> 3655682Smarkm#endif 3755682Smarkm#ifdef HAVE_NETINET_IN_H 3855682Smarkm#include <netinet/in.h> 3955682Smarkm#endif 4055682Smarkm#ifdef HAVE_NETINET_IN6_H 4155682Smarkm#include <netinet/in6.h> 4255682Smarkm#endif 4355682Smarkm#ifdef HAVE_NETINET6_IN6_H 4455682Smarkm#include <netinet6/in6.h> 4555682Smarkm#endif 4655682Smarkm#ifdef HAVE_RPCSVC_YPCLNT_H 4755682Smarkm#include <rpcsvc/ypclnt.h> 4855682Smarkm#endif 4955682Smarkm 5055682Smarkm#include "roken.h" 5155682Smarkm 5255682Smarkmint __check_rhosts_file = 1; 5355682Smarkmchar *__rcmd_errstr = 0; 5455682Smarkm 5555682Smarkm/* 5655682Smarkm * Returns "true" if match, 0 if no match. 5755682Smarkm */ 5855682Smarkmstatic 5955682Smarkmint 6055682Smarkm__icheckhost(unsigned raddr, const char *lhost) 6155682Smarkm{ 6255682Smarkm struct hostent *hp; 6355682Smarkm u_long laddr; 6455682Smarkm char **pp; 6555682Smarkm 6655682Smarkm /* Try for raw ip address first. */ 6755682Smarkm if (isdigit((unsigned char)*lhost) 6855682Smarkm && (long)(laddr = inet_addr(lhost)) != -1) 6955682Smarkm return (raddr == laddr); 7055682Smarkm 7155682Smarkm /* Better be a hostname. */ 7255682Smarkm if ((hp = gethostbyname(lhost)) == NULL) 7355682Smarkm return (0); 7455682Smarkm 7555682Smarkm /* Spin through ip addresses. */ 7655682Smarkm for (pp = hp->h_addr_list; *pp; ++pp) 7755682Smarkm if (memcmp(&raddr, *pp, sizeof(u_long)) == 0) 7855682Smarkm return (1); 7955682Smarkm 8055682Smarkm /* No match. */ 8155682Smarkm return (0); 8255682Smarkm} 8355682Smarkm 8455682Smarkm/* 8555682Smarkm * Returns 0 if ok, -1 if not ok. 8655682Smarkm */ 8755682Smarkmstatic 8855682Smarkmint 8955682Smarkm__ivaliduser(FILE *hostf, unsigned raddr, const char *luser, 9055682Smarkm const char *ruser) 9155682Smarkm{ 9255682Smarkm char *user, *p; 9355682Smarkm int ch; 9455682Smarkm char buf[MaxHostNameLen + 128]; /* host + login */ 9555682Smarkm char hname[MaxHostNameLen]; 9655682Smarkm struct hostent *hp; 9755682Smarkm /* Presumed guilty until proven innocent. */ 9855682Smarkm int userok = 0, hostok = 0; 9955682Smarkm#ifdef HAVE_YP_GET_DEFAULT_DOMAIN 10055682Smarkm char *ypdomain; 10155682Smarkm 10255682Smarkm if (yp_get_default_domain(&ypdomain)) 10355682Smarkm ypdomain = NULL; 10455682Smarkm#else 10555682Smarkm#define ypdomain NULL 10655682Smarkm#endif 10755682Smarkm /* We need to get the damn hostname back for netgroup matching. */ 10855682Smarkm if ((hp = gethostbyaddr((char *)&raddr, 10955682Smarkm sizeof(u_long), 11055682Smarkm AF_INET)) == NULL) 11155682Smarkm return (-1); 11255682Smarkm strlcpy(hname, hp->h_name, sizeof(hname)); 11355682Smarkm 11455682Smarkm while (fgets(buf, sizeof(buf), hostf)) { 11555682Smarkm p = buf; 11655682Smarkm /* Skip lines that are too long. */ 11755682Smarkm if (strchr(p, '\n') == NULL) { 11855682Smarkm while ((ch = getc(hostf)) != '\n' && ch != EOF); 11955682Smarkm continue; 12055682Smarkm } 12155682Smarkm if (*p == '\n' || *p == '#') { 12255682Smarkm /* comment... */ 12355682Smarkm continue; 12455682Smarkm } 12555682Smarkm while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { 12655682Smarkm if (isupper((unsigned char)*p)) 12755682Smarkm *p = tolower((unsigned char)*p); 12855682Smarkm p++; 12955682Smarkm } 13055682Smarkm if (*p == ' ' || *p == '\t') { 13155682Smarkm *p++ = '\0'; 13255682Smarkm while (*p == ' ' || *p == '\t') 13355682Smarkm p++; 13455682Smarkm user = p; 13555682Smarkm while (*p != '\n' && *p != ' ' && 13655682Smarkm *p != '\t' && *p != '\0') 13755682Smarkm p++; 13855682Smarkm } else 13955682Smarkm user = p; 14055682Smarkm *p = '\0'; 14155682Smarkm /* 14255682Smarkm * Do +/- and +@/-@ checking. This looks really nasty, 14355682Smarkm * but it matches SunOS's behavior so far as I can tell. 14455682Smarkm */ 14555682Smarkm switch(buf[0]) { 14655682Smarkm case '+': 14755682Smarkm if (!buf[1]) { /* '+' matches all hosts */ 14855682Smarkm hostok = 1; 14955682Smarkm break; 15055682Smarkm } 15155682Smarkm if (buf[1] == '@') /* match a host by netgroup */ 15255682Smarkm hostok = innetgr((char *)&buf[2], 15355682Smarkm (char *)&hname, NULL, ypdomain); 15455682Smarkm else /* match a host by addr */ 15555682Smarkm hostok = __icheckhost(raddr,(char *)&buf[1]); 15655682Smarkm break; 15755682Smarkm case '-': /* reject '-' hosts and all their users */ 15855682Smarkm if (buf[1] == '@') { 15955682Smarkm if (innetgr((char *)&buf[2], 16055682Smarkm (char *)&hname, NULL, ypdomain)) 16155682Smarkm return(-1); 16255682Smarkm } else { 16355682Smarkm if (__icheckhost(raddr,(char *)&buf[1])) 16455682Smarkm return(-1); 16555682Smarkm } 16655682Smarkm break; 16755682Smarkm default: /* if no '+' or '-', do a simple match */ 16855682Smarkm hostok = __icheckhost(raddr, buf); 16955682Smarkm break; 17055682Smarkm } 17155682Smarkm switch(*user) { 17255682Smarkm case '+': 17355682Smarkm if (!*(user+1)) { /* '+' matches all users */ 17455682Smarkm userok = 1; 17555682Smarkm break; 17655682Smarkm } 17755682Smarkm if (*(user+1) == '@') /* match a user by netgroup */ 17855682Smarkm userok = innetgr(user+2, NULL, (char *)ruser, 17955682Smarkm ypdomain); 18055682Smarkm else /* match a user by direct specification */ 18155682Smarkm userok = !(strcmp(ruser, user+1)); 18255682Smarkm break; 18355682Smarkm case '-': /* if we matched a hostname, */ 18455682Smarkm if (hostok) { /* check for user field rejections */ 18555682Smarkm if (!*(user+1)) 18655682Smarkm return(-1); 18755682Smarkm if (*(user+1) == '@') { 18855682Smarkm if (innetgr(user+2, NULL, 18955682Smarkm (char *)ruser, ypdomain)) 19055682Smarkm return(-1); 19155682Smarkm } else { 19255682Smarkm if (!strcmp(ruser, user+1)) 19355682Smarkm return(-1); 19455682Smarkm } 19555682Smarkm } 19655682Smarkm break; 19755682Smarkm default: /* no rejections: try to match the user */ 19855682Smarkm if (hostok) 19955682Smarkm userok = !(strcmp(ruser,*user ? user : luser)); 20055682Smarkm break; 20155682Smarkm } 20255682Smarkm if (hostok && userok) 20355682Smarkm return(0); 20455682Smarkm } 20555682Smarkm return (-1); 20655682Smarkm} 20755682Smarkm 20855682Smarkm/* 20955682Smarkm * New .rhosts strategy: We are passed an ip address. We spin through 21055682Smarkm * hosts.equiv and .rhosts looking for a match. When the .rhosts only 21155682Smarkm * has ip addresses, we don't have to trust a nameserver. When it 21255682Smarkm * contains hostnames, we spin through the list of addresses the nameserver 21355682Smarkm * gives us and look for a match. 21455682Smarkm * 21555682Smarkm * Returns 0 if ok, -1 if not ok. 21655682Smarkm */ 217233294SstasROKEN_LIB_FUNCTION int ROKEN_LIB_CALL 21855682Smarkmiruserok(unsigned raddr, int superuser, const char *ruser, const char *luser) 21955682Smarkm{ 22055682Smarkm char *cp; 22155682Smarkm struct stat sbuf; 22255682Smarkm struct passwd *pwd; 22355682Smarkm FILE *hostf; 22455682Smarkm uid_t uid; 22555682Smarkm int first; 22655682Smarkm char pbuf[MaxPathLen]; 22755682Smarkm 22855682Smarkm first = 1; 22955682Smarkm hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); 23055682Smarkmagain: 23155682Smarkm if (hostf) { 23255682Smarkm if (__ivaliduser(hostf, raddr, luser, ruser) == 0) { 23355682Smarkm fclose(hostf); 23455682Smarkm return (0); 23555682Smarkm } 23655682Smarkm fclose(hostf); 23755682Smarkm } 23855682Smarkm if (first == 1 && (__check_rhosts_file || superuser)) { 23955682Smarkm first = 0; 24055682Smarkm if ((pwd = k_getpwnam((char*)luser)) == NULL) 24155682Smarkm return (-1); 24255682Smarkm snprintf (pbuf, sizeof(pbuf), "%s/.rhosts", pwd->pw_dir); 24355682Smarkm 24455682Smarkm /* 24555682Smarkm * Change effective uid while opening .rhosts. If root and 24655682Smarkm * reading an NFS mounted file system, can't read files that 24755682Smarkm * are protected read/write owner only. 24855682Smarkm */ 24955682Smarkm uid = geteuid(); 250178825Sdfr if (seteuid(pwd->pw_uid) < 0) 251178825Sdfr return (-1); 25255682Smarkm hostf = fopen(pbuf, "r"); 25355682Smarkm seteuid(uid); 25455682Smarkm 25555682Smarkm if (hostf == NULL) 25655682Smarkm return (-1); 25755682Smarkm /* 25855682Smarkm * If not a regular file, or is owned by someone other than 25955682Smarkm * user or root or if writeable by anyone but the owner, quit. 26055682Smarkm */ 26155682Smarkm cp = NULL; 26255682Smarkm if (lstat(pbuf, &sbuf) < 0) 26355682Smarkm cp = ".rhosts lstat failed"; 26455682Smarkm else if (!S_ISREG(sbuf.st_mode)) 26555682Smarkm cp = ".rhosts not regular file"; 26655682Smarkm else if (fstat(fileno(hostf), &sbuf) < 0) 26755682Smarkm cp = ".rhosts fstat failed"; 26855682Smarkm else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) 26955682Smarkm cp = "bad .rhosts owner"; 27055682Smarkm else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) 27155682Smarkm cp = ".rhosts writeable by other than owner"; 27255682Smarkm /* If there were any problems, quit. */ 27355682Smarkm if (cp) { 27455682Smarkm __rcmd_errstr = cp; 27555682Smarkm fclose(hostf); 27655682Smarkm return (-1); 27755682Smarkm } 27855682Smarkm goto again; 27955682Smarkm } 28055682Smarkm return (-1); 28155682Smarkm} 282