#include	"sys/types.h"
#include	"sys/stat.h"
#include	"sys/termio.h"
#include	"ctype.h"
#include	"login.h"
#include	"extdefs.h"



struct	utimbuf {
	time_t	actime;
	time_t	modtime;
};

getname(nam)
register char *nam;
{
	register char *s;
	register int r;
	static char hbuf[256];
	char *nextf();

	if((r = getent(HFILE, nam, hbuf)) < 0){
		logit(9, nam, 0);
second:
		printf("\nContact systems personnel.\n");
		return(getnm1(nam));
	}
	if(r)return(-1);

	if((s = nextf(pwe.lognm, 8, hbuf)) == 0 ||
	   (s = nextf(pwe.passwd, 13, s)) == 0 ||
	   (s = nextf(pwe.uid, 5, s)) == 0 ||
	   (s = nextf(pwe.gid, 5, s)) == 0 ||
#ifdef	NICEFIELD
	   (s = nextf(pwe.prio, 4, s)) == 0 ||
#endif
	   (pwe.pstat = *s++) == 0 ||
	   (s = nextf(pwe.termlim, 2, s)) == 0 ||
	   (s = nextf(pwe.homedir, 32, s)) == 0 ||
	   (s = nextf(pwe.shell, 33, s)) == 0){
error:
		printf("login: getname: Hashed passwd in bad format near %s\n",
			hbuf);
		logit(8, nam, hbuf);
		goto second;
	}
	return(0);
}

char *nextf(s, l, t)
register char *s, *t;
int l;
{
	register char *p;

	p = s + l;
	while(s < p && *t != ':' && *t != '\n' && *t)
		*s++ = *t++;
	while(*t && *t != ':' && *t != '\n')t++;
	if(*t == 0)return(0);
	*s = 0;
	return(t+1);
}

getnm1(nam)
char *nam;
{
	register char *s, *l;
	register int flag;
	char *t;
	int fd, r;

	flag = 0;
	if((fd = open(PWFIL, 0)) == -1){
		printf("No %s - Contact Systems personnel\n", PWFIL);
		logit(10, nam, 0);
		sleep(3);
		exit(-1);
	}

	t = pwe.lognm;

	while((r = read(fd, buf, 512)) > 0)
		for(s = buf, l = &buf[r]; s < l; s++){
			switch(flag){

	case -1:
		if(*s == '\n') flag = 0;
		break;

	case 0:
		if(*s == ':'){
			*t = 0;
			if(strcmp(pwe.lognm, nam) == 0){
				t = pwe.passwd;
				flag++;
			}
			else	{
				t = pwe.lognm;
				flag = -1;
			}
			break;
		}
		if(t < &pwe.lognm[8])
			*t++ = *s;
		break;

	case 1:
	case 2:
	case 3:
#ifdef	NICEFIELD
	case 4:
	case 8:
#else
	case 7:
#endif
		if(*s == ':'){
			*t = 0;
			t = paddr[++flag];
			break;
		}
		if(t < paddr[flag]+plen[flag])
			*t++ = *s;
		break;


#ifdef	NICEFIELD
	case 5:
#else
	case 4:
#endif
		pwe.pstat = *s;
		flag++;
		t = pwe.termlim;
		break;

#ifdef	NICEFIELD
	case 6:
#else
	case 5:
#endif
		if(*s == ' '){
			*t = 0;
			flag++;
			break;
		}
		if(t < &pwe.termlim[2])
			*t++ = *s;
		break;

#ifdef	NICEFIELD
	case 7:
#else
	case 6:
#endif
		if(*s == ':'){
			t = pwe.homedir;
			flag++;
			break;

		}

		break;
#ifdef	NICEFIELD
	case 9:
#else
	case 8:
#endif
		if(*s == '\n'){
			*t = 0;
			close(fd);
			return(0);
		}
		if(t < &pwe.shell[32])*t++ = *s;
		break;

	default:
		logit(11, nam, 0);
		printf("Program error - Contact systems personnel\n");
		sleep(3);
		exit(8);
			}

		}
	close(fd);
	return(-1);
}

