		5) USERFILE array size too small


From: teklabs!ucbvax!mhtsa!eagle!harpo!duke!mcnc!unc!brl-bmd!dpk
Date: Fri Jul 30 05:47:05 1982
Subject: Fix to bug in chkpth.c - (nf)
Newsgroups: net.bugs.uucp


	At our site, the USERFILE has gotten quite large, and
we began to have weird problems with UUCP.  We began to have
problems with UUCP leaving LCK files lying around for no
apparent reason.  And finally when our USERFILE got the 20th
(or was it 21th) line, UUCICO broke entirely, with no word
as to the reason.  I later discovered that there was a limit
to the number lines (MAXUSERS (I believe) in chkpth.c). I cut
back our USERFILE.  We still had the lockfile problem, so I
looked again and discovered that although MAXUSERS was 20,
there was a hardcoded 15 for the arraysize.  rdpth() was
madly tromping all over dynamically allocated memory.  Yuck.
I was dismayed that they had hardcoded in a maximum number anyway,
so I have rewritten a good chunck of chkpth.c so that now
all memory needed is dynamically allocated and kept in a linked
list of "struct userpath".  I just made the fix, so I won't post
it yet, but if it is still bug-free by tomorrow, I will post the
part of the module that I changed to this newsgroup/notesfile.
I also want to fix the "blank line syndrome" that causes UUCICO to
fall flat on its face if there is a blank line in the USERFILE.

	Sign.  Stay tuned for futher details.

				Tired of fixing UUCP...
					Doug Kingston  <dpk>
					Ballistics Research Laboratory
					duke!unc!brl-bmd!dpk



[ Doug's new module is included below ]


From: teklabs!decvax!duke!mcnc!unc!brl-bmd!dpk
Date: Sat Jul 31 14:14:58 1982
Subject: Repaired UUCICO/chkpth.c - (nf)
Newsgroups: net.bugs.uucp
References: chkpth.c


	This is the repaired verison of chkpth.c.  The only real
changes have to do with the userpath structure, which is now handled
as a dynamically allocated linked list.  I checked the vanilla V7
and 2.8BSD distributions, and they both have this bug.  It should
only be a problem on systems with USERFILE's of 16 or more entries.
Note that although defined, DFLTNAME is not used.  Anyone have
the code implement this?

	/*  chkpth  3.1  10/26/79  11:21:30  */
	/*  Modified Doug Kingston, 30 July 82 to fix handling of	*/
	/*	of the "userpath" structures.				*/

#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;
	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 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;
{
	struct userpath *u;
	extern char *lastpart();
	char **p, *s;
	char c;
	int ret, i;

	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' && strcmp(mchname, u->us_mname) == 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);
	}

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

	if (prefix(Spool, path)) {
		if ((c = *lastpart(path)) == DATAPRE
		  || c == XQTPRE)
			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
 */

rdpth()
{
	char buf[BUFSIZ + 1], *pbuf[BUFSIZ + 1], *pc, **cp;
	char *calloc(), *index();
	FILE *uf;

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

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

		if ((u = malloc (sizeof (struct userpath))) == NULL) {
			DEBUG (1, "*** Userpath malloc failed\n", 0);
			fclose (uf);
			return;
		}
		if ((pc = calloc(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 (*u->us_lname == '\0' && Logdef == NULL)
			Logdef = u;
		else 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;
		if ((cp = u->us_path =
		  (char **) calloc(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);
	return;
}


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

callback(name)
char *name;
{
	struct userpath *u;
	int ret, i;

	if (Uptfirst) {
		rdpth();
		ASSERT(Uhead == NULL, "INIT USERFILE, No Users!", 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 0 | FAIL
 */

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

	if (stat(file, &s) != -1)
		return(0);

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

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

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

