#include	"sys/types.h"
#include	"termio.h"
#include	"quotas.h"
#include	"hsubs.h"
#include	"info.h"
#include	"stdio.h"

struct	info	info;
struct	termio	ttyb;

char	*env[8];
extern char **environ;

char *to;
int	lfd;
char	pl[128], ib[256], ps1[16], tty[16], home[32], lbuf[256];
long	now;
int	bye();


main(c,v)
char **v;
{
	register char *s;
	register short gid;
	register char *t;
	short tuid, tgid, tflg, uid;
	char *p;


	gid = getgid();
	uid = getuid();
	if(c > 2){
		printf("Usage: %s [username]\n", v[0]);
		exit(1);
	}

	if(!isatty(0) || !isatty(1)) {
		printf("stdin/stdout is not a tty\n");
		exit(-1);
	}

	to = "root";
	if(c == 2)
		to = v[1];

	if(gid > 99 && uid - gid*100){
		printf("Class accounts may not use '%s'\n", v[0]);
		exit(2);
	}

	if(ngetent(HFILE_NM, to, pl)){
		printf("%s not found in password file.\n", to);
		exit(3);
	}

	clhash();
	s = pl;
	while(*s && *s != ':')s++;
	if(*s++ == 0){
her:
		printf("Bad hashed entry:\n%s", pl);
		exit(4);
	}

	p = s;
	while(*s && *s != ':')s++;
	if(*s++ == 0)goto her;
	tuid = tgid = 0;
	while(*s >= '0' && *s <= '9')
		tuid = tuid * 10 + (*s++) - '0';
	if(*s++ != ':')goto her;
	while(*s >= '0' && *s <= '9')
		tgid = tgid * 10 + (*s++) - '0';
	if(*s++ != ':')goto her;

	if(gid && gid != 2){
		if(*s != 'A' && *s != ' '){
			printf("Account status for '%s', (%c), is not active\n",
				to, *s);
			exit(5);
		}
		if(gid != 5){
			if(gid > 99){
				if(tgid != gid){
					printf("You may not use '%s' to go to that account\n",
						v[0]);
					exit(6);
				}
			} else
				if(tgid > 99){
					printf("You may not use '%s' to go to class accounts\n",
						v[0]);
					exit(6);
				}
		}
		if(tgid < 100 && chkquo(to)){
			printf("Quota of '%s' exceeded -- Logout then login\n", to);
			exit(9);
		}
	}
	if(gid &&			/* Not prived */
	   gid < 100 &&			/* Not a class/professor account */
	   (gid != 5 || tgid < 100)){	/* Staff account not going to class */
		if(c == 1)printf("Root ");
		printf("Password: ");
		fflush(stdout);
		ioctl(0, TCGETA, &ttyb);
		tflg = ttyb.c_lflag;
		ttyb.c_lflag &= ~ECHO;
		signal(2, bye);
		signal(3, bye);
		signal(14, bye);
		alarm(30);
		ioctl(0, TCSETA, &ttyb);
		ttyb.c_lflag = tflg;
		t = ib;
		while((*t = getchar()) > 0 && *t != '\n')
			t++;
		*t = 0;
		ioctl(0, TCSETA, &ttyb);
		printf("\n");
		signal(2, 0);
		signal(3, 0);
		if(t == ib)
			exit(6);
		if(strncmp(p, crypt(ib, p), 13)){
			printf("Password incorrect.\n");
			signal(2,1);
			signal(3,1);
			if((lfd = open("/usr/adm/.sulog", 1)) > 0){
				lseek(lfd, 0L, 2);
				time(&now);
				sprintf(lbuf, "%s/%s failed to %s(%s): %s",
					logname(), logtty(), to, ib, ctime(&now));
				write(lfd, lbuf, strlen(lbuf));
				close(lfd);
			}
			exit(7);
		}
	}
	signal(2,1);
	signal(3,1);
	if((lfd = open("/usr/adm/.sulog", 1)) > 0){
		lseek(lfd, 0L, 2);
		time(&now);
		sprintf(lbuf, "%s/%s to %s: %s", logname(), logtty(),
			to, ctime(&now));
		write(lfd, lbuf, strlen(lbuf));
		close(lfd);
	}
	signal(2,0);
	signal(3,0);
	strcpy(info.l_lognam, to);
	while(*s && *s != ':')s++;
	if(*s++ == 0)goto her;
	t = s;
	while(*s && *s != ':')s++;
	if(*s == 0)goto her;
	*s = 0;
	strcpy(info.l_logdir, t);
	strcpy(info.l_logtty, logtty());
	logpost(&info);
	strcpy(ps1, "PS1=");
	strcpy(home, "HOME=");
	strcpy(tty, "TTY=");
	strcat(ps1, to);
	strcat(ps1, "$ ");
	strcat(home, t);
	strcat(tty, logtty());
	env[0] = home;
	env[1] = "PATH=:/bin:/usr/bin";
	env[2] = "TERM=adm3a";
	env[3] = tty;
	env[4] = ps1;
	env[5] = 0;
	environ = env;
	setuid(tuid);
	setgid(tgid);
	if(chdir(t))
		printf("No directory: %s -- Su'ing but no directory change\n",t);
	execl("/bin/sh", "SU/sh", 0);
	printf("Could not execute new shell.\n");
	exit(9);
}

bye()
{
	signal(2,1);
	signal(3,1);
	ioctl(0, TCSETA, &ttyb);
	exit(10);
}

short qfd;

chkquo(n)
char *n;
{

	if((qfd = open(QUOFILE, 0)) == -1)
		return(0);
	if(getqent(qfd, &q, n) == 0){
		close(qfd);
		return(0);
	}
	close(qfd);
	if(q.q_dused > q.q_dquo ||
		(q.q_mquo && q.q_mused > q.q_mquo) ||
		q.q_fused > q.q_fquo)
			return(1);
	return(0);
}