strcmp(s,t)
register char *s , *t;
{
	while(*s == *t && *s != ':' && *s)s++,t++;
	if(*t == 0)
		if(*s == 0 || *s == ' ' || *s == ':')return(0);
		else	return(1);
	if(*s == 0 || *s == ' ' || *s == ':')return(-1);
	return(*s < *t ? -1 : 1);
}


equal(s, t)
register char *s, *t;
{
	while(*s == *t++)
		if(*s++ == 0)return(1);
	return(0);
}

val(s)
register char *s;
{
	register int sign , value;

	value = 0;
	sign = 1;

	while(*s == ' ' || *s == '0')s++;
	if(*s == '-') {
		sign = -1;
		s++;
	}

	while(*s >= '0' && *s <= '9')
		value = value * 10 + (*s++) - '0';
	return(sign*value);
}


whom(s)
char *s;
{
	register struct utmp *wp;
	register char *pt;
	register c;
	char *ps;
	int i;
	int fd;

	c = 0;
	if((fd = open(UTMP,0)) == -1)
		return(0);
	usercnt = 0;
	while((i = read(fd,wbuf,4608)) > 0) 
		for(wp = wbuf; wp < &wbuf[i]; wp++) {
			if(equal(wp->ut_line, mytty))continue;
			wp->ut_id[0] = 0;	/* kludge! */
			if(strcmp(wp->ut_name, s) == 0){
				pt = terms[c++];
				ps = wp->ut_line;
				while((*pt++ = *ps) && ps < &wp->ut_line[8])ps++;
				*pt = 0;
			}
			if(wp->ut_name[0])usercnt++;
		}

	close(fd);
	return(c);
}

getnm(n)
char *n;
{
	static char nambuf[64];
	register char *p;
	register short sepflg;

	passflg = 0;
	sepflg = 0;
	printf("Name: ");
	fflush(stdout);
	nambuf[0] = nambuf[1] = 0;
	p = nambuf+2;
lp:
	if(read(0, p, 1) != 1)
		return(-1);
	if(*p != '\n') {
		if(*p == '/' || *p == ';')
			sepflg++;
		if(p < &nambuf[63] && (sepflg || *p != ' '))
			p++;
		goto lp;
	}

	*p = 0;
	sep(nambuf+2, n);
	return(0);
}

getpaswd(p)
register char *p;
{
	register char *s;
	char *crypt();

	if(passflg){
		goto gotpw;
	}
	printf("Password: ");
	fflush(stdout);
	s = passbuf;
	*p = 0;
	setty(1);

lp:
	if(read(0,s,1) != 1) {
		printf("\n");
		setty(0);
		return(-1);
	}
	if(*s != '\n'){
		if(s < &passbuf[8])s++;
		goto lp;
	}
	*s = 0;
	printf("\n");
	setty(0);
gotpw:
	s = crypt(passbuf, pwe.passwd);
	while(*p++ = *s++);
	return(0);
}


setty(on_off)		/* 1 sets no echo, 0 sets echo */
register on_off;
{
	struct termio ttyb;

	ioctl(0, TCGETA, &ttyb);
	if(on_off)
		ttyb.c_lflag &= ~ECHO;
	else	ttyb.c_lflag |= ECHO;
	ioctl(0, TCSETA, &ttyb);
}


sep(b,n)
register char *b , *n;
{
	register char *nmax;

	nmax = n + 8;
	*n = 0;
	motdflg = 0;

	while(n < nmax && (*n = *b) && *b != '/' && *b != ';')n++,b++;
	*n = 0;
	while(*b && *b != '/' && *b != ';')b++;
	if(*b == '/'){
		b++;
		motdflg = 1;
	} else	if(*b == ';')
			b++;
	if(*b){
		n = passbuf;
		nmax = n + 8;
		while((*n = *b++) && n < nmax)
			n++;
		*n = 0;
		passflg = 1;
	}
	return(0);
}



tmout(){
	setty(0);
				/* Reset echo, if timeout at Password: */
	printf("\n");
	exit(14);
}

dialup(){
	register char **s;
	s = dial;
	while(*s)
		if(equal(mytty, *s++))return(1);
	return(0);
}

