#
/*
 * login [ name ]
 */

struct utmp {
	char	name[8];
	int	line;
	int	time[2];
	int	pid;
} utmp;
struct {
	int	regs[2];
	int	tflags;
} ttyb;

struct {
	int	junk[5];
	int	size;
	int	more[12];
} statb;
 
int	cbuf[256];
char	*ttyx;
char	zero[16];
char	*utmpf	"/etc/utmp";
char	*wtmpf	"/etc/wtmp";
int	lid;

#define	ECHO	010

main(argc, argv)
char **argv;
{
	register struct utmp *p;
	register char *namep,*np;
	char pbuf[128];
	char pwbuf[9];
	int   f, c, uid;
	struct{
		char	lobyte;
		char	hibyte;
	};

	signal(3, 1);
	signal(2, 1);
	ttyx = "/dev/ln\0\0";
	lid = lnxx(0);
	if(lid.lobyte == 'x' && lid.hibyte == 'x'){
		write(1, "Sorry.\n", 7);
		exit(-1);
	}
	ttyx[7] = lid.lobyte;
	ttyx[8] = lid.hibyte;
    loop:
	namep = utmp.name;
	if (argc>1) {
		np = argv[1];
		while (namep<utmp.name+8 && *np)
			*namep++ = *np++;
		argc = 0;
	} else {
		write(1, "Name: ", 7);
		while ((c = getchar()) != '\n') {
			if (c==0)
				exit(-1);
			if (namep < utmp.name+8)
				*namep++ = c;
		}
	}
	while (namep < utmp.name+8)
		*namep++ = ' ';
	if (getpwentry(utmp.name, pbuf))
		goto bad;
	np = colon(pbuf);
	if (*np!=':') {
		gtty(0, &ttyb);
		f = ttyb.tflags;
		ttyb.tflags =& ~ ECHO;
		stty(0, &ttyb);
		write(1, "Password: ", 10);
		namep = pwbuf;
		while ((c=getchar()) != '\n') {
			if (c==0)
				exit(-1);
			if (namep<pwbuf+8)
				*namep++ = c;
		}
		*namep++ = '\0';
		ttyb.tflags = f;
		stty(0, &ttyb);
		write(1, "\n", 1);
		namep = crypt(pwbuf);
		while (*namep++ == *np++);
		if (*--namep!='\0' || *--np!=':')
			goto bad;
	}
	np = colon(np);
	uid = 0;
	while (*np != ':')
		uid = uid*10 + *np++ - '0';
	np++;
	np = colon(np);
	namep = np;
	np = colon(np);
	if (chdir(namep)<0) {
		write(1, "No directory\n", 13);
		goto loop;
	}
	lnacctg();
	if ((f = open("/etc/motd", 0)) >= 0) {
		while(read(f, &c, 1) > 0)
			write(1, &c, 1);
		close(f);
	}
	if (stat(".mail", &statb) >= 0 && statb.size)
		write(1, "You have mail.\n", 15);
	chown(ttyx, uid);
	setgid(1);
	setuid(uid);
	if (*np == '\0')
		np = "/bin/sh";
	execl(np, "-", 0);
	write(1, "No shell.\n", 9);
	exit(-1);
bad:
	write(1, "Login incorrect.\n", 17);
	goto loop;
}

getpwentry(name, buf)
char *name, *buf;
{
	extern fin;
	int fi, r, c;
	register char *gnp, *rnp;

	fi = fin;
	r = 1;
	if((fin = open("/etc/passwd", 0)) < 0)
		goto ret;
loop:
	gnp = name;
	rnp = buf;
	while((c=getchar()) != '\n') {
		if(c == '\0')
			goto ret;
		*rnp++ = c;
	}
	*rnp++ = '\0';
	rnp = buf;
	while (*gnp++ == *rnp++);
	if ((*--gnp!=' ' && gnp<name+8) || *--rnp!=':')
		goto loop;
	r = 0;
ret:
	close(fin);
	fin = 0;
	(&fin)[1] = 0;
	(&fin)[2] = 0;
	return(r);
}

colon(p)
char *p;
{
	register char *rp;

	rp = p;
	while (*rp != ':') {
		if (*rp++ == '\0') {
			write(1, "Bad /etc/passwd\n", 16);
			exit(-1);
		}
	}
	*rp++ = '\0';
	return(rp);
}
/*
*	Login presumes that an entry(in utmp) with the
*	activated line already exists.  Thus its accounting
*	procedure merely searches for a matching line id and
*	stamps a new time into the time field.
*/
lnacctg()
{
	register struct utmp *p;
	register rw,k;
	if((rw=open(utmpf,2)) < 0) return;
	while((k=read(rw,&cbuf,512)) > 0) {
		for(p = &cbuf; (k =- 16) >= 0; p++){
			if(p->line != lid) continue;
			utmp.name[0] =| 0200; /*line process*/
			utmp.line = p->line;
			time(utmp.time);
			utmp.pid = p->pid;
			seek(rw,-(k+16),1); /*relative offset from end*/
			write(rw,&utmp,16);
			close(rw);
			if ((rw = open(wtmpf, 1)) >= 0) {
				seek(rw, 0, 2);
				write(rw, &utmp, 16);
				close(rw);
			}
			return;
		}
	}
}
