#if	!defined(lint) && defined(DOSCCS)
static char sccsid[] = "@(#)chkpth.c	5.4.1 (2.11BSD) 1997/10/2";
#endif

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

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

/*LINTLIBRARY*/

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

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

	/* Allow only rooted pathnames.  Security wish.  rti!trt */
	if (*path != '/') {
		DEBUG(4, "filename doesn't begin with /\n", CNULL);
		return FAIL;
	}

	if (Uptfirst) {
		rdpth();
		ASSERT(Uhead != NULL, "INIT USERFILE, No entrys!", CNULL, 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, MAXBASENAME) == SAME)
			break;
		u = u->unext;
	}
	if (u == NULL) {
		if (*logname == '\0')
			u = Mchdef;
		else
			u = Logdef;
		if (u == NULL)
			return FAIL;
	}

	/*  check for /../ in path name  */
	for (s = path; *s != '\0'; s++) {
		if (prefix("/../",s)) {
			DEBUG(4, "filename has /../ in it\n", CNULL);
			return FAIL;
		}
	}

	/* Check for access permission */
	for (p = u->us_path; *p != NULL; p++)
		if (prefix(*p, path))
			return SUCCESS;
	DEBUG(4, "filename not in list\n", CNULL);

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


/***
 *	rdpth()
 *
 *	rdpth  -  this routine will read the USERFILE and
 *	construct the userpath structure pointed to by (u);
 *
 */

rdpth()
{
	char buf[100 + 1], *pbuf[50 + 1];
	register struct userpath *u;
	register char *pc, **cp;
	FILE *uf;

	if ((uf = fopen(USERFILE, "r")) == NULL) {
		/* can not open file */
		return;
	}

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

		u = (struct userpath *)malloc(sizeof (struct userpath));
		if (u == NULL) {
			DEBUG (1, "*** Userpath malloc failed\n", 0);
			fclose (uf);
			return;
		}
		if ((pc = (char *)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, 50);
		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) > MAXBASENAME)
			u->us_mname[MAXBASENAME] = '\0';
		if (*u->us_lname == '\0' && Logdef == NULL)
			Logdef = u;
		if (*u->us_mname == '\0' && Mchdef == NULL)
			Mchdef = u;
		i = 1;
		if (strcmp(pbuf[1], "c") == SAME) {
			u->us_callback = 1;
			i++;
		}
		else
			u->us_callback = 0;
		cp = (char **)calloc((unsigned)(nargs-i+1), sizeof(char *));
		if (cp == NULL) {
			/*  can not allocate space */
			DEBUG (1, "Userpath calloc 2 failed!\n", 0);
			fclose(uf);
			return;
		}
		u->us_path = cp;

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

	fclose(uf);
	return;
}

/***
 *	callback(name)	check for callback
 *	char *name;
 *
 *	return codes:
 *		0  -  no call back
 *		1  -  call back
 */

callback(name)
register char *name;
{
	register struct userpath *u;

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

	for (u = Uhead; u != NULL; ) {
		if (strcmp(u->us_lname, name) == SAME)
			/* found user name */
			return u->us_callback;
		u = u->unext;
	}

	/* userid not found */
	return 0;
}


/***
 *	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 SUCCESS | FAIL
 */

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

	if (stat(subfile(file), &s) == 0) {
		if ((s.st_mode & ANYWRITE) == 0) {
			DEBUG(4,"file is not writable: mode %o\n", s.st_mode);
			return FAIL;
		}
		return SUCCESS;
	}

	strcpy(dir, file);
	*lastpart(dir) = '\0';
	if ((ret = stat(subfile(dir), &s)) == -1 && mopt == NULL) {
		DEBUG(4, "can't stat directory %s\n", subfile(dir));
		return FAIL;
	}

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

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

/*
 * Check for sufficient privilege to request debugging.
 */
chkdebug()
{
	if (access(SYSFILE, 04) < 0) {
		fprintf(stderr, "Sorry, you must be able to read L.sys for debugging\n");
		cleanup(1);
		exit(1);	/* Just in case */
	}
}