addme()
{
	register char *s , *t;
	register int fd;
	struct utmp lwho;

	s = unm;
	t = who.ut_name;
	while(*t++ = *s++);
	t--;
	time(&who.ut_time);
	who.ut_type = USER_PROCESS;
	while(t < who.ut_name+8)
		*t++ = 0;
	t = info.l_lognam;
	s = unm;
	while(t < &(info.l_lognam[8]) && (*t = *s++))t++;
	while(t < &(info.l_lognam[8]))*t++ = 0;
	t = info.l_logdir;
	s = pwe.homedir;
	while(t < &(info.l_logdir[32]) && (*t = *s++))t++;
	while(t < &(info.l_logdir[32]))*t++ = 0;
	t = mytty;
	s = info.l_logtty;
	while(s < &(info.l_logtty[8]) && (*s = *t++))s++;
	while(s < &(info.l_logtty[8]))*s++ = 0;
	logpost(&info);
	t = mytty;
	s = who.ut_line;
	while(t < mytty + 8 && (*s++ = *t++));
	while(s < &who.ut_line[8])*s++ = 0;
	if((fd = open(UTMP,2)) >= 0){
		while(read(fd, &lwho, (sizeof (struct utmp))) ==
			sizeof (struct utmp)){
			switch(lwho.ut_type){
			case INIT_PROCESS:
			case LOGIN_PROCESS:
			case USER_PROCESS:
			case DEAD_PROCESS:
				if(strncmp(lwho.ut_line, who.ut_line, 8) == 0){
					lseek(fd, -(long)(sizeof (struct utmp)), 1);
					goto found;
				}
				break;
			default:
				break;
			}
		}
found:
		write(fd,&who,sizeof (struct utmp));
		close(fd);
	}
	if((fd = open(WTMP,1)) >= 0){
		lseek(fd, 0L, 2);
		write(fd,&who,sizeof (struct utmp));
		close(fd);
	}
}

#ifdef	HALTSTAT
haltstat(){
	int pid;
	if((pid = fork()) == -1)return;
	if(pid)
		wait(&pid);
	else	{
		execl("/bin/haltstat","haltstat","-",0);
		exit(1);
	}
}
#endif

login(u,g)
register u , g;
{
#ifdef	NICEFIELD
	nice(val(pwe.prio));
#endif
	chown(ttyx, u, 0);
	chmod(ttyx,0611);
	setgid(g);
	setuid(u);
	umask(022);
}

motd(){
	long lt;
	struct	stat stb;
	struct utimbuf	tmbuf;
	int mf;
	char byte;

	mail = 0;
	if(stat(".mail",&stb) == 0) {
		mail = (stb.st_size != 0);
		lt = stb.st_atime;
		if(motdflg){
			time(&(tmbuf.actime));
			tmbuf.modtime = stb.st_mtime;
			utime(".mail", &tmbuf);
			if(stat("/etc/motd",&stb) == 0)
				if(lt >= stb.st_mtime)
					motdflg++;
		}
	}
	if(motdflg != 2){
		uname(&utsname);
		printf("\t%s %s %s %s Timesharing System\n",
			utsname.nodename, utsname.machine, utsname.release,
			utsname.sysname);
		if(stat("/usr/news", &stb) == 0)
			printf("\n\tNews last updated: %s\n", ctime(&stb.st_mtime));
		if((mf = open("/etc/motd", 0)) >= 0){
			signal(2,mint);
			signal(3,mint);
			moerr = 1;
			while((motdflg = read(mf,buf,512)) && moerr)
				write(1,buf,motdflg);
			close(mf);
			signal(2,1);
			signal(3,1);
		}
	}

}

mint(){
	moerr = 0;
}

mailcall(){
	if(mail)
		printf("\nYou have mail.\n\n");
	else	printf("\n");
}

shell(){
	register char *s , *t;

	environ = envinit;
	strncat(homedir, pwe.homedir, MAXHOMELEN - 6);
	strncat(teletype, mytty, MAXTTYLEN - 5);
	envinit[TYPEPLACE] = gettype(mytty);
	t = s = pwe.shell;

	if(*t == 0)
		execl("/bin/sh","-",0);
	else	{
		while(*t)
			if(*t++ == '/')s = t;
		while(*--t == '/')*t = 0;
		t = buf;
		*t++ = '-';
		while(*t++ = *s++);
		execl(pwe.shell,buf,0);
		execl("/bin/sh","sh",pwe.shell,0);
	}
}




