V10/cmd/login.c

Compare this file to the similar file:
Show the results in this format:

/*
 * login  [ -f  name ] [ -p passwdline ] [ command ]
 *    -f:  if su, log in with no password
 *    -p:  if su, use entire password line.
 *    command: if given, just execute command
 */

#include <sys/param.h>
#include <sys/ttyio.h>
#include <utmp.h>
#include <signal.h>
#include <pwd.h>
#include <libc.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/vlimit.h>

#define SCPYN(a, b)	strncpy(a, b, sizeof(a))

#define ISIZE 32
#define POSTMKSIZ sizeof "From  Sun Jan 00 00:00:00 1979"
char	maildir[30] =	"/usr/spool/mail/";
struct	passwd nouser = {"", "nope"};
struct	utmp utmp, xtmp;
char	minusnam[16] = "-";
char	homedir[64] = "HOME=";
char	path[] = "PATH=:/bin:/usr/bin";
char	**env;
int	nenv = 0;
char	nolog[] = "/etc/nologin";
char	motd[] = "/etc/motd";
struct	passwd *pwd;
struct	passwd *pwdecode();
char	*cmd;

extern	char **environ;

main(argc, argv)
char **argv;
{
	register char *namep;
	register int i, f;
	char input[ISIZE];
	char *ttyn;
	int neednopass = 0;
	int hangitup = 0;
	int ntries = 0;
	struct ttydevb tb;

	alarm(60);
	signal(SIGQUIT, SIG_IGN);
	signal(SIGINT, SIG_IGN);
	signal(SIGHUP, SIG_IGN);
	nice(-100);
	nice(20);
	for (i=NSYSFILE; i<NOFILE; i++)
		close(i);
	ttyn = ttyname(0);
	if (ttyn==0)
		SCPYN(utmp.ut_line, "tty??");
	else if (strncmp(ttyn, "/dev/", 5) == 0)
		SCPYN(utmp.ut_line, ttyn+5);
	else
		SCPYN(utmp.ut_line, ttyn);	/* shouldn't happen */
	SCPYN(input, "");
	switch(argc) {
	case 0:
	case 1:
		break;

	case 2:
		SCPYN(input, argv[1]);
		break;

	default:
		if (strcmp(argv[1], "-f")==0 || strcmp(argv[1], "-p")==0) {
			if (getuid()!=0) {
				printf("login: not super-user\n");
				exit(1);
			}
			neednopass++;
			if (strcmp(argv[1], "-f")==0)
				SCPYN(input, argv[2]);
			else {
				pwd = pwdecode(argv[2]);
				SCPYN(input, pwd->pw_name);
			}
			if (argc>3)
				cmd = argv[3];
		} else
			exit(1);
	}
    loop:
	if (ntries) {
		if (ntries > 5 || hangitup) {
			ioctl(0, TIOCGDEV, &tb);
			tb.ispeed = tb.ospeed = 0;
			ioctl(0, TIOCSDEV, &tb);
			sleep(5);
			exit(1);
		}
		neednopass = 0;
		pwd = NULL;
		SCPYN(input, "");
	}
	ntries++;
	while (input[0] == '\0') {
		namep = input;
		printf("login: ");
		while ((i = getchar()) != '\n') {
			if(i == ' ')
				i = '_';
			if (i == EOF)
				exit(0);
			if (namep < input + ISIZE - 1)
				*namep++ = i;
		}
		*namep = NULL;
	}
	SCPYN(utmp.ut_name, input);
	utmp.ut_time = 0;
	if (pwd == NULL) {
		setpwent();
		if ((pwd = getpwnam(input)) == NULL)
			pwd = &nouser;
		endpwent();
	}
	if (namep = strchr(utmp.ut_name, '\001'))
		if (namep[1]=='L' && namep[2]=='\002')	/* loopback? */
			hangitup++;
	time(&utmp.ut_time);
	if (*pwd->pw_passwd != '\0' && !neednopass) {
		namep = crypt(getpass("Password:"), pwd->pw_passwd);
		if (strcmp(namep, pwd->pw_passwd)) {
			/* magic string detects loopbacks */
			printf("\001L\002ogin incorrect\n");
			f = open("/usr/adm/xtmp", 1);
			if (f > 0) {
				lseek(f, 0L, 2);
				write(f, (char *)&utmp, sizeof(utmp));
				close(f);
			}
			goto loop;
		}
	}
	if(pwd->pw_uid != 0 && access(nolog, 0) == 0){
		showmotd(nolog);
		exit(0);
	}
	if(chdir(pwd->pw_dir) < 0) {
		printf("No directory\n");
		if(pwd->pw_uid != 0 || (access(nolog, 0) < 0))
			goto loop;
	}
	setlogname(utmp.ut_name);
	if(setupshares(pwd->pw_uid, printf))
		goto loop;
	if (cmd) {		/* remote exec */
		i = strlen(utmp.ut_name);
		if (i < sizeof(utmp.ut_name))
			utmp.ut_name[i] = '*';
	}
	if (ttyn && cmd == 0)
		setut(&utmp);
	if ((f = open("/usr/adm/wtmp", 1)) >= 0) {
		lseek(f, 0L, 2);
		write(f, (char *)&utmp, sizeof(utmp));
		close(f);
	}
	if (ttyn) {
		chown(ttyn, pwd->pw_uid, pwd->pw_gid);
		chmod(ttyn, 0622);
	}
	setgid(pwd->pw_gid);
	setuid(pwd->pw_uid);
	if (*pwd->pw_shell == '\0')
		pwd->pw_shell = "/bin/sh";
	strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
	nenv = 0;
	for(i = 0; environ[i]; i++)
		;
	env = (char **) malloc(sizeof(char *) * (i + 10));
	if (env == NULL) {
		printf("No memory for environment.\n");
		exit(1);
	}
	for (i = 0; environ[i]; i++) {
		if (strncmp(environ[i], "HOME=", 5) == 0)
			continue;
		if (strncmp(environ[i], "PATH=", 5) == 0)
			continue;
		env[nenv++] = environ[i];
	}
	if(homedir[0])
		env[nenv++] = homedir;
	if(path[0])
		env[nenv++] = path;
	env[nenv] = NULL;
	if ((namep = strrchr(pwd->pw_shell, '/')) == NULL)
		namep = pwd->pw_shell;
	else
		namep++;
	strcat(minusnam, namep);
	alarm(0);
	umask(02);
	vlimit(LIM_CORE, 1024*1024);
	if (cmd==NULL) {
		showmotd(motd);
		strcat(maildir, pwd->pw_name);
		if(access(maildir,4)==0) {
			struct stat statb;
			stat(maildir, &statb);
			if (statb.st_size > POSTMKSIZ)
				printf("You have mail.\n");
		}
	}
	signal(SIGQUIT, SIG_DFL);
	signal(SIGINT, SIG_DFL);
	signal(SIGHUP, SIG_DFL);
	environ = env;
	fflush(stdout);
	if (cmd==NULL)
		execlp(pwd->pw_shell, minusnam, 0);
	else {
		env[nenv++] = "REXEC=1";
		ioctl(0, TIOCEXCL, (void *)NULL);
		env[nenv] = 0;
		execlp(pwd->pw_shell, minusnam, "-c", cmd, (char *)0);
	}
	printf("No shell\n");
	exit(0);
}

