Ultrix-3.1/src/cmd/uucp/chkpth.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

static char Sccsid[] = "@(#)chkpth.c	3.0	4/22/86";

/*
 *  chkpth.c implements the security algorithms.
 *  Modified Doug Kingston, 30 July 82 to fix handling of	
 *	of the "userpath" structures.			
 * (brl-bmd) 
 * chkpth should not be called for implied Spool requests .
 * But explicit requests (foo!/usr/spoo/uucp/*) should use chkpth.
 * 
 *  decvax!larry - callcheck() checks to see if remote machine
 *		used a valed login id.
 *  decvax!larry - getxeqlevel() gets the execution level assigned
 *		to a remote machine.
 */


#include "uucp.h"
#include <sys/types.h>
#include <sys/stat.h>


#define DFLTNAME "default"	/* Not Implemented. ??? */

struct userpath {
	char *us_lname;
	char *us_mname;
	char us_callback;
	int  us_xeqlev;		/* remote execution level */
	char **us_path;
	struct userpath *unext;
};
struct userpath *Uhead = NULL;
struct userpath *Mchdef = NULL, *Logdef = NULL;
int Uptfirst = 1;


/*******
 *	chkpth(logname, mchname, path)
 *	char *path, *logname, *mchname;
 *
 *	chkpth  -  this routine will check the USERFILE for the
 *	machine or log name (non-null parameter) to see if the
 *	input path starts with an acceptable prefix.
 *
 *	return codes:  0  |  FAIL
 */

chkpth(logname, mchname, path)
char *path, *logname, *mchname;
{
	struct userpath *u;
	extern char *lastpart();
	char **p, *s;

	/* Allow only rooted pathnames.  Security wish.  rti!trt */
	if (*path != '/')
		return(FAIL);

	if (Uptfirst) {
		rdpth();
		ASSERT(Uhead != NULL, "INIT USERFILE, No entrys!", "", 0);
		Uptfirst = 0;
	}
	for (u = Uhead; u != NULL; ) {
		if (*logname != '\0' && strcmp(logname, u->us_lname) == SAME)
			break;
		if (*mchname != '\0' && strncmp(mchname, u->us_mname, 7) == SAME)
			break;
		u = u->unext;
	}
	if (u == NULL) {
		if (*logname == '\0')
			u = Mchdef;
		else
			u = Logdef;
		if (u == NULL)
			return(FAIL);
	}
	/* found user name */
	p = u->us_path;

	/*  check for /../ in path name  */
	for (s = path; *s != '\0'; s++) {
		if (prefix("/../",s))
			return(FAIL);
	}

	/* Check for access permission */
	for (p = u->us_path; *p != NULL; p++)
		if (prefix(*p, path))
			return(0);

	/* path name not valid */
	return(FAIL);
}


/***
 *	rdpth()
 *
 *	rdpth  -  this routine will read the USERFILE and
 *	construct the userpath structure pointed to by (u);
 *
 *	return codes:  0  |  FAIL
 *
 * 5/3/81 - changed to enforce the uucp-wide convention that system
 *	    names be 7 chars or less in length
 */

#define NO_XEQ_LEVEL -1

rdpth()
{
	char buf[100 + 1], *pbuf[50 + 1], *pc, **cp;
	FILE *uf;
	if ((uf = fopen(USERFILE, "r")) == NULL) {
		/* can not open file */
		ASSERT_NOFAIL(uf != NULL, "Can not open USERFILE", "", uf);
		return;
	}

	while (cfgets(buf, sizeof(buf), uf) != NULL) {
		int nargs, i;
		struct userpath *u;

		if ((u = (struct userpath *)malloc(sizeof (struct userpath))) == NULL) {
			DEBUG (1, "*** Userpath malloc failed\n", 0);
			fclose (uf);
			return;
		}
		if ((pc = calloc((unsigned)strlen(buf) + 1, sizeof (char)))
			== NULL) {
			/* can not allocate space */
			DEBUG (1, "Userpath calloc 1 failed\n", 0);
			fclose(uf);
			return;
		}

		strcpy(pc, buf);
		nargs = getargs(pc, pbuf);
		u->us_lname = pbuf[0];
		pc = index(u->us_lname, ',');
		if (pc != NULL)
			*pc++ = '\0';
		else
			pc = u->us_lname + strlen(u->us_lname);
		u->us_mname = pc;
		if (strlen(u->us_mname) > 7)
			u->us_mname[7] = '\0';
		if (strcmp(u->us_lname, "remote") == SAME) { 
			ASSERT(pbuf[1][0]=='X',"default xeq level undefined in USERFILE", u->us_lname, 0);
			Mchdef = u;
		}
		else
			if (strcmp(u->us_lname, "local") == SAME) {
				ASSERT(pbuf[1][0]=='X',"default xeq level undefined in USERFILE", u->us_lname, 0);
				Logdef = u;
			}
		i = 1;
		if (pbuf[1][0]=='X') {
			u->us_xeqlev = atoi(&pbuf[1][1]);
			i++;
		}
		else
			u->us_xeqlev = NO_XEQ_LEVEL;
/*
		DEBUG(5, "in chkpth, machine is:%s:, ", u->us_mname);
		DEBUG(5, "in chkpth, user is:%s:, ", u->us_lname);
		DEBUG(5, "xeqlevel is %d\n", u->us_xeqlev);
*/
		if (strcmp(pbuf[2], "c") == SAME) {
			u->us_callback = 1;
			i++;
			DEBUG(5,"callback for option on for user %s/n",
				u->us_lname);
		}
		else
			u->us_callback = 0;
		if ((cp = u->us_path =
		  (char **)calloc((unsigned)(nargs-i+1), sizeof(char *))) == NULL) {
			/*  can not allocate space */
			DEBUG (1, "Userpath calloc 2 failed!\n", 0);
			fclose(uf);
			return;
		}

		while (i < nargs)
			*cp++ = pbuf[i++];
		*cp = NULL;
		u->unext = Uhead;
		Uhead = u;
	}

	fclose(uf);
	ASSERT(Mchdef != NULL, "NO default in USERFILE for remote machines","",0);
	ASSERT(Logdef != NULL, "NO default in USERFILE for local users","",0);
	return;
}

