Added iruserok()
git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@379 ec53bebd-3082-4978-b11e-865c3cabbd6b
This commit is contained in:
		| @@ -1,3 +1,36 @@ | ||||
| /* | ||||
|  * Copyright (c) 1983, 1993, 1994 | ||||
|  *	The Regents of the University of California.  All rights reserved. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions | ||||
|  * are met: | ||||
|  * 1. Redistributions of source code must retain the above copyright | ||||
|  *    notice, this list of conditions and the following disclaimer. | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright | ||||
|  *    notice, this list of conditions and the following disclaimer in the | ||||
|  *    documentation and/or other materials provided with the distribution. | ||||
|  * 3. All advertising materials mentioning features or use of this software | ||||
|  *    must display the following acknowledgement: | ||||
|  *	This product includes software developed by the University of | ||||
|  *	California, Berkeley and its contributors. | ||||
|  * 4. Neither the name of the University nor the names of its contributors | ||||
|  *    may be used to endorse or promote products derived from this software | ||||
|  *    without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||||
|  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
|  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||||
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
|  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||||
|  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
|  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||
|  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
|  * SUCH DAMAGE. | ||||
|  */ | ||||
|  | ||||
| #include "bsd_locl.h" | ||||
|  | ||||
| RCSID("$Id$"); | ||||
| @@ -7,14 +40,227 @@ RCSID("$Id$"); | ||||
| int     __check_rhosts_file = 1; | ||||
| char    *__rcmd_errstr = 0; | ||||
|  | ||||
| /* | ||||
|  * Returns "true" if match, 0 if no match. | ||||
|  */ | ||||
| static | ||||
| int | ||||
| __icheckhost(u_int32_t raddr, const char *lhost) | ||||
| { | ||||
| 	register struct hostent *hp; | ||||
| 	register u_long laddr; | ||||
| 	register char **pp; | ||||
|  | ||||
| 	/* Try for raw ip address first. */ | ||||
| 	if (isdigit(*lhost) && (long)(laddr = inet_addr(lhost)) != -1) | ||||
| 		return (raddr == laddr); | ||||
|  | ||||
| 	/* Better be a hostname. */ | ||||
| 	if ((hp = gethostbyname(lhost)) == NULL) | ||||
| 		return (0); | ||||
|  | ||||
| 	/* Spin through ip addresses. */ | ||||
| 	for (pp = hp->h_addr_list; *pp; ++pp) | ||||
| 		if (!bcmp(&raddr, *pp, sizeof(u_long))) | ||||
| 			return (1); | ||||
|  | ||||
| 	/* No match. */ | ||||
| 	return (0); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Returns 0 if ok, -1 if not ok. | ||||
|  */ | ||||
| static | ||||
| int | ||||
| __ivaliduser(FILE *hostf, u_int32_t raddr, const char *luser, const char *ruser) | ||||
| { | ||||
| 	register char *user, *p; | ||||
| 	int ch; | ||||
| 	char buf[MAXHOSTNAMELEN + 128];		/* host + login */ | ||||
| 	char hname[MAXHOSTNAMELEN]; | ||||
| 	struct hostent *hp; | ||||
| 	/* Presumed guilty until proven innocent. */ | ||||
| 	int userok = 0, hostok = 0; | ||||
| #ifdef HAVE_YP_GET_DEFAULT_DOMAIN | ||||
| 	char *ypdomain; | ||||
|  | ||||
| 	if (yp_get_default_domain(&ypdomain)) | ||||
| 		ypdomain = NULL; | ||||
| #else | ||||
| #define	ypdomain NULL | ||||
| #endif | ||||
| 	/* We need to get the damn hostname back for netgroup matching. */ | ||||
| 	if ((hp = gethostbyaddr((char *)&raddr, sizeof(u_long), | ||||
| 							AF_INET)) == NULL) | ||||
| 		return (-1); | ||||
| 	strcpy(hname, hp->h_name); | ||||
|  | ||||
| 	while (fgets(buf, sizeof(buf), hostf)) { | ||||
| 		p = buf; | ||||
| 		/* Skip lines that are too long. */ | ||||
| 		if (strchr(p, '\n') == NULL) { | ||||
| 			while ((ch = getc(hostf)) != '\n' && ch != EOF); | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (*p == '\n' || *p == '#') { | ||||
| 			/* comment... */ | ||||
| 			continue; | ||||
| 		} | ||||
| 		while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') { | ||||
| 			*p = isupper(*p) ? tolower(*p) : *p; | ||||
| 			p++; | ||||
| 		} | ||||
| 		if (*p == ' ' || *p == '\t') { | ||||
| 			*p++ = '\0'; | ||||
| 			while (*p == ' ' || *p == '\t') | ||||
| 				p++; | ||||
| 			user = p; | ||||
| 			while (*p != '\n' && *p != ' ' && | ||||
| 			    *p != '\t' && *p != '\0') | ||||
| 				p++; | ||||
| 		} else | ||||
| 			user = p; | ||||
| 		*p = '\0'; | ||||
| 		/* | ||||
| 		 * Do +/- and +@/-@ checking. This looks really nasty, | ||||
| 		 * but it matches SunOS's behavior so far as I can tell. | ||||
| 		 */ | ||||
| 		switch(buf[0]) { | ||||
| 		case '+': | ||||
| 			if (!buf[1]) {     /* '+' matches all hosts */ | ||||
| 				hostok = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 			if (buf[1] == '@')  /* match a host by netgroup */ | ||||
| 				hostok = innetgr((char *)&buf[2], | ||||
| 					(char *)&hname, NULL, ypdomain); | ||||
| 			else		/* match a host by addr */ | ||||
| 				hostok = __icheckhost(raddr,(char *)&buf[1]); | ||||
| 			break; | ||||
| 		case '-':     /* reject '-' hosts and all their users */ | ||||
| 			if (buf[1] == '@') { | ||||
| 				if (innetgr((char *)&buf[2], | ||||
| 					      (char *)&hname, NULL, ypdomain)) | ||||
| 					return(-1); | ||||
| 			} else { | ||||
| 				if (__icheckhost(raddr,(char *)&buf[1])) | ||||
| 					return(-1); | ||||
| 			} | ||||
| 			break; | ||||
| 		default:  /* if no '+' or '-', do a simple match */ | ||||
| 			hostok = __icheckhost(raddr, buf); | ||||
| 			break; | ||||
| 		} | ||||
| 		switch(*user) { | ||||
| 		case '+': | ||||
| 			if (!*(user+1)) {      /* '+' matches all users */ | ||||
| 				userok = 1; | ||||
| 				break; | ||||
| 			} | ||||
| 			if (*(user+1) == '@')  /* match a user by netgroup */ | ||||
| 				userok = innetgr(user+2, NULL, ruser, ypdomain); | ||||
| 			else	   /* match a user by direct specification */ | ||||
| 				userok = !(strcmp(ruser, user+1)); | ||||
| 			break; | ||||
| 		case '-': 		/* if we matched a hostname, */ | ||||
| 			if (hostok) {   /* check for user field rejections */ | ||||
| 				if (!*(user+1)) | ||||
| 					return(-1); | ||||
| 				if (*(user+1) == '@') { | ||||
| 					if (innetgr(user+2, NULL, | ||||
| 							ruser, ypdomain)) | ||||
| 						return(-1); | ||||
| 				} else { | ||||
| 					if (!strcmp(ruser, user+1)) | ||||
| 						return(-1); | ||||
| 				} | ||||
| 			} | ||||
| 			break; | ||||
| 		default:	/* no rejections: try to match the user */ | ||||
| 			if (hostok) | ||||
| 				userok = !(strcmp(ruser,*user ? user : luser)); | ||||
| 			break; | ||||
| 		} | ||||
| 		if (hostok && userok) | ||||
| 			return(0); | ||||
| 	} | ||||
| 	return (-1); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * New .rhosts strategy: We are passed an ip address. We spin through | ||||
|  * hosts.equiv and .rhosts looking for a match. When the .rhosts only | ||||
|  * has ip addresses, we don't have to trust a nameserver.  When it | ||||
|  * contains hostnames, we spin through the list of addresses the nameserver | ||||
|  * gives us and look for a match. | ||||
|  * | ||||
|  * Returns 0 if ok, -1 if not ok. | ||||
|  */ | ||||
| int | ||||
| iruserok(u_int32_t raddr, int superuser, const char *ruser, const char *luser) | ||||
| { | ||||
|   return -1; | ||||
| 	register char *cp; | ||||
| 	struct stat sbuf; | ||||
| 	struct passwd *pwd; | ||||
| 	FILE *hostf; | ||||
| 	uid_t uid; | ||||
| 	int first; | ||||
| 	char pbuf[MAXPATHLEN]; | ||||
|  | ||||
| 	first = 1; | ||||
| 	hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); | ||||
| again: | ||||
| 	if (hostf) { | ||||
| 		if (__ivaliduser(hostf, raddr, luser, ruser) == 0) { | ||||
| 			(void)fclose(hostf); | ||||
| 			return (0); | ||||
| 		} | ||||
| 		(void)fclose(hostf); | ||||
| 	} | ||||
| 	if (first == 1 && (__check_rhosts_file || superuser)) { | ||||
| 		first = 0; | ||||
| 		if ((pwd = getpwnam(luser)) == NULL) | ||||
| 			return (-1); | ||||
| 		(void)strcpy(pbuf, pwd->pw_dir); | ||||
| 		(void)strcat(pbuf, "/.rhosts"); | ||||
|  | ||||
| 		/* | ||||
| 		 * Change effective uid while opening .rhosts.  If root and | ||||
| 		 * reading an NFS mounted file system, can't read files that | ||||
| 		 * are protected read/write owner only. | ||||
| 		 */ | ||||
| 		uid = geteuid(); | ||||
| 		(void)seteuid(pwd->pw_uid); | ||||
| 		hostf = fopen(pbuf, "r"); | ||||
| 		(void)seteuid(uid); | ||||
|  | ||||
| 		if (hostf == NULL) | ||||
| 			return (-1); | ||||
| 		/* | ||||
| 		 * If not a regular file, or is owned by someone other than | ||||
| 		 * user or root or if writeable by anyone but the owner, quit. | ||||
| 		 */ | ||||
| 		cp = NULL; | ||||
| 		if (lstat(pbuf, &sbuf) < 0) | ||||
| 			cp = ".rhosts lstat failed"; | ||||
| 		else if (!S_ISREG(sbuf.st_mode)) | ||||
| 			cp = ".rhosts not regular file"; | ||||
| 		else if (fstat(fileno(hostf), &sbuf) < 0) | ||||
| 			cp = ".rhosts fstat failed"; | ||||
| 		else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) | ||||
| 			cp = "bad .rhosts owner"; | ||||
| 		else if (sbuf.st_mode & (S_IWGRP|S_IWOTH)) | ||||
| 			cp = ".rhosts writeable by other than owner"; | ||||
| 		/* If there were any problems, quit. */ | ||||
| 		if (cp) { | ||||
| 			__rcmd_errstr = cp; | ||||
| 			(void)fclose(hostf); | ||||
| 			return (-1); | ||||
| 		} | ||||
| 		goto again; | ||||
| 	} | ||||
| 	return (-1); | ||||
| } | ||||
|  | ||||
| #endif /* !HAVE_IRUSEROK */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Björn Groenvall
					Björn Groenvall