#ifdef EXPSTUFF
expsleep()
{
	struct exp file[3];
	struct exp *filep, *entryp;
	struct position {
		char tty;
		int pos;
		};
	static struct position offset[3] =  {
					EXPRESS1,       0,
					0,       43,
					0,       85
					};
	struct position *off;
	int fd, i, found, pos;
	register char *nm;

	if ((fd = open(EXPFILE,2)) < 0)
		return;

	off = &offset;
	filep = &file;
	entryp = &entry;
	nm = entry.names;
	*(nm + 8) = 0;

	if (strcmp (nm, "debug") == 0 || strcmp (nm,"who") == 0 || strcmp (nm,"who+") == 0){
		close(fd);
		return;
	}

	while (off <= &offset[2]) {
		if (off->tty == entryp->ttys) {
			pos = off->pos;
			lseek(fd, (long)(pos), 0);
			break;
		}
		off++;

	}

	if (read (fd, filep, sizeof file) < sizeof file){        /* file messed up */
		close(fd);
		return;
	}
	while ( filep <= &file[2]) {
		if (strcmp (filep->names, nm) == 0) {
			found++;
			break;
		}
		filep++;
	}

	if (found && (filep->times - entryp->times < FIFTEEN)) {
		printf ("Express terminal login forbidden\n");
		sleep(3);
		exit (1);
		}

	lseek(fd, (long)(pos), 0);
	filep = &file[1];
	write (fd, filep, 14);
	filep++;
	write (fd, filep, 14);
	write (fd, entryp, 14);
	close(fd);
	killsleep(FIFTEEN);
	return (0);
}
#endif
killsleep (time)
int time;
{
	int pid;
	int warning = 120;
	register char *s, *t;

	signal(1,1);
	signal(2,1);
	if ((pid = fork()) == 0) {
		close(0);
		close(2);
		sleep (time - warning);
		if ((pid = getppid()) == 1){
kludge1:
			sleep(5);
			exit(1);
		}
		printf("\007\007*** %d minute warning ***\n", 
			warning/60);
		close(1);
		sleep (warning);
		if ((pid = getppid()) == 1)goto kludge1;

		signal(15, 1);
		kill (0, 15);
		sleep(10);
		kill (0,9);
		exit (0);
	}

	signal(1,0);
	signal(2,0);
}

quota(s)
register char *s;
{
	register short i, j, k;
	short nlogs;

	if(find(s))return(0);

	nlogs = q.q_flg & LCNT;
	if(nlogs == NDISABLE){
		printf("\nYour account has been voluntarily turned off by your group");
		printf("\nleader.  You should contact him for more information.\n\n");
		logit(15, s, 0);
		sleep(3);
		exit(15);
	}
	i = (q.q_dquo < q.q_dused);
	j = (q.q_fquo < q.q_fused);
	k = (q.q_mquo && q.q_mused > q.q_mquo);
	if(!i && !j && !k)
		return(0);
	if((i || j) && nlogs){
		update(s);
		if(find(s))return(0);
		if((q.q_flg & LCNT) == 0)return(0);
	}

	signal(2,1);
	if((q.q_flg++ & LCNT) == NOVER){
		printf("\nYou have consistently ignored the over");
		printf(" quota messages.\nYou must seek systems personnel");
		printf(" for assistance.\n\n");
		logit(12, s, 0);
		sleep(3);
		exit(4);
	}

	if((q.q_flg & WARNING) == 0 && (qfd = open(QFILE, 1)) > 0){
		lseek(qfd, (long)(qval)*QSZ, 0);
		write(qfd, &q, QSZ);
		close(qfd);
	}

	signal(2,0);
	if(k)
		printf("\nYou have run out of money%s\n",
			(i || j) ? " not to mention" : ".");
	if(i || j)
		printf("You have exceeded ");
	if(i)
		printf("your disk quota of %u blocks by %u%s\n",
			q.q_dquo, q.q_dused - q.q_dquo, j ? " and" : ".");
	if(j)
		printf("your file quota of %u files by %u.\n", q.q_fquo,
			q.q_fused - q.q_fquo);
	j = q.q_flg & (LCNT|WARNING);
	if(j <= NOVER){
		if(j == NOVER)
			printf("\nThis is the last chance you have");
		else	printf("\nYou have %d logins left", (NOVER+1) - j);
		printf(k ? ".\n" : " to remove files.\n");
	}
	if(j == NOVER && k)
		printf("\nYou must see %s in order to get more money.\n",
			q.q_uid >= 10000 ? "your instructor" : "Rose Zamalcany (Rm 223)");
	return((q.q_flg & WARNING) == 0);
}