setut(u)
register struct utmp *u;
{
	register struct utmp *v, *ev;
	struct utmp xtmp[200];
	register int slot;
	register int n, i;
	int fd;

	if ((fd = open("/etc/utmp", 2)) < 0)
		return;
	slot = -1;
	i = 0;
	while ((n = read(fd, (char *)xtmp, sizeof(xtmp))) > 0) {
		ev = &xtmp[n/sizeof(struct utmp)];
		for (v = xtmp; v < ev; i++, v++) {
			if (slot < 0 && v->ut_line[0] == 0) {
				slot = i;
				continue;
			}
			if (strncmp(u->ut_line, v->ut_line, sizeof(v->ut_line))==0) {
				slot = i;
				goto found;
			}
		}
	}
	if (slot < 0)		/* no empties found */
		slot = i;
found:
	lseek(fd, (off_t)slot*sizeof(struct utmp), 0);
	write(fd, (char *)u, sizeof(*u));
	close(fd);
}

int	stopmotd;
catch()
{
	signal(SIGINT, SIG_IGN);
	stopmotd++;
}

showmotd(f)
char *f;
{
	register FILE *mf;
	register c;

	signal(SIGINT, catch);
	if((mf = fopen(f, "r")) != NULL) {
		while((c = getc(mf)) != EOF && stopmotd == 0)
			putchar(c);
		fclose(mf);
		fflush(stdout);
	}
	signal(SIGINT, SIG_IGN);
}