[net.sources] UNaXcess 0.4.4 - Part 1 of 4

allbery@ncoast.UUCP (Brandon S. Allbery) (07/26/86)

There was a whole sh*tload of bugs in 0.4.3, from which I have concluded that
trying to write a BBS without maintaining it was a big mistake.  Here is the
latest version (save for the one I'm working on now, unready as yet) of
UNaXcess; it seems to work after testing, but I suppose I'll find out soon
enough if it's broken...   :-)

---------------------------------- cut here ---------------------------------
# This is a shell archive.  Save this into a file, edit it
# and delete all lines above this comment.  Then give this
# file to sh by executing the command "sh file".  The files
# will be extracted into the current directory owned by
# you with default permissions.
#
# The files contained herein are:
#            ua.c         date.c         bull.c          sys.c
#          user.c        param.c          dir.c
#
echo 'x - ua.c'
sed 's/^X//' <<'________This_Is_The_END________' >>ua.c
X/*
X * @(#)ua.c	1.1 86/05/05 01:43:55 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)ua.c	1.1 86/05/05 01:43:55 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
X#include "ua.h"
X
Xstruct cmd
X    {
X    char c_ch;				/* command character */
X    char c_desc[33];			/* command description */
X    int (*c_exec)();			/* command executive */
X    }
X    ;					/* used for command array */
X
X/* forward references for command executives */
X
Xextern int
X	readmsg(),	readnew(),	confidx(),	enter(),
X	join(),		killmsg(),	helpme(),	scanmsg(),
X	logout(),	bulletin(),	linelen(),	shell(),
X	userctl(),	userlist(),	qscan(),	udl(),
X	unsub(),	setlconf();
X
Xstruct cmd cmdt[] =
X    {
X    '?', "Print help messages",			helpme,
X    'a', "Alter or examine a user",		userctl,
X    'b', "Reprint login bulletins",		bulletin,
X    'c', "Shell command access",		shell,
X    'd', "Set default login conference",	setlconf,
X    'e', "Enter a message",			enter,
X    'f', "File area (Downloading)",		udl,
X    'g', "Exit UNaXcess",			logout,
X    'h', "Print help messages",			helpme,
X    'i', "Index of conferences",		confidx,
X    'j', "Join a new conference",		join,
X    'k', "Kill a message",			killmsg,
X    'l', "Set line length",			linelen,
X    'n', "Read all new messages",		readnew,
X    'q', "Quick scan of messages",		qscan,
X    'r', "Read messages in a conference",	readmsg,
X    's', "Scan messages",			scanmsg,
X    'u', "Unsubscribe from a conference",	unsub,
X    'w', "List of UNaXcess users",		userlist,
X    NULL,NULL,					NULL
X    };
X
Xint nopause;
Xjmp_buf cmdloop;
X
Xmain(argc, argv)
X    char **argv;
X    {
X    char line[256], *lp;
X    short lcnt;
X    FILE *tp;
X
X    getparms();
X    chdir(parms.ua_home);
X    logon();
X    if (parms.ua_hco == 1) {
X    	printf("\nDo you wish me to stop every few lines to let you read messages (Y)? ");
X    	gets(line);
X    	log("Pause? %s", line);
X    }
X    if (parms.ua_hco == 0 || (parms.ua_hco == 1 && ToLower(line[0]) != 'n'))
X    	nopause = 0;
X    else
X    	nopause = 1;
X    alarm(parms.ua_tlimit * 60);		/* time limit */
X    signal(SIGINT, SIG_IGN);
X    signal(SIGQUIT, quit);
X    for (lcnt = 4; lcnt < SIGUSR1; lcnt++)	/* we don't muck with others */
X	signal(lcnt, logsig);
X    signal(SIGALRM, thatsall);
X    if (parms.ua_bnr[0] == '\0')
X	puts("\nWelcome to UNaXcess Version 0.04.04\nCopyright (C) 1984, 1985 by Brandon Allbery");
X    else
X    	cat(parms.ua_bnr);
X    if (argc > 2)
X	{
X	puts("To run UNaXcess from the shell, type `ua' or `ua username'.\nIf username has spaces or shell metacharacters in it, quote it.\n");
X	log("Invoked with %d arguments.  Goodbye.", argc);
X	exit(1);
X	}
X    else
X	argc--;
X    if (parms.ua_bbs[0] != '\0' && strcmp(getlogin(), parms.ua_bbs) == 0) {
X
Xnouser:
X        for (lcnt = 0; lcnt != 3; lcnt++) {
X 		if (argc) {
X			strcpy(line, argv[1]);
X	    		argc--;
X			putchar('\n');
X 		}
X		else {
X	    		if (parms.ua_login[0] == 0)
X				printf("\nEnter your user name, GUEST, OFF, or NEW: ");
X			else
X				fputs(parms.ua_login, stdout);
X			gets(line);
X		}
X	log("Login: %s", line);
X	if (line[0] == '\0')
X	    {
X	    lcnt--;
X	    continue;
X	    }
X	for (lp = line; *lp != '\0'; lp++)
X	    *lp = ToLower(*lp);
X	if (strcmp(line, "off") == 0)
X	    {
X	    puts("Goodbye...\n\n");
X	    log("Logout.");
X	    exit(0);
X	    }
X	if (!getuser(line, &user))
X	    {
X	    printf("No such user.\n");
X	    log("No such user.");
X	    }
X	else if (user.u_pass[0] != '\0')
X	    {
X	    strcpy(line, getpass("Enter your password: "));
X	    log("Password: %s", line);
X	    puts("\nChecking password...");
X	    if (strcmp(crypt(line, line) + 2, user.u_pass) == 0)
X		break;
X	    }
X	else
X	    break;
X	}
X    if (parms.ua_nla > 0 && lcnt == parms.ua_nla)
X	{
X	puts("\nSorry, you blew it.");
X	log("Program aborted.");
X	exit(1);
X	}
X    }
X    else if (!getuser(getlogin(), &user))
X    	goto nouser;
X    log("%s, access = %d, sys = %s, line = %d", user.u_name, user.u_access, user.u_login, user.u_llen);
X    if (user.u_access == A_NONE)
X	{
X	puts("Your access privileges have been revoked.  Goodbye...\n\n");
X	log("Security violation:  access revoked.");
X	exit(1);
X	}
X    if ((tp = fopen(RIndex(ttyname(fileno(stdin)), '/') + 1, "w")) == NULL)
X	{
X	log("Error %d opening %s", errno, RIndex(ttyname(fileno(stdin)), '/') + 1);
X	log("Non-interactive session not logged to terminal.");
X	}
X    else {
X	fprintf(tp, "%s on as \"%s\" on %s\n", getlogin(), user.u_name, longdate());
X	fclose(tp);
X    }
X    putchar('\n');
X    if (user.u_access != A_MKUSER)
X	bulletin(NULL);
X    umask(0);					/* so xedit() works */
X    if (user.u_lconf[0] != '\0')
X        if (isconf(user.u_lconf))
X            strcpy(conference, user.u_lconf);
X        else {
X            putchar('\n');
X            for (lp = parms.ua_sysop; *lp != '\0'; lp++)
X                putchar(ToUpper(*lp));
X            printf(" deleted \"%s\", your login conference.  I'm setting you\nback to the \"general\" conference.\n", user.u_lconf);
X            user.u_lconf[0] = '\0';
X            strcpy(conference, "general");
X        }
X    else
X        strcpy(conference, "general");
X    hicnts = readhigh(&user);
X    cleanhigh();	/* kill any lingering corpses */
X    if (!setjmp(cmdloop))
X	signal(SIGINT, intrp);
X    while (cmd())
X	;
X    printf("Goodbye, ");
X    for (lp = user.u_name; *lp != '\0'; lp++)
X	putchar(ToUpper(*lp));
X    printf(".  Call again soon!\n\n\n");
X    log("Logout.");
X    cleanup();
X    }
X
Xcleanup()
X    {
X    char tmps[256];
X    FILE *fp;
X
X    sprintf(tmps, "%s/himotd", MOTD);
X    if ((fp = fopen(tmps, "r")) == NULL)
X	{
X	log("Error %d opening %s", errno, tmps);
X	panic("himotd");
X	}
X    fgets(tmps, 32, fp);
X    fclose(fp);
X    user.u_nbull = atoi(tmps);
X    putuser(user.u_name, &user);
X    unlink(RIndex(ttyname(fileno(stdin)), '/') + 1);
X    exit(0);
X    }
X
Xcmd()
X    {
X    char line[256], *p;
X    struct cmd *cmdp;
X
X    if (user.u_access == A_MKUSER) {
X	newuser();
X	if (user.u_access == A_NONE) {
X	    puts("\nYou'll have to be validated before you can use UNaXcess.");
X	    return 0;
X	}
X    }
X    printf("\n(%s) Command (? = Help): ", conference);
X    gets(line);
X    log("Command: %s", line);
X    if (line[0] == '\0')
X	return 1;
X    for (p = line; *p != '\0'; p++)
X	*p = ToLower(*p);
X    for (cmdp = cmdt; cmdp->c_ch != NULL; cmdp++)
X	if (ToLower(cmdp->c_ch) == line[0])
X	    return (*cmdp->c_exec)(line);
X    puts("Type '?' for help.");
X    log("No such command.");
X    return 1;
X    }
X
Xlogout()
X    {
X    char line[256];
X
X    printf("Are you sure you want to log out (N)? ");
X    gets(line);
X    log("Logout? %s", line);
X    return (ToLower(line[0]) != 'y');
X    }
X
Xhelpme()
X    {
X    short lcnt;
X    struct cmd *cmdp;
X
X    putchar('\n');
X    lcnt = 2 * ((user.u_llen < 80) + 1);
X    for (cmdp = cmdt; cmdp->c_ch != NULL; cmdp++)
X	{
X	printf("%c - %-32.32s", ToUpper(cmdp->c_ch), cmdp->c_desc);
X	lcnt++;
X	if (user.u_llen < 80 || !(lcnt % 2))
X	    putchar('\n');
X	if ((lcnt / 2) % (user.u_llen >= 80? 32: 16) == 0)
X	    if (!cont())
X		break;
X	}
X    if (user.u_llen >= 80 && lcnt % 2 != 0)
X    	putchar('\n');
X    puts("\nIf you need further help, look for (or ask for) a HELP conference.");
X    return 1;
X    }
X
Xlinelen(s)
X    char *s;
X    {
X    int llen;
X    char line[256], *p;
X
X    p = s;
X    while (*p != '\0')
X	if (*p++ == ' ')
X	    if ((llen = atoi(p)) > 40 && llen < 132)
X		{
X		printf("New line length = %d.\n", llen);
X		user.u_llen = llen;
X		putuser(user.u_name, &user);
X		return 1;
X		}
X	    else
X		break;
X    llen = 0;
X    while (llen < 40 || llen > 132)
X	{
X	printf("\nEnter new line length (40-132): ");
X	gets(line);
X	llen = atoi(line);
X	}
X    return 1;
X    }
X
Xcont()
X    {
X    char ch;
X
X    if (!isatty(0) || nopause)
X	return 1;
X    printf("More (Y)? ");
X    silent();
X    ch = getchar();
X    talk();
X    log("Cont? %c", ch);
X    printf("\b \b\b \b\b \b\b \b\b \b\b \b\b \b\b \b\b \b\b \b");
X    return (int) (RIndex(" Yy\r\n", ch) != NULL);
X    	/* the above cast is because Plexus pcc is stupid! */
X    }
X
Xcat(file)
X    char *file;
X    {
X    FILE *f;
X    char ch;
X    short lcnt, ccnt;
X
X    if ((f = fopen(file, "r")) == NULL)
X	{
X	log("Error %d opening %s", errno, file);
X	puts("Cannot open file.");
X	return;
X	}
X    lcnt = ccnt = 0;
X    while ((ch = getc(f)) != EOF)
X	{
X	if (ch == '\n')
X	    {
X	    putchar(ch);
X	    ccnt = 0;
X	    if (++lcnt % 16 == 0)
X		if (!cont())
X		    break;
X	    }
X	else if (ch == '\t')
X		putchar('\t');
X	else
X	    {
X	    if (iscntrl(ch))
X		putchar('.');
X	    else
X		putchar(ch);
X	    if (++ccnt == (user.u_llen<40? 80: user.u_llen) - 1)
X		{
X		ccnt = 0;
X		putchar('\n');
X		if (++lcnt % 16 == 0)
X		    if (!cont())
X			break;
X		}
X	    }
X	}
X    fclose(f);
X    }
________This_Is_The_END________
echo 'x - date.c'
sed 's/^X//' <<'________This_Is_The_END________' >>date.c
X/*
X * @(#)date.c	1.1 86/05/05 01:43:38 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)date.c	1.1 86/05/05 01:43:38 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
X#ifdef BSD
X#include <sys/time.h>
X#else
X#include <time.h>
X#endif BSD
X
Xstatic char *month[] =
X    {
X	"January",	"February",	"March",	"April",
X	"May",		"June",		"July",		"August",
X	"September",	"October",	"November",	"December"
X    };
X
Xstatic char *wkday[] =
X    {
X	"Sunday",	"Monday",	"Tuesday",	"Wednesday",
X	"Thursday",	"Friday",	"Saturday"
X    };
X
Xstruct tm *localtime();
X
Xchar *date()
X    {
X    long clock;
X    struct tm *ltbuf;
X    static char tbuf[18];
X
X    time(&clock);
X    ltbuf = localtime(&clock);
X    sprintf(tbuf, "%02d/%02d/%02d %02d:%02d:%02d", ltbuf->tm_mon + 1, ltbuf->tm_mday, ltbuf->tm_year, ltbuf->tm_hour, ltbuf->tm_min, ltbuf->tm_sec);
X    return tbuf;
X    }
X
Xchar *longdate()
X    {
X    long clock;
X    struct tm *ltbuf;
X    static char tbuf[80];
X    short hour;
X    char ampm;
X
X    time(&clock);
X    ltbuf = localtime(&clock);
X    if (ltbuf->tm_hour == 0)
X	{
X	hour = 12;
X	ampm = 'A';
X	}
X    else if (ltbuf->tm_hour < 12)
X	{
X	hour = ltbuf->tm_hour;
X	ampm = 'A';
X	}
X    else if (ltbuf->tm_hour == 12)
X	{
X	hour = 12;
X	ampm = 'P';
X	}
X    else
X	{
X	hour = ltbuf->tm_hour - 12;
X	ampm = 'P';
X	}
X    sprintf(tbuf, "%s, %s %d, 19%02d - %d:%02d %cM", wkday[ltbuf->tm_wday], month[ltbuf->tm_mon], ltbuf->tm_mday, ltbuf->tm_year, hour, ltbuf->tm_min, ampm);
X    return tbuf;
X    }
________This_Is_The_END________
echo 'x - bull.c'
sed 's/^X//' <<'________This_Is_The_END________' >>bull.c
X/*
X * @(#)bull.c	1.1 86/05/05 01:43:32 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)bull.c	1.1 86/05/05 01:43:32 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
X#include "ua.h"
X
Xbulletin(s)
X    char *s;
X    {
X    short mcnt, himotd;
X    char tmps[256];
X    FILE *fp;
X
X    if (user.u_access == A_MKUSER)
X    	return;
X    sprintf(tmps, "%s/himotd", MOTD);
X    if ((fp = fopen(tmps, "r")) == NULL)
X	{
X	log("Error %d opening %s", errno, tmps);
X	panic("himotd");
X	}
X    fgets(tmps, 32, fp);
X    fclose(fp);
X    himotd = atoi(tmps);
X    for (mcnt = (strcmp(user.u_name, "guest") == 0? 0: user.u_nbull + 1); mcnt <= himotd; mcnt++)
X	{
X	sprintf(tmps, "%s/%d", MOTD, mcnt);
X	if (!readmotd(tmps, mcnt))
X	    break;
X	}
X    }
X
Xreadmotd(motd, mnum)
X    char *motd;
X    short mnum;
X    {
X    char line[256];
X
X    printf("Bulletin #%d:\n", mnum);
X    cat(motd);
X    printf("\nContinue or Stop (C)? ");
X    if (!isatty(0) || nopause)
X	{
X	putchar('\n');
X	line[0] = '\0';
X	}
X    else
X	gets(line);
X    log("C/S? %s", line);
X    return ToLower(line[0]) != 's';
X    }
________This_Is_The_END________
echo 'x - sys.c'
sed 's/^X//' <<'________This_Is_The_END________' >>sys.c
X/*
X * @(#)sys.c	1.1 86/05/05 01:43:49 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)sys.c	1.1 86/05/05 01:43:49 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
X#include "ua.h"
X
Xstatic FILE *lfp;
X
Xshort critical = 0;
X
Xshort quitc = 0;
Xshort intr = 0;
Xshort alrm = 0;
X
Xshort shhh = 0;
X
Xshort warned = 0;
X
X#ifdef SYS3
X#include <sys/ioctl.h>
X#include <termio.h>
Xstruct termio mode;
X#else
X#include <sgtty.h>
X#ifndef V7
X#include <sys/ioctl.h>
X#endif
Xstruct sgttyb mode;
X#endif
X
Xlogon()
X    {
X    struct stat sb;
X    char *cp;
X
X    	/* first set up ttymode structure */
X#ifdef SYS3
X    ioctl(0, TCGETA, &mode);
X#else
X#ifdef V7
X    gtty(0, &mode);
X#else
X    ioctl(0, TIOCGETP, &mode);
X#endif
X#endif
X
X    if (parms.ua_env) {
X    	if ((cp = getenv("SHELL")) != NULL)
X    		strcpy(parms.ua_shell, cp);
X    	if ((cp = getenv("EDITOR")) != NULL)
X    		strcpy(parms.ua_edit, cp);
X    }
X    
X    if (!parms.ua_log || stat(LOG, &sb) < 0)		/* no logfile => no logging */
X	{
X	lfp = NULL;
X	return;
X	}
X    if ((lfp = fopen(LOG, "a")) == NULL)
X	{
X	perror(LOG);
X	puts("panic: log");
X	exit(2);
X	}
X    }
X
Xlog(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
X    char *fmt, *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8, *a9;
X    {
X    char buf[1024];
X    static char lockfile[] = "logfile.lock";
X
X    if (lfp == NULL)			/* logging not enabled */
X	return;
X    CRIT();
X    sprintf(buf, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
X    mklock(lockfile);
X    fprintf(lfp, "%s (%05d)  %s\n", date(), getpid(), visible(buf));
X    fflush(lfp);
X    rmlock(lockfile);
X    NOCRIT();
X    }
X
Xlogsig(sig)
X    int sig;
X    {
X    log("Received signal %d.", sig);
X    fprintf(stderr, "\n\nUNaXcess internal error: %d.\n", sig);
X    unlink(RIndex(ttyname(fileno(stdin)), '/') + 1);
X    signal(SIGIOT, SIG_DFL);
X    abort();
X    }
X
Xpanic(s)
X    char *s;
X    {
X    log("panic: %s", s);
X    fprintf(stderr, "panic: %s\n", s);
X    unlink(RIndex(ttyname(2), '/') + 1);
X    exit(1);
X    }
X
Xquit()
X    {
X    char line[256];
X
X    if (critical) {
X    	quitc++;
X    	return;
X    }
X    puts("\n\nFast logout\n");
X    signal(SIGQUIT, quit);
X    log("Signalled QUIT.");
X    printf("\nDo you really want to leave UNaXcess (N)? ");
X    gets(line);
X    if (ToLower(line[0]) == 'y')
X	{
X	printf("OK, %s.  See you later!\n\n\n", user.u_name);
X	cleanup();
X	}
X    }
X
Xintrp()
X    {
X    if (critical) {
X    	intr++;
X    	return;
X    }
X    puts("\n\nAborted.");
X    log("Command aborted.");
X    signal(SIGINT, intrp);
X    longjmp(cmdloop, 1);
X    }
X
Xchar *visible(s)
X    char *s;
X    {
X    static char vs[256];
X    char *sp, *vp;
X
X    vp = vs;
X    for (sp = s; *sp != '\0'; sp++)
X	if (!iscntrl(*sp))
X	    *vp++ = *sp;
X	else
X	    {
X	    *vp++ = '^';
X	    *vp++ = uncntrl(*sp);
X	    }
X    *vp = '\0';
X    return vs;
X    }
X
Xshell()
X    {
X    short sig;
X    unsigned altime;
X
X    if (user.u_access == A_GUEST || user.u_access == A_USER || parms.ua_shell[0] == '\0')
X	{
X	puts("You don't have shell access privileges.");
X	log("Security violation:  Unauthorized SHELL");
X	return 1;
X	}
X    switch (fork())
X	{
X	case -1:
X	    log("Error %d forking shell", errno);
X	    puts("Sorry, the system's full.  Try again later.");
X	    return 1;
X	case 0:
X	    for (sig = 2; sig < SIGUSR1; sig++)
X		signal(sig, SIG_DFL);
X	    setuid(getuid());
X	    chdir(getpwuid(getuid())->pw_dir);
X	    run(parms.ua_shell, 0);
X	    log("Error %d exec'ing %s", errno, parms.ua_shell);
X	    puts("Couldn't run the shell.");
X	    exit(1);
X	default:
X	    CRIT();
X	    for (sig = 2; sig < SIGUSR1; sig++)
X		signal(sig, SIG_IGN);
X	    signal(SIGALRM, thatsall);	/* trapped by the CRIT() */
X	    wait(NULL);
X	    signal(SIGINT, intrp);
X	    signal(SIGQUIT, quit);
X	    for (sig = 4; sig < SIGUSR1; sig++)
X		signal(sig, logsig);
X	    signal(SIGALRM, thatsall);
X	    NOCRIT();
X	}
X    return 1;
X    }
X
Xthatsall()
X    {
X    if (critical) {
X    	alrm++;
X    	return;
X    }
X    if (warned) {
X        log("Timeout.");
X        puts("\nI'm sorry, but you're out of time.\n\n");
X        cleanup();
X        }
X    else 
X        {
X    	log("5-minute warning.");
X    	puts("\nYou have only five minutes left in this session.\n\n");
X    	warned = 1;
X    	alarm(5 * 60);
X        }
X    }
X
X/*
X * I've had problems with this.  If it breaks, delete the innards of the lock
X * functions.  Hopefully, I got it right this time...
X */
X
Xmklock(lockfile)
Xchar *lockfile; {
X    char lockpath[50];
X    int lock_fd;
X    struct stat statbuf;
X    long now;
X    
X    strcpy(lockpath, "lock/");
X    strcat(lockpath, lockfile);
X    while (stat(lockpath, &statbuf) == 0) {
X    	time(&now);
X        if (now - statbuf.st_atime > 60) {
X            unlink(lockpath);
X            break;
X        }
X    }
X    if ((lock_fd = creat(lockpath, 0600)) < 0) {
X        fprintf(stderr, "Errno = %d creating lockfile %s\n", errno, lockpath);
X        exit(-1);
X    }
X    close(lock_fd);
X}
X
Xrmlock(lockfile)
Xchar *lockfile; {
X    char lockpath[50];
X    struct stat statbuf;
X    
X    strcpy(lockpath, "lock/");
X    strcat(lockpath, lockfile);
X    if (stat(lockpath, &statbuf) < 0) {
X        log("Lockfile %s deleted???", lockpath);
X        printf("\n\nSomeone futzed with the lockfile.  Please tell %s IMMEDIATELY!!!\nSorry, but this means I have to log you out now.\n\n", parms.ua_sysop);
X        panic("LOCKFILE DELETED");
X    }
X    if (unlink(lockpath) < 0) {
X        log("Errno = %d, can't unlink lockfile %s", errno, lockpath);
X        puts("\nI've got a lockfile problem.  You won't be able to do some\nthings until it's fixed.  Sorry...\n");
X    }
X}
X
Xxedit(file)
X    char *file;
X    {
X    short sig;
X    unsigned altime;
X
X    if (user.u_access == A_GUEST || user.u_access == A_USER || parms.ua_edit[0] == '\0')
X	{
X	puts("You don't have shell access privileges.");
X	log("Security violation:  Unauthorized XEDIT");
X	return 1;
X	}
X    if (strcmp(parms.ua_edit, "ua-edit") == 0) {
X    	edit(file);
X    	return 1;
X    }
X    switch (fork())
X	{
X	case -1:
X	    log("Error %d forking shell", errno);
X	    puts("Sorry, the system's full.  Using the line editor...");
X	    edit(file);
X	    return 1;
X	case 0:
X	    for (sig = 2; sig < SIGUSR1; sig++)
X		signal(sig, SIG_DFL);
X	    setuid(getuid());
X	    chdir(getpwuid(getuid())->pw_dir);
X	    run(parms.ua_edit, file);
X	    log("Error %d exec'ing %s", errno, parms.ua_edit);
X	    puts("Couldn't run the editor; using the line editor...");
X	    edit(file);
X	    exit(0);
X	default:
X	    CRIT();
X	    for (sig = 2; sig < SIGUSR1; sig++)
X		signal(sig, SIG_IGN);
X	    signal(SIGALRM, thatsall);
X	    wait(NULL);
X	    signal(SIGINT, intrp);
X	    signal(SIGQUIT, quit);
X	    for (sig = 4; sig < SIGUSR1; sig++)
X		signal(sig, logsig);
X	    signal(SIGALRM, thatsall);
X	    NOCRIT();
X	}
X    return 1;
X    }
X
XCRIT() {
X	alrm = 0;
X	quitc = 0;
X	intr = 0;
X	if (critical)
X		return;	/* clears pending signals */
X	critical = 1;
X}
X
XNOCRIT() {
X	if (!critical)
X		return;
X	critical = 0;
X	if (alrm)
X		thatsall(14);
X	if (quitc)
X		quit(3);
X	if (intr)
X		intrp(2);
X	alrm = 0;
X	quitc = 0;
X	intr = 0;
X}
X
Xrun(cmd, arg)
Xchar *cmd, *arg; {
X	char cmdbuf[5120];
X	
X	sprintf(cmdbuf, "%s %s", cmd, (arg? arg: ""));
X	execl("/bin/sh", "sh", "-c", cmdbuf, 0);
X	return -1;
X}
X
Xsilent() {
X	if (shhh)
X		return;
X#ifdef SYS3
X	mode.c_lflag &= ~(ICANON|ISIG|ECHO|ECHOE|ECHOK);
X	mode.c_cc[VMIN] = 1;
X	mode.c_cc[VTIME] = 0;
X	ioctl(0, TCSETAW, &mode);
X#else
X	mode.sg_flags |= CBREAK;
X	mode.sg_flags &= ~ECHO;
X#ifdef V7
X	stty(0, &mode);
X#else
X	ioctl(0, TIOCSETP, &mode);
X#endif
X#endif
X	shhh = 1;
X}
X
Xtalk() {
X	if (!shhh)
X		return;
X#ifdef SYS3
X	mode.c_lflag |= (ICANON|ISIG|ECHO|ECHOE|ECHOK);
X	mode.c_cc[VEOF] = CEOF;
X	mode.c_cc[VEOL] = CNUL;
X	ioctl(0, TCSETAW, &mode);
X#else
X	mode.sg_flags |= ECHO;
X	mode.sg_flags &= ~CBREAK;
X#ifdef V7
X	stty(0, &mode);
X#else
X	ioctl(0, TIOCSETP, &mode);
X#endif
X#endif
X	shhh = 0;
X}
X
Xcopylink(src, dest)
Xchar *src, *dest; {
X	int srcp, destp, cnt;
X	char buf[1024];
X	
X	if (link(src, dest) == 0) {
X		unlink(src);
X		return 0;
X	}
X	if ((srcp = open(src, 0)) < 0) {
X		perror(src);
X		return -1;
X	}
X	unlink(dest);
X	if ((destp = creat(dest, 0600)) < 0) {
X		perror(dest);
X		return -1;
X	}
X	while ((cnt = read(srcp, buf, sizeof buf)) > 0)
X		write(destp, buf, cnt);
X	close(destp);
X	close(srcp);
X	return 0;
X}
________This_Is_The_END________
echo 'x - user.c'
sed 's/^X//' <<'________This_Is_The_END________' >>user.c
X/*
X * @(#)user.c	1.1 86/05/05 01:44:07 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)user.c	1.1 86/05/05 01:44:07 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
X#include "ua.h"
X
Xstruct user user;
Xstruct _himsg *hicnts;
X
Xgetuser(name, buf)
Xchar *name;
Xstruct user *buf; {
X	FILE *bfd;
X	char line[1024], lcuname[33], *p, *q;
X	int ncolon;
X
X	if ((bfd = fopen(PASSWD, "r")) == NULL) {
X		log("Error %d opening %s", errno, PASSWD);
X		panic("passwd");
X	}
X	for (p = name, q = lcuname; *p != '\0' && p - name <= 32; p++, q++)
X		*q = ToLower(*p);
X	*q = '\0';
X	while (fgets(line, sizeof line, bfd) != NULL)
X		if (strncmp(line, lcuname, strlen(lcuname)) == 0 && line[strlen(lcuname)] == ':') {
X			fclose(bfd);
X			buf->u_name[0] = '\0';
X			buf->u_pass[0] = '\0';
X			buf->u_access = 0;
X			buf->u_login[0] = '\0';
X			buf->u_llen = 0;
X			buf->u_nbull = 0;
X			buf->u_lconf[0] = '\0';
X			ncolon = 0;
X			for (p = line; *p != '\0'; p++)
X				if (*p == ':')
X					ncolon++;
X			if (ncolon < 5) {
X				log("Bad userfile entry for %s", lcuname);
X				return 0;
X			}
X			for (p = line, q = buf->u_name; *p != ':'; p++, q++)
X				*q = *p;
X			*q = '\0';
X			for (p++, q = buf->u_pass; *p != ':'; p++, q++)
X				*q = *p;
X			*q = '\0';
X			for (p++, q = lcuname; *p != ':'; p++, q++)
X				*q = *p;
X			*q = '\0';
X			buf->u_access = atoi(lcuname);
X			for (p++, q = buf->u_login; *p != ':'; p++, q++)
X				*q = *p;
X			*q = '\0';
X			for (p++, q = lcuname; *p != ':'; p++, q++)
X				*q = *p;
X			*q = '\0';
X			buf->u_llen = atoi(lcuname);
X			for (p++, q = lcuname; *p != ':'; p++, q++)
X				*q = *p;
X			*q = '\0';
X			buf->u_nbull = atoi(lcuname);
X			for (p++, q = buf->u_lconf; *p != '\n'; p++, q++)
X				*q = *p;
X			*q = '\0';
X			return 1;
X		}
X	fclose(bfd);
X	return 0;
X}
X
Xputuser(name, ubuf)
X    char *name;
X    struct user *ubuf;
X    {
X    FILE *fd, *tfd;
X    char line[1024], *tempfile = mktemp("/tmp/UptXXXXXX"), lcname[33], *p, *q;
X    static char lockfile[] = "userfil.lock";
X    short flag;
X
X    CRIT();
X    mklock(lockfile);
X    if ((fd = fopen(PASSWD, "r")) == NULL)
X	{
X	log("Error %d opening %s", errno, PASSWD);
X	panic("passwd");
X	}
X    if ((tfd = fopen(tempfile, "w")) == NULL)
X	{
X	log("Error %d opening %s", errno, tempfile);
X	panic("tmp");
X	}
X    flag = 0;
X    for (p = name, q = lcname; *p != '\0' && p - name < 33; p++, q++)
X	*q = ToLower(*p);
X    *q = 0;
X    while (fgets(line, sizeof line, fd) != NULL)
X	if (strncmp(line, lcname, strlen(lcname)) == 0 && line[strlen(lcname)] == ':')
X	    {
X	    fprintf(tfd, "%s:%s:%d:%s:%d:%d:%s\n", ubuf->u_name, ubuf->u_pass, ubuf->u_access, ubuf->u_login, ubuf->u_llen, (s_cmp(ubuf->u_name, "guest") == 0? 0: ubuf->u_nbull), (s_cmp(ubuf->u_name, "guest") == 0? "": ubuf->u_lconf));
X	    flag++;
X	    }
X	else
X	    fputs(line, tfd);
X    if (!flag)
X	fprintf(tfd, "%s:%s:%d:%s:%d:%d:%s\n", ubuf->u_name, ubuf->u_pass, ubuf->u_access, ubuf->u_login, ubuf->u_llen, (s_cmp(ubuf->u_name, "guest") == 0? 0: ubuf->u_nbull), (s_cmp(ubuf->u_name, "guest") == 0? "": ubuf->u_lconf));
X    fclose(fd);
X    fclose(tfd);
X    unlink(PASSWD);
X    if (copylink(tempfile, PASSWD) < 0)
X	{
X	log("Error %d copylinking %s to %s", errno, tempfile, PASSWD);
X	panic("copylink");
X	}
X    unlink(tempfile);
X    rmlock(lockfile);
X    NOCRIT();
X    }
X
Xwritehigh(hilist)
X    struct _himsg *hilist;
X    {
X    FILE *hp, *f;
X    static char line[1024], hirec[1024];	/* 68000's have limited frames */
X    char *tmpf = mktemp("/tmp/RcXXXXXX");
X    char *eofflag;
X    static char lockfile[] = "newmsgs.lock";
X    struct _himsg *hptr;
X
X    if (s_cmp(user.u_name, "guest") == 0)
X        return;	/* don't write GUEST hirecs! */
X    CRIT();
X    if ((f = fopen(tmpf, "w")) == NULL)
X	{
X	log("Error %d opening %s", errno, tmpf);
X	panic("tmp");
X	}
X    if ((hp = fopen(NEWMSGS, "r")) == NULL)
X	{
X	log("Error %d opening %s", errno, NEWMSGS);
X	fclose(f);
X	unlink(tmpf);
X	panic("userind");
X	}
X    mklock(lockfile);
X    sprintf(line, "%s:", user.u_name);
X    while ((eofflag = fgets(hirec, sizeof hirec, hp)) != NULL) {
X	if (strncmp(hirec, line, strlen(line)) == 0)
X	    break;
X	fputs(hirec, f);
X    }
X    if (eofflag != NULL)
X        while ((eofflag = fgets(hirec, sizeof hirec, hp)) != NULL)
X            if (hirec[0] != '\t' && hirec[0] != ' ')
X       	        break;
X    fputs(line, f);
X    putc('\n', f);
X    for (hptr = hilist; hptr != NULL; hptr = hptr->hi_next)
X        fprintf(f, "\t%s%c %d\n", hptr->hi_conf, (hptr->hi_uns == HI_UNSUB? '!': ':'), hptr->hi_num);
X    if (eofflag != NULL && hirec[0] != '\t' && hirec[0] != ' ')
X        fputs(hirec, f);
X    if (eofflag != NULL)
X        while (fgets(hirec, sizeof hirec, hp) != NULL)
X            fputs(hirec, f);
X    fclose(f);
X    fclose(hp);
X    unlink(NEWMSGS);
X    if (copylink(tmpf, NEWMSGS) < 0)
X	{
X	log("Error %d copylinking %s to %s", errno, tmpf, NEWMSGS);
X	panic("copylink");
X	}
X    unlink(tmpf);
X    rmlock(lockfile);
X    NOCRIT();
X    }
X
Xstruct _himsg *readhigh(foruser)
X    struct user *foruser;
X    {
X    static char hirec[1024];
X    char uidx[40], *p, *q;
X    FILE *f;
X    struct _himsg *workp, *initp, *lastp;
X
X    strcpy(uidx, foruser->u_name);
X    strcat(uidx, ":");
X    if ((f = fopen(NEWMSGS, "r")) == NULL)
X	return NULL;
X    while (fgets(hirec, sizeof hirec, f) != NULL)
X	if (strncmp(hirec, uidx, strlen(uidx)) == 0)
X	    break;
X    if (feof(f))
X	{
X	fclose(f);
X	return NULL;
X	}
X    workp = NULL;
X    initp = NULL;
X    while (fgets(hirec, sizeof hirec, f) != NULL && (hirec[0] == ' ' || hirec[0] == '\t')) {
X    	hirec[strlen(hirec) - 1] = '\0';
X	for (p = hirec; *p == ' ' || *p == '\t'; p++)
X            ;
X        for (q = uidx; *p != ' ' && *p != '\t' && *p != '\0' && *p != ':' && *p != '!'; p++)
X	    *q++ = *p;
X	*q = '\0';
X	while (*p == ' ' || *p == '\t')
X	    p++;
X    	if (*p == '!') {	/* unsubscribed... */
X	    if ((workp = (struct _himsg *) calloc((unsigned) 1, sizeof (struct _himsg))) == NULL)
X	        {
X	        log("Error %d allocating _himsg for %s", errno, uidx);
X	        panic("alloc");
X	        }
X	    strcpy(workp->hi_conf, uidx);
X	    workp->hi_num = atoi(++p);
X	    workp->hi_next = initp;
X	    workp->hi_uns = HI_UNSUB;
X	    initp = workp;
X	    continue;
X    	}
X	if (*p != ':') {
X	    log("Invalid format of userind record: ``%s''", hirec);
X	    puts("Your index is garbled; some conference\nhigh-message counts may be lost.");
X	    break;
X	}
X	if ((workp = (struct _himsg *) calloc((unsigned) 1, sizeof (struct _himsg))) == NULL)
X	    {
X	    log("Error %d allocating _himsg for %s", errno, uidx);
X	    panic("alloc");
X	    }
X	strcpy(workp->hi_conf, uidx);
X	workp->hi_num = atoi(++p);
X	workp->hi_next = initp;
X	workp->hi_uns = HI_SUBSCR;
X	initp = workp;
X	}
X    fclose(f);
X    return initp;
X    }
X
Xnewuser()
X    {
X    struct user nubuf, junk;
X    char line[256], *p;
X
X    log("Entered newuser module.");
X    cat(NEWUSER);
X
XAgain:
X    printf("\nDo you still want to become a user (N)? ");
X    gets(line);
X    log("Become user? %s", line);
X    if (ToLower(line[0]) != 'y')
X	return;
X    do
X	{
X	printf("What name would you like to use on this system?  It should not be\nmore than 32 letters long: ");
X	gets(line);
X	log("Name: %s", line);
X	if (line[0] == '\0' || line[0] == ' ')
X	    {
X	    line[0] = '?';
X	    p = line;
X	    continue;
X	    }
X	for (p = line; *p != '\0'; p++)
X	    if (*p == ':')
X		{
X		puts("Sorry, no colons allowed; they cause nasty surprises.");
X		log("Illegal colon in name");
X		break;
X		}
X	}
X	while (*p != NULL);
X    strncpy(nubuf.u_name, line, 32);
X    nubuf.u_name[32] = '\0';
X    line[0] = '\0';
X    do
X	{
X	if (line[0] != 0)
X	    puts("You made a typing error.");
X	strcpy(line, getpass("Please enter a password of three to eight characters.\nIt will not be displayed: "));
X	log("Pass: %s", line);
X	}
X	while (strlen(line) < 3 || strcmp(line, getpass("Please re-enter it, just to make sure: ")) != 0);
X    strcpy(nubuf.u_pass, line);
X    do
X	{
X	printf("How many characters per line are on your terminal?\nPlease enter a number from 40 to 132, or <ENTER> for 80: ");
X	gets(line);
X	log("Line: %s", line);
X	if (line[0] == '\0')
X	    nubuf.u_llen = 80;
X	else
X	    nubuf.u_llen = atoi(line);
X	}
X	while (nubuf.u_llen < 40 || nubuf.u_llen > 132);
X    printf("\nName:\t%s\nPass:\t%s\nLine:\t%d\n\nIs this correct (N)? ", nubuf.u_name, nubuf.u_pass, nubuf.u_llen);
X    gets(line);
X    log("Okay? %s", line);
X    if (ToLower(line[0]) != 'y')
X	goto Again;
X    puts("Encrypting password, please wait...");
X    strcpy(nubuf.u_pass, crypt(nubuf.u_pass, nubuf.u_pass) + 2);
X    strcpy(nubuf.u_login, user.u_login);/* default login name ( guest ?) */
X    nubuf.u_access = user.u_llen;	/* since we don't use u_llen here */
X    nubuf.u_nbull = 0;			/* no bulletins read yet */
X    puts("Recording user information...");
X    for (p = nubuf.u_name; *p != '\0'; p++)
X	*p = ToLower(*p);
X    if (getuser(nubuf.u_name, &junk))
X	{
X	puts("Sorry, but that name's already in use.  Please choose another.");
X	goto Again;
X	}
X    putuser(nubuf.u_name, &nubuf);
X    user = nubuf;
X    }
X
Xuserctl(s)
X    char *s;
X    {
X    char line[256], *p, *q;
X    struct user ubuf;
X    short cflag, pflag;
X
X    if (user.u_access != A_WITNESS)
X	{
X	if (strcmp(user.u_name, "guest") == 0) {
X	    log("Security violation:  userctl by GUEST");
X	    puts("Sorry, but GUEST can't change himself.");
X	    return 1;
X	}
X	pflag = 1;
X	log("Userctl by non-Witness; restricting control modes.");
X	puts("Since you're not a Fairwitness, you can only change some things about\nyourself, like your password.");
X	strcpy(line, user.u_name);
X	}
X    else
X	{
X	line[0] = '\0';
X	pflag = 0;
X	for (p = s; *p != '\0'; p++)
X	    if (*p == ' ')
X		{
X		strcpy(line, ++p);
X		break;
X		}
X	if (line[0] == '\0')
X	    {
X	    printf("Examine which user: ");
X	    gets(line);
X	    log("User: %s", line);
X	    if (line[0] == '\0')
X		return 1;
X	    for (p = line; *p != '\0'; p++)
X		*p = ToLower(*p);
X	    }
X	line[32] = '\0';
X	}
X    if (!getuser(line, &ubuf))
X	if (pflag)
X	    {
X	    log("Can't locate current user in the userfile.");
X	    panic("user");
X	    }
X	else
X	    {
X	    printf("No such user.  Create him (N)? ");
X	    strcpy(ubuf.u_name, line);
X	    gets(line);
X	    log("New user? %s", line);
X	    if (ToLower(line[0]) != 'y')
X		return 1;
X	    ubuf.u_pass[0] = '\0';
X	    ubuf.u_access = A_USER;
X	    ubuf.u_llen = 80;
X	    ubuf.u_nbull = 0;
X	    cflag = 0;
X	    }
X    else if (strlen(ubuf.u_pass) == 0)
X	cflag = 0;
X    else
X	cflag = 1;
X    for (;;)
X	{
X	printf("\nName:\t%s\nPass:\t%s%s\nAccess:\t%s\n%s:\t%d\nLogin conference: %s\n\nChange Name, Pass, Access, Login, %s,\nDefault Login Conference; Quit; or Save: ", ubuf.u_name, ubuf.u_pass,
X	    (cflag? " (encrypted)": ""), (ubuf.u_access==A_NONE? "None": (ubuf.u_access==A_GUEST? "Guest": (ubuf.u_access==A_USER? "Ordinary user": (ubuf.u_access==A_SYSTEM? "System": (ubuf.u_access==A_FILES? "Files":
X	    (ubuf.u_access==A_WITNESS? "Fairwitness": "User maker")))))), (ubuf.u_access==A_MKUSER? "DftAxs": "Width"), ubuf.u_llen, ubuf.u_lconf, (ubuf.u_access==A_MKUSER? "Default Access": "Width"));
X	gets(line);
X	log("Change: %s", line);
X	switch (line[0])
X	    {
X	    case 'N':
X	    case 'n':
X		if (pflag)
X		    {
X		    log("Security violation: Attempted to change name.");
X		    puts("You can't do that.");
X		    break;
X		    }
X		printf("Enter new name: ");
X		gets(line);
X		log("Name: %s", line);
X		if (line[0] == '\0')
X		    break;
X		for (p = line; *p != '\0'; p++)
X		    if (*p == ':')
X			{
X			log("Illegal colon in name.");
X			puts("Can't put a colon in a user name.");
X			break;
X			}
X		for (p = line, q = ubuf.u_name; *p != '\0'; p++, q++)
X		    *q = ToLower(*p);
X		*q = '\0';
X		break;
X	    case 'P':
X	    case 'p':
X		strcpy(line, getpass("Enter new password: "));
X		if (line[0] == '\0')
X		    break;
X		strcpy(ubuf.u_pass, line);
X		cflag = 0;		/* it's not encrypted now */
X		break;
X	    case 'A':
X	    case 'a':
X		if (pflag)
X		    {
X		    log("Security violation: Attempted to change access level.");
X		    puts("You can't do that.");
X		    break;
X		    }
X		printf("Access: None, Guest, User, Files, System, Witness, Makeuser? ");
X		gets(line);
X		log("Access: %s", line);
X		if ((ToLower(line[0]) == 'a' || ubuf.u_access == A_WITNESS) && strcmp(user.u_name, SYSOP) != 0)
X		    {
X		    puts("Sorry, only the sysop can administer Witness privileges.");
X		    log("Security violation: WITNESS administering WITNESS");
X		    break;
X		    }
X		switch (line[0])
X		    {
X		    case 'g':
X		    case 'G':
X			ubuf.u_access = A_GUEST;
X			break;
X		    case 'n':
X		    case 'N':
X			ubuf.u_access = A_NONE;
X			break;
X		    case '\0':
X			break;
X		    case 'u':
X		    case 'U':
X			ubuf.u_access = A_USER;
X			break;
X		    case 's':
X		    case 'S':
X			ubuf.u_access = A_SYSTEM;
X			break;
X		    case 'w':
X		    case 'W':
X			ubuf.u_access = A_WITNESS;
X			break;
X		    case 'm':
X		    case 'M':
X			ubuf.u_access = A_MKUSER;
X			break;
X		    case 'f':
X		    case 'F':
X		        ubuf.u_access = A_FILES;
X		        break;
X		    default:
X			puts("What?  Access unchanged.");
X		    }
X		break;
X            case 'D':
X            case 'd':
X                printf("Enter the default login conference: ");
X                gets(line);
X                log("Login conference: %s", line);
X                if (!isconf(line))
X                    puts("That conference doesn't exist.");
X                else if (uisunsub(ubuf.u_name, line))
X                    printf("%s isn't subscribed to %s.\n", ubuf.u_name, line);
X                else
X                    strcpy(ubuf.u_lconf, line);
X                break;
X	    case 'W':
X	    case 'w':
X		if (ubuf.u_access == A_MKUSER) {
X		    printf("Default Access: None, Guest, User, Files, System? ");
X		    gets(line);
X		    log("DftAxs: %s", line);
X		    if (ToLower(line[0]) == 'a') {
X		        puts("I don't think you really want to make every user a Fairwitness.");
X		        log("Security violation: DftAxs == A_WITNESS?");
X		        break;
X		    }
X		    switch (line[0]) {
X		        case 'g':
X		        case 'G':
X			    ubuf.u_llen = A_GUEST;
X			    break;
X		        case 'n':
X		        case 'N':
X			    ubuf.u_llen = A_NONE;
X			    break;
X		        case '\0':
X			    break;
X		        case 'u':
X		        case 'U':
X			    ubuf.u_llen = A_USER;
X			    break;
X		        case 's':
X		        case 'S':
X			    ubuf.u_access = A_SYSTEM;
X			    break;
X		        case 'm':
X		        case 'M':
X			    puts("Default access is user maker???");
X			    log("Attempted to make default access == MAKEUSER?");
X			    break;
X		        case 'f':
X		        case 'F':
X		            ubuf.u_access = A_FILES;
X		            break;
X		        default:
X			    puts("What?  Default access unchanged.");
X		    }
X		}
X		else {
X		    printf("Enter new line length, 40-132: ");
X		    gets(line);
X		    log("Line length: %s", line);
X		    if (line[0] == '\0')
X		        break;
X		    ubuf.u_llen = atoi(line);
X		}
X		break;
X	    case 'Q':
X	    case 'q':
X		printf("Abort user examine, are you sure (N)? ");
X		gets(line);
X		log("Abort? %s", line);
X		if (ToLower(line[0]) != 'y')
X		    break;
X		return 1;
X	    case 'S':
X	    case 's':
X		if (!cflag)
X		    {
X		    puts("Encrypting password, please wait...");
X		    strcpy(ubuf.u_pass, crypt(ubuf.u_pass, ubuf.u_pass) + 2);
X		    }
X		putuser(ubuf.u_name, &ubuf);
X		if (strcmp(ubuf.u_name, user.u_name) == 0)
X		    user = ubuf;
X		return 1;
X	    default:
X		puts("What?  Please enter one of N, P, L, A, D, or S.");
X	    }
X	}
X    }
X
Xuserlist()
X    {
X    FILE *bfd;
X    char line[1024], *p, *q, dbuf[20];
X    short lcnt, ncolon;
X    struct user buf;
X
X    if ((bfd = fopen(PASSWD, "r")) == NULL)
X	{
X	log("Error %d opening %s", errno, PASSWD);
X	panic("passwd");
X	}
X    puts("\nList of UNaXcess users:\n");
X    lcnt = 0;
X    while (fgets(line, 1024, bfd) != NULL)
X	{
X	buf.u_name[0] = '\0';
X	buf.u_pass[0] = '\0';
X	buf.u_access = 0;
X	buf.u_login[0] = '\0';
X	buf.u_llen = 0;
X	buf.u_nbull = 0;
X	buf.u_lconf[0] = '\0';
X	ncolon = 0;
X	for (p = line; *p != '\0'; p++)
X		if (*p == ':')
X			ncolon++;
X	if (ncolon < 6) {
X		log("Bad usefile entry %.*s", strlen(line) - 1, line);
X		continue;
X	}
X	for (p = line, q = buf.u_name; *p != ':'; p++, q++)
X		*q = *p;
X	*q = '\0';
X	for (p++, q = buf.u_pass; *p != ':'; p++, q++)
X		*q = *p;
X	*q = '\0';
X	for (p++, q = dbuf; *p != ':'; p++, q++)
X		*q = *p;
X	*q = '\0';
X	buf.u_access = atoi(dbuf);
X	for (p++, q = buf.u_login; *p != ':'; p++, q++)
X		*q = *p;
X	*q = '\0';
X	for (p++, q = dbuf; *p != ':'; p++, q++)
X		*q = *p;
X	*q = '\0';
X	buf.u_llen = atoi(dbuf);
X	for (p++, q = dbuf; *p != ':'; p++, q++)
X		*q = *p;
X	*q = '\0';
X	buf.u_nbull = atoi(dbuf);
X	for (p++, q = buf.u_lconf; *p != '\n'; p++, q++)
X		*q = *p;
X	*q = '\0';
X	for (p = buf.u_name; *p != NULL; p++)
X	    *p = ToUpper(*p);
X	printf("%-32.32s Access: %s\n", buf.u_name, (buf.u_access==A_NONE?
X	    "None": (buf.u_access==A_GUEST? "Guest": (buf.u_access==A_USER?
X	    "Normal": (buf.u_access==A_WITNESS? "Fairwitness": (buf.u_access==A_SYSTEM? "System": (user.u_access==A_FILES? "Files": "(make a user)")))))));
X	if (++lcnt % 16 == 0)
X	    if (!cont())
X		break;
X	}
X    fclose(bfd);
X    return 1;
X    }
________This_Is_The_END________
echo 'x - param.c'
sed 's/^X//' <<'________This_Is_The_END________' >>param.c
X/*
X * @(#)param.c	1.1 86/05/05 01:43:47 tdi2!brandon @(#)
X * @(#) Copyright (C) 1986 by Brandon S. Allbery, All Rights Reserved @(#)
X *
X * Permission is hereby granted to copy and freely distribute this code,
X * UNaXcess Version 0.04.04 and derivatives ONLY.  Version 1.00.00 and later
X * may NOT be copied or distributed without the author's written permission.
X * You may charge only a reasonable handling/copying fee for distribution of
X * this code; you may not sell it or include it in a commercial package for
X * resale.
X */
X
X#ifndef lint
Xstatic char _SccsId[] = "@(#)param.c	1.1 86/05/05 01:43:47 tdi2!brandon @(#)";
Xstatic char _CopyRt[] = "@(#) Copyright (C) 1985 by Brandon S. Allbery @(#)";
X#endif  lint
X
X#include "ua.h"
X
Xstruct sys parms = {
X#ifdef NOAUTOPATH
X	NOAUTOPATH,
X#else
X	"/usr/unaxcess",
X#endif NOAUTOPATH
X	1,
X	0,
X	"ua-edit",
X	"/bin/sh",
X	1,
X	"unaxcess",
X	30,
X	"sysop",
X	1,
X	0,
X	"",
X	"",
X	1,
X	3,
X	"trap '' 2; stty -echo; echo 'Begin sending your file.  End with a CONTROL-D.'; cat - > %s; stty echo",
X	"trap '' 2; cat %s",
X	"umodem -rb",
X	"umodem -sb",
X	"kermit -iwr",
X	"kermit -iws",
X};
X
X#define NUM		0
X#define STR		1
X#define BOOL		2
X
Xstruct rparm {
X	char *parmname;
X	char parmtype;
X	char *parmval;
X} sysparms[] = {
X	"bbs-directory",STR,	parms.ua_home,
X	"readonly",	BOOL,	&parms.ua_roc,
X	"x-rated",	BOOL,	&parms.ua_xrc,
X	"editor",	STR,	parms.ua_edit,
X	"shell",	STR,	parms.ua_shell,
X	"read-env",	BOOL,	&parms.ua_env,
X	"bbs-user",	STR,	parms.ua_bbs,
X	"time-limit",	NUM,	&parms.ua_tlimit,
X	"sysop",	STR,	parms.ua_sysop,
X	"private-msgs",	BOOL,	&parms.ua_pm,
X	"logging",	BOOL,	&parms.ua_log,
X	"banner",	STR,	parms.ua_bnr,
X	"login-msg",	STR,	parms.ua_login,
X	"pauses",	NUM,	&parms.ua_hco,
X	"login-tries",	NUM,	&parms.ua_nla,
X	"ascii-upload",	STR,	parms.ua_auc,
X	"ascii-download",STR,	parms.ua_adc,
X	"xmodem-upload",STR,	parms.ua_xuc,
X	"xmodem-download",STR,	parms.ua_xdc,
X	"kermit-upload",STR,	parms.ua_kuc,
X	"kermit-download",STR,	parms.ua_kdc,
X	0,		0,	0,
X};
X
X/*
X * 1. Get home directory
X * 2. Open $HOME/uaconfig
X * 3. Parse lines; # is a comment, input form is KEYWORD VALUE
X *    VALUE is numeric, Y/N, "string" and backslash escapes for
X *     \n \t \r \b \f \e \nnn are understood
X * 4. Assign the values to the parms structure
X */
X
Xstatic char line[512], var[20], sval[50];
X 
Xgetparms() {
X 	char home[512];
X 	FILE *cfp;
X 	short nval, cnt, pos, scnt, canon;
X 	
X#ifdef NOAUTOPATH
X	strcpy(home, NOAUTOPATH);
X#else
X 	strcpy(home, getpwuid(geteuid())->pw_dir);
X#endif NOAUTOPATH
X	strcpy(parms.ua_home, home);
X 	strcpy(line, home);
X 	strcat(line, "/");
X 	strcat(line, CONFIG);
X 	if ((cfp = fopen(line, "r")) == NULL) {
X 		fprintf(stderr, "panic: param get, %s\n", line);
X 		exit(1);
X 	}
X 	while (fgets(line, 512, cfp) != NULL) {
X 		line[strlen(line) - 1] = '\0';
X 		if (Index(line, '#') != NULL)
X 			*(Index(line, '#')) = '\0';
X 		scnt = 0;
X 		pos = 0;
X 		while (line[pos] != '\0' && line[pos] != ' ' && line[pos] != '\t')
X 			var[scnt++] = line[pos++];
X 		var[scnt] = '\0';
X 		if (var[0] == '\0')
X 			continue;
X 		for (cnt = 0; sysparms[cnt].parmname != NULL; cnt++)
X 			if (strcmp(sysparms[cnt].parmname, var) == 0)
X 				break;
X 		if (sysparms[cnt].parmname == NULL) {
X 			fprintf(stderr, "Please inform the sysop that there is an invalid parameter\n%s in the setup file.\n", var);
X 			continue;
X 		}
X		while (line[pos] == ' ' || line[pos] == '\t')
X			pos++;
X 		switch (sysparms[cnt].parmtype) {
X 			case NUM:
X 				*((char *) sysparms[cnt].parmval) = atoi(&line[pos]) & 0xff;
X 				break;
X 			case BOOL:
X 				if (line[pos] == '\0' || ToLower(line[pos]) == 'y')
X 					*((char *) sysparms[cnt].parmval) = 1;
X 				else
X 					*((char *) sysparms[cnt].parmval) = 0;
X 				break;
X 			case STR:
X 				if (line[pos] == '"') {
X 					canon = 1;
X 					pos++;
X 				}
X 				for (scnt = 0; (canon? line[pos] != '"': line[pos] != '\0' && line[pos] != ' ' && line[pos] != '\t'); pos++, scnt++) {	
X 					if (canon && line[pos] == '\\') {
X 						switch (line[++pos]) {	
X 							case 'n':
X 								sval[scnt] = '\n';
X 								break;
X 							case 't':
X 								sval[scnt] = '\t';
X 								break;
X 							case 'r':
X 								sval[scnt] = '\r';
X 								break;
X 							case 'b':
X 								sval[scnt] = '\b';
X 								break;
X 							case 'f':
X 								sval[scnt] = '\f';
X 								break;
X 							case 'e':
X 							case 'E':
X 								sval[scnt] = '\033';
X 								break;
X 							case 'a':
X 								sval[scnt] = '\7';	/* proposed extension of C string metasyntax */
X 								break;
X 							case '0':
X 							case '1':
X 							case '2':
X 							case '3':
X 							case '4':
X 							case '5':
X 							case '6':
X 							case '7':
X 								sval[scnt] = 0;
X 								while (Index("01234567", line[pos]) != NULL)
X 									sval[scnt] = sval[scnt] * 8 + (line[pos++] - '0');
X								pos--;
X								break;
X							default:
X								sval[scnt] = line[pos];
X 						}
X 					}
X 					else
X 						sval[scnt] = line[pos];
X 				}
X 				sval[scnt] = '\0';
X 				strcpy(sysparms[cnt].parmval, sval);
X 		}
X 	}
X}
________This_Is_The_END________
echo 'x - dir.c'
sed 's/^X//' <<'________This_Is_The_END________' >>dir.c
X/*
X *
X *				N O T I C E
X *
X * This file is NOT a copyrighted part of the UNaXcess distribution.  These
X * are directory-reading routines which are compatible with the Berkeley Unix
X * (4.2BSD, 4.3BSD) directory routines.  They come from the Usenet news
X * distribution and are in the public domain.
X *
X * To get the best use of them:  install the file "dir.h" in /usr/include
X * -- standard usage calls it "ndir.h", and make a random archive of dir.o and
X * put it in /usr/lib/libndir.a .  It is then available with "-lndir".
X *
X * Bell System {III, V} sites, just make an archive -- it is only one file
X * anyway.  Other sites will have to run ranlib on the archive to keep ld
X * happy.
X */
X
X#include <sys/types.h>
X#include "dir.h"
X
X#ifndef BSD
X
X/*
X * close a directory.
X */
Xclosedir(dirp)
X        register DIR *dirp;
X{
X        close(dirp->dd_fd);
X        dirp->dd_fd = -1;
X        dirp->dd_loc = 0;
X        free(dirp);
X}
X
X
X
X/*
X * open a directory.
X */
XDIR *
Xopendir(name)
X        char *name;
X{
X        register DIR *dirp;
X        register int fd;
X
X        if ((fd = open(name, 0)) == -1)
X                return NULL;
X        if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) {
X                close (fd);
X                return NULL;
X        }
X        dirp->dd_fd = fd;
X        dirp->dd_loc = 0;
X        return dirp;
X}
X
X
X
X/*
X * read an old style directory entry and present it as a new one
X */
X#define ODIRSIZ 14
X
Xstruct  olddirect {
X        ino_t   od_ino;
X        char    od_name[ODIRSIZ];
X};
X
X/*
X * get next entry in a directory.
X */
Xstruct direct *
Xreaddir(dirp)
X        register DIR *dirp;
X{
X        register struct olddirect *dp;
X        static struct direct dir;
X
X        for (;;) {
X                if (dirp->dd_loc == 0) {
X                        dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 
X                            DIRBLKSIZ);
X                        if (dirp->dd_size <= 0)
X                                return NULL;
X                }
X                if (dirp->dd_loc >= dirp->dd_size) {
X                        dirp->dd_loc = 0;
X                        continue;
X                }
X                dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc);
X                dirp->dd_loc += sizeof(struct olddirect);
X                if (dp->od_ino == 0)
X                        continue;
X                dir.d_ino = dp->od_ino;
X                strncpy(dir.d_name, dp->od_name, ODIRSIZ);
X                dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */
X                dir.d_namlen = strlen(dir.d_name);
X                dir.d_reclen = DIRBLKSIZ;
X                return (&dir);
X        }
X}
X
X#endif BSD
________This_Is_The_END________
exit
-- 
  ---------------- /--/	Brandon S. Allbery		UUCP:
 /              / /|\/	Tridelta Industries, Inc.       decvax!cwruecmp!ncoast!
----    -------- /-++	7350 Corporate Blvd.		    tdi2!brandon
   /   / /---,  /--/	Mentor, Ohio 44060		PHONE:  (home)
  /   / /    / /  /	     -- HOME --			+1 216 974 9210
 /   / /    / /  /	6615 Center St. Apt. A1-105	ARPA:  ncoast!allbery%
----  /----~ /--/	Mentor, Ohio 44060-4101		case.CSNET@csnet-relay
-------------------------------------------------------------------------------
			Space -- The Final Frontier