update(s)
register char *s;
{
	register int i;
	int ret;

	signal(1,1);
	signal(2,1);
	if(fork() == 0){
		execl("/accting/chgquo", "chgquo", s, "-u", 0);
		printf("\nQuota update program is missing - Please notify systems personnel.\n\n");
		logit(13, s, 0);
		exit(1);
	}
	wait(&ret);
	signal(1,0);
	signal(2,0);
}

find(s)
register char *s;
{
	q.q_flg = LCNT | NONOTIFY | WARNING;
	if((qfd = open(QFILE, 0)) == -1)
		return(1);
	qval = getqent(qfd, &q, s);
	close(qfd);
	if(qval == 0){
		q.q_flg = LCNT | NONOTIFY | WARNING;
		return(1);
	}
	return(0);
}

logit(n, s, arg)
short n;
int arg;
char *s;
{
	char	obuf[128];
	register char *p;
	register short fd, *pt;
	short len;
	int tv[2];
	int *localtime();

	if((fd = open(LOGFILE, 1)) == -1)
		return;
	time(tv);
	pt = localtime(tv);
	sprintf(p = obuf, "%s\t%s", s, errmsg[n]);
	p += strlen(p);
	if(arg){
		if(n == 1 || n == 6 || n == 7 || n == 8)
			sprintf(p, "(%s)", arg);
		else	if(n == 3)
				sprintf(p, "(%s)", arg ? "" : "dial-up");
			else	if(n == 14)
					sprintf(p, "(%c)", (char)(arg));
				else
					sprintf(p, "(%d)", arg);
	}
	p += strlen(p);
	sprintf(p, "	%02d/%02d	%02d:%02d	%s\n",
		pt[4]+1, pt[3], pt[2], pt[1], mytty);
	len = strlen(obuf);
	lseek(fd, 0L, 2);
	write(fd, obuf, len);
	close(fd);
}

cleanam(s)
register char *s;
{
	while(*s)
		if(!isalnum(*s) && *s != ' ')
			return(0);
		else	s++;
	return(1);
}

validate(unm, p)
char *unm, *p;
{
	register char *s, *t, *q;
	static char xbuf[64];
	short err;

	err = 0;
	if(strcmp(p, unm) == 0)
		err = 1;		/* Passwd = logname */
	else	{
		s = p;
		q = s;
		while(*s)
			s++;
		if(s-q > 8){
			s = q + 8;
			*s = 0;
		}
		t = xbuf;
		while(s >= q)
			*t++ = *--s;
		if(strcmp(xbuf, unm) == 0)
			err = 2;
	}
	if(err == 0)
		return(0);
	logit(16, unm, 0);
	printf("\nYour password is not secure -- you MUST change it\n\n");
	execl("/bin/passwd", "passwd", unm, 0);
	execl("/usr/bin/passwd", "passwd", unm, 0);
	printf("Please do so by using the 'passwd' command after you login.\n\n");
	logit(17, unm, 0);
}

gettype(tname)
char *tname;
{
	FILE *fp;
	static char lbuf[80];
	register char *s, *t;

	if((fp = fopen(TTYTYPE, "r")) == (FILE *)NULL){
error:
		strcpy(lbuf, "TERM=adm3a");
		return(lbuf);
	}
	while((s = fgets(lbuf, 64, fp)) != (char *)NULL){
		while(*s && *s != '\n' && *s != ':' && s < &lbuf[63])
			s++;
		if(*s != ':')
			continue;
		*s++ = '\0';
		if(strcmp(lbuf, tname))
			continue;
		for(t = s; *t && *t != '\n' && t < &lbuf[63]; t++)
			;
		*t = '\0';
		fclose(fp);
		/* This is quite safe -- s is always > lbuf! */
		sprintf(lbuf, "TERM=%s", s);
		return(lbuf);
	}
	fclose(fp);
	goto error;
}