/* routine to get execution level for a remote machine */
getxeqlevel(mch_name)
register char *mch_name;
{
	register struct userpath *u;

	if (Uptfirst) {
		rdpth();
		ASSERT(Uhead != 0, "INIT USERFILE, No entries!!", "", 0);
		Uptfirst = 0;
	}

	for (u = Uhead; u != NULL;) 
		if (strncmp(u->us_mname, mch_name, 7) == SAME) {
				DEBUG(4,"getxeqlevel %d\n",u->us_xeqlev);
			/*
			 * return default remote execution level if
			 * no execution level specified for this system
			 */
				if (u->us_xeqlev == NO_XEQ_LEVEL)
					return(Mchdef->us_xeqlev);
				return(u->us_xeqlev);
			}
			else 	{
				u = u->unext;
				continue;
				}
/*
 * machine name not found - return default execution level
 * 	for remote machines.
 * If the specified machine happens to be the local system
 * then return the default "local" execution level
 */
	if (strncmp(mch_name, Myname, 7) == SAME)
		return(Logdef->us_xeqlev); /* local xeq level returned */
	return(Mchdef->us_xeqlev);
}


/***
 *	chkperm(file, mopt)	check write permission of file
 *	char *mopt;		none NULL - create directories
 *
 *	if mopt != NULL and permissions are ok,
 *	a side effect of this routine is to make
 *	directories up to the last part of the
 *	filename (if they do not exist).
 *
 *	return 0 | FAIL
 */

chkperm(file, mopt)
char *file, *mopt;
{
	struct stat s;
	int ret;
	char dir[MAXFULLNAME];
	extern char *lastpart();

	if (stat(subfile(file), &s) == 0) {
		/* Forbid scribbling on a not-generally-writable file */
		/* rti!trt */
		if ((s.st_mode & ANYWRITE) == 0)
			return(FAIL);
		return(0);
	}

	strcpy(dir, file);
	*lastpart(dir) = '\0';
	if ((ret = stat(subfile(dir), &s)) == -1
	  && mopt == NULL)
		return(FAIL);

	if (ret != -1) {
		if ((s.st_mode & ANYWRITE) == 0)
			return(FAIL);
		else
			return(0);
	}

	/*  make directories  */
	return(mkdirs(subfile(file)));
}

/*
 * Check for sufficient privilege to request debugging.
 * Credit to seismo!stewart, John Stewart.
 */
chkdebug(uid)
int uid;
{
/* should put this somewhere else can't compile uustat */
/*
	if (uid > PRIV_UIDS) {
		fprintf(stderr, "Sorry, uid must be <= %d for debugging\n",
			PRIV_UIDS);
		cleanup(1);
		exit(1);
	}
*/
}




/*
 * check for callback and bad login/machine match
 *	log_name	-> login name
 *	mch_name	-> remote machine name
 * returns:
 *	0	-> no call back
 *	1	-> call back
 *	2	-> login/machine match failure
 */
callcheck(log_name, mch_name)
register char *log_name;
register char *mch_name;
{
	register struct userpath *u;
	register int i;
	int ret;
	int found_mch = 0;
	int found_log = 0;

	if (Uptfirst) {
		rdpth();
		ASSERT(Uhead != 0, "INIT USERFILE, No entries!!", "", 0);
		Uptfirst = 0;
	}

	for (u = Uhead; u != NULL;) {
		if (strncmp(u->us_mname, mch_name, 7) == SAME) {
			found_mch++; 
			/* now must get login/machine match */
			if (strcmp(u->us_lname, log_name) == SAME) {
				DEBUG(4,"callcheck1 %d\n",u->us_callback);
				return(u->us_callback);
			}
			else 	{
				u = u->unext;
				continue;
				}
		}
		if (u->us_mname[0] != '\0') {
			u = u->unext;
			continue;
		}

/* machine was null, check if login matches */

		if (strcmp(u->us_lname, log_name) != SAME) {
			u = u->unext;
			continue;
		}
		found_log++;
		if (found_mch) {
/* valid login wrong machine */
			u = u->unext;
			continue;
		}
		/* have found login name with null (default) machine name */
		DEBUG(4,"callcheck2 %d\n",u->us_callback);
		return(u->us_callback);
	}

	if (found_log==0 && found_mch==0) {
		struct stat statbuf;
		/*
	       	 * login has not been specifed in USERFILE 
	         * anything goes. 
	         */
		DEBUG(4, "login not in USERFILE - %s\n", log_name);
		if (stat("/usr/lib/uucp/INSECURE",&statbuf)==0)
			return(0);
		else
			return(2);
	}
	/*
	 * userid not found -- login/machine name do not match 
	 */
	return(2);
}