xref: /csrg-svn/usr.bin/login/login.c (revision 36515)
119843Sdist /*
2*36515Sbostic  * Copyright (c) 1980, 1987, 1988 The Regents of the University of California.
3*36515Sbostic  * All rights reserved.
4*36515Sbostic  *
5*36515Sbostic  * Redistribution and use in source and binary forms are permitted
6*36515Sbostic  * provided that the above copyright notice and this paragraph are
7*36515Sbostic  * duplicated in all such forms and that any documentation,
8*36515Sbostic  * advertising materials, and other materials related to such
9*36515Sbostic  * distribution and use acknowledge that the software was developed
10*36515Sbostic  * by the University of California, Berkeley.  The name of the
11*36515Sbostic  * University may not be used to endorse or promote products derived
12*36515Sbostic  * from this software without specific prior written permission.
13*36515Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14*36515Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15*36515Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1619843Sdist  */
1719843Sdist 
1812678Ssam #ifndef lint
1919843Sdist char copyright[] =
20*36515Sbostic "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\
2119843Sdist  All rights reserved.\n";
22*36515Sbostic #endif /* not lint */
2312678Ssam 
2419843Sdist #ifndef lint
25*36515Sbostic static char sccsid[] = "@(#)login.c	5.25 (Berkeley) 01/06/89";
26*36515Sbostic #endif /* not lint */
2719843Sdist 
281043Sbill /*
291043Sbill  * login [ name ]
3031695Skarels  * login -r hostname	(for rlogind)
3131695Skarels  * login -h hostname	(for telnetd, etc.)
3231695Skarels  * login -f name	(for pre-authenticated login: datakit, xterm, etc.)
331043Sbill  */
341043Sbill 
3512984Ssam #include <sys/param.h>
3612687Ssam #include <sys/quota.h>
3712687Ssam #include <sys/stat.h>
3812687Ssam #include <sys/time.h>
3912687Ssam #include <sys/resource.h>
4016453Sroot #include <sys/file.h>
4136460Sbostic #include <sys/ioctl.h>
4212687Ssam 
431043Sbill #include <utmp.h>
441043Sbill #include <signal.h>
451043Sbill #include <lastlog.h>
4612678Ssam #include <errno.h>
4716453Sroot #include <ttyent.h>
4816453Sroot #include <syslog.h>
4926862Smckusick #include <grp.h>
5036460Sbostic #include <pwd.h>
51*36515Sbostic #include <setjmp.h>
5236460Sbostic #include <stdio.h>
5336460Sbostic #include <strings.h>
541043Sbill 
5536460Sbostic #define	TTYGRPNAME	"tty"		/* name of group to own ttys */
5626862Smckusick 
5736460Sbostic #define	MOTDFILE	"/etc/motd"
5836460Sbostic #define	MAILDIR		"/usr/spool/mail"
5936460Sbostic #define	NOLOGIN		"/etc/nologin"
6036460Sbostic #define	HUSHLOGIN	".hushlogin"
6136460Sbostic #define	LASTLOG		"/usr/adm/lastlog"
6236460Sbostic #define	BSHELL		"/bin/sh"
632822Swnj 
6412687Ssam /*
6536460Sbostic  * This bounds the time given to login.  Not a define so it can
6636460Sbostic  * be patched on machines where it's too small.
6712687Ssam  */
6831509Sbostic int	timeout = 300;
696005Swnj 
7036460Sbostic struct passwd *pwd;
7136460Sbostic char term[64], *hostname, *username;
726005Swnj 
73*36515Sbostic struct sgttyb sgttyb;
7436460Sbostic struct tchars tc = {
7513074Ssam 	CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
761365Sbill };
7736460Sbostic struct ltchars ltc = {
7813074Ssam 	CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
7913074Ssam };
801365Sbill 
811043Sbill main(argc, argv)
8236460Sbostic 	int argc;
8336460Sbostic 	char **argv;
841043Sbill {
8536460Sbostic 	extern int errno, optind;
8636460Sbostic 	extern char *optarg, **environ;
8736460Sbostic 	struct group *gr;
8836460Sbostic 	register int ch;
8936460Sbostic 	register char *p;
9036460Sbostic 	int fflag, hflag, pflag, rflag, cnt;
9136460Sbostic 	int quietlog, passwd_req, ioctlval, timedout();
92*36515Sbostic 	char *domain, *salt, *envinit[1], *ttyn, *tty;
9336460Sbostic 	char tbuf[MAXPATHLEN + 2];
9436460Sbostic 	char *ttyname(), *stypeof(), *crypt(), *getpass();
9536460Sbostic 	time_t time();
9636460Sbostic 	off_t lseek();
971043Sbill 
9836460Sbostic 	(void)signal(SIGALRM, timedout);
9936460Sbostic 	(void)alarm((u_int)timeout);
10036460Sbostic 	(void)signal(SIGQUIT, SIG_IGN);
10136460Sbostic 	(void)signal(SIGINT, SIG_IGN);
10236460Sbostic 	(void)setpriority(PRIO_PROCESS, 0, 0);
10336460Sbostic 	(void)quota(Q_SETUID, 0, 0, 0);
10436460Sbostic 
10512687Ssam 	/*
10618549Ssam 	 * -p is used by getty to tell login not to destroy the environment
10712687Ssam 	 * -r is used by rlogind to cause the autologin protocol;
10831695Skarels  	 * -f is used to skip a second login authentication
10912687Ssam 	 * -h is used by other servers to pass the name of the
11012687Ssam 	 * remote host to login so that it may be placed in utmp and wtmp
11112687Ssam 	 */
11236460Sbostic 	(void)gethostname(tbuf, sizeof(tbuf));
11336460Sbostic 	domain = index(tbuf, '.');
11436460Sbostic 
11536460Sbostic 	fflag = hflag = pflag = rflag = 0;
11636460Sbostic 	passwd_req = 1;
117*36515Sbostic 	while ((ch = getopt(argc, argv, "fh:pr:")) != EOF)
118*36515Sbostic 		switch (ch) {
11936460Sbostic 		case 'f':
12036460Sbostic 			if (rflag) {
12136460Sbostic 				fprintf(stderr,
12236460Sbostic 				    "login: only one of -r and -f allowed.\n");
12324712Sbloom 				exit(1);
12424712Sbloom 			}
12536460Sbostic 			fflag = 1;
12636460Sbostic 			break;
12736460Sbostic 		case 'h':
12836460Sbostic 			if (getuid()) {
12936460Sbostic 				fprintf(stderr,
13036460Sbostic 				    "login: -h for super-user only.\n");
13132313Sbostic 				exit(1);
13231695Skarels 			}
13331695Skarels 			if (rflag) {
13436460Sbostic 				fprintf(stderr,
13536460Sbostic 				    "login: only one of -r and -h allowed.\n");
13624712Sbloom 				exit(1);
13724712Sbloom 			}
13836460Sbostic 			hflag = 1;
13936460Sbostic 			if (domain && (p = index(optarg, '.')) &&
14036460Sbostic 			    strcmp(p, domain) == 0)
14136460Sbostic 				*p = 0;
14236460Sbostic 			hostname = optarg;
14336460Sbostic 			break;
14436460Sbostic 		case 'p':
14518549Ssam 			pflag = 1;
14636460Sbostic 			break;
14736460Sbostic 		case 'r':
14836460Sbostic 			if (hflag || fflag) {
14936460Sbostic 				fprintf(stderr,
15036460Sbostic 				    "login: -f and -h not allowed with -r.\n");
15136460Sbostic 				exit(1);
15236460Sbostic 			}
153*36515Sbostic 			if (getuid()) {
154*36515Sbostic 				fprintf(stderr,
155*36515Sbostic 				    "login: -r for super-user only.\n");
156*36515Sbostic 				exit(1);
157*36515Sbostic 			}
158*36515Sbostic 			/* "-r hostname" must be last args */
159*36515Sbostic 			if (optind != argc) {
160*36515Sbostic 				fprintf(stderr, "Syntax error.\n");
161*36515Sbostic 				exit(1);
162*36515Sbostic 			}
16336460Sbostic 			rflag = 1;
164*36515Sbostic 			passwd_req = (doremotelogin(optarg) == -1);
16536460Sbostic 			if (domain && (p = index(optarg, '.')) &&
16636460Sbostic 			    !strcmp(p, domain))
16736460Sbostic 				*p = '\0';
16836460Sbostic 			hostname = optarg;
16936460Sbostic 			break;
17036460Sbostic 		case '?':
17136460Sbostic 		default:
172*36515Sbostic 			fprintf(stderr, "usage: login [-fp] [username]\n");
17336460Sbostic 			exit(1);
17418549Ssam 		}
17536460Sbostic 	argc -= optind;
17636460Sbostic 	argv += optind;
17736460Sbostic 	if (*argv)
17836460Sbostic 		username = *argv;
17936460Sbostic 
18036460Sbostic 	ioctlval = 0;
18136460Sbostic 	(void)ioctl(0, TIOCLSET, &ioctlval);
18236460Sbostic 	(void)ioctl(0, TIOCNXCL, 0);
183*36515Sbostic 	(void)fcntl(0, F_SETFL, ioctlval);
184*36515Sbostic 	(void)ioctl(0, TIOCGETP, &sgttyb);
18536460Sbostic 
18612687Ssam 	/*
18736460Sbostic 	 * If talking to an rlogin process, propagate the terminal type and
18812687Ssam 	 * baud rate across the network.
18912687Ssam 	 */
19012687Ssam 	if (rflag)
191*36515Sbostic 		doremoteterm(&sgttyb);
192*36515Sbostic 	sgttyb.sg_erase = CERASE;
193*36515Sbostic 	sgttyb.sg_kill = CKILL;
19436460Sbostic 	(void)ioctl(0, TIOCSLTC, &ltc);
19536460Sbostic 	(void)ioctl(0, TIOCSETC, &tc);
196*36515Sbostic 	(void)ioctl(0, TIOCSETP, &sgttyb);
19736460Sbostic 
19836460Sbostic 	for (cnt = getdtablesize(); cnt > 2; cnt--)
19936460Sbostic 		close(cnt);
20036460Sbostic 
2011043Sbill 	ttyn = ttyname(0);
20236460Sbostic 	if (ttyn == NULL || *ttyn == '\0')
2031043Sbill 		ttyn = "/dev/tty??";
20436460Sbostic 	if (tty = rindex(ttyn, '/'))
20536460Sbostic 		++tty;
20636460Sbostic 	else
20716453Sroot 		tty = ttyn;
20836460Sbostic 
20924852Seric 	openlog("login", LOG_ODELAY, LOG_AUTH);
21036460Sbostic 
21136460Sbostic 	for (cnt = 0;; username = NULL) {
21236460Sbostic 		ioctlval = 0;
21336460Sbostic 		(void)ioctl(0, TIOCSETD, &ioctlval);
21436460Sbostic 
215*36515Sbostic 		if (username == NULL) {
216*36515Sbostic 			fflag = 0;
21736460Sbostic 			getloginname();
218*36515Sbostic 		}
219*36515Sbostic 		if (pwd = getpwnam(username))
220*36515Sbostic 			salt = pwd->pw_passwd;
221*36515Sbostic 		else
222*36515Sbostic 			salt = "xx";
22336460Sbostic 
22436460Sbostic 		/* if user not super-user, check for disabled logins */
225*36515Sbostic 		if (pwd == NULL || pwd->pw_uid)
22636460Sbostic 			checknologin();
22736460Sbostic 
22812687Ssam 		/*
229*36515Sbostic 		 * Disallow automatic login to root; if not invoked by
230*36515Sbostic 		 * root, disallow if the uid's differ.
23112687Ssam 		 */
232*36515Sbostic 		if (fflag && pwd) {
23331695Skarels 			int uid = getuid();
23431695Skarels 
235*36515Sbostic 			passwd_req = pwd->pw_uid == 0 ||
236*36515Sbostic 			    (uid && uid != pwd->pw_uid);
23731695Skarels 		}
23836460Sbostic 
23912687Ssam 		/*
24036460Sbostic 		 * If no remote login authentication and a password exists
24136460Sbostic 		 * for this user, prompt for one and verify it.
24212687Ssam 		 */
243*36515Sbostic 		if (!passwd_req || pwd && !*pwd->pw_passwd)
24436460Sbostic 			break;
24512687Ssam 
24636460Sbostic 		setpriority(PRIO_PROCESS, 0, -4);
247*36515Sbostic 		p = crypt(getpass("Password:"), salt);
24836460Sbostic 		setpriority(PRIO_PROCESS, 0, 0);
249*36515Sbostic 		if (pwd && !strcmp(p, pwd->pw_passwd))
25036460Sbostic 			break;
25136460Sbostic 
25236460Sbostic 		printf("Login incorrect\n");
25336460Sbostic 		if (++cnt >= 5) {
25436460Sbostic 			if (hostname)
25536460Sbostic 			    syslog(LOG_ERR,
25636460Sbostic 				"REPEATED LOGIN FAILURES ON %s FROM %.*s, %.*s",
25736460Sbostic 				tty, UT_HOSTSIZE, hostname, UT_NAMESIZE,
25836460Sbostic 				username);
25925230Smckusick 			else
26036460Sbostic 			    syslog(LOG_ERR,
26136460Sbostic 				"REPEATED LOGIN FAILURES ON %s, %.*s",
26236460Sbostic 				tty, UT_NAMESIZE, username);
26336460Sbostic 			(void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL);
26436460Sbostic 			sleepexit(1);
2652822Swnj 		}
26636460Sbostic 	}
2671043Sbill 
26836460Sbostic 	/* committed to login -- turn off timeout */
26936460Sbostic 	(void)alarm((u_int)0);
27036460Sbostic 
27136460Sbostic 	/*
27236460Sbostic 	 * If valid so far and root is logging in, see if root logins on
27336460Sbostic 	 * this terminal are permitted.
27436460Sbostic 	 */
275*36515Sbostic 	if (pwd->pw_uid == 0 && !rootterm(tty)) {
27636460Sbostic 		if (hostname)
277*36515Sbostic 			syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s FROM %.*s",
27836460Sbostic 			    tty, UT_HOSTSIZE, hostname);
27912678Ssam 		else
280*36515Sbostic 			syslog(LOG_ERR, "ROOT LOGIN REFUSED ON %s", tty);
28136460Sbostic 		printf("Login incorrect\n");
28236460Sbostic 		sleepexit(1);
28312678Ssam 	}
2842822Swnj 
28536460Sbostic 	if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
28636460Sbostic 		switch(errno) {
28736460Sbostic 		case EUSERS:
28836460Sbostic 			fprintf(stderr,
28936460Sbostic 		"Too many users logged on already.\nTry again later.\n");
29036460Sbostic 			break;
29136460Sbostic 		case EPROCLIM:
29236460Sbostic 			fprintf(stderr,
29336460Sbostic 			    "You have too many processes running.\n");
29436460Sbostic 			break;
29536460Sbostic 		default:
29636460Sbostic 			perror("quota (Q_SETUID)");
2972822Swnj 		}
29836460Sbostic 		sleepexit(0);
2992822Swnj 	}
30036460Sbostic 
301*36515Sbostic 	if (chdir(pwd->pw_dir) < 0) {
302*36515Sbostic 		printf("No directory %s!\n", pwd->pw_dir);
303*36515Sbostic 		if (chdir("/"))
304*36515Sbostic 			exit(0);
305*36515Sbostic 		pwd->pw_dir = "/";
306*36515Sbostic 		printf("Logging in with home = \"/\".\n");
307*36515Sbostic 	}
308*36515Sbostic 
309*36515Sbostic 	/* nothing else left to fail -- really log in */
31036460Sbostic 	{
31136460Sbostic 		struct utmp utmp;
31236460Sbostic 
31336460Sbostic 		(void)time(&utmp.ut_time);
31436460Sbostic 		strncpy(utmp.ut_name, username, sizeof(utmp.ut_name));
31536460Sbostic 		strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host));
31636460Sbostic 		strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
31736460Sbostic 		login(&utmp);
31836460Sbostic 	}
31936460Sbostic 
32036460Sbostic 	quietlog = access(HUSHLOGIN, F_OK) == 0;
32136460Sbostic 	dolastlog(quietlog, tty);
32236460Sbostic 
32336460Sbostic 	if (!hflag && !rflag) {					/* XXX */
32436460Sbostic 		static struct winsize win = { 0, 0, 0, 0 };
32536460Sbostic 
32636460Sbostic 		(void)ioctl(0, TIOCSWINSZ, &win);
32736460Sbostic 	}
32836460Sbostic 
32936460Sbostic 	(void)chown(ttyn, pwd->pw_uid,
33036460Sbostic 	    (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid);
33136460Sbostic 	(void)chmod(ttyn, 0620);
33236460Sbostic 	(void)setgid(pwd->pw_gid);
33336460Sbostic 
33436460Sbostic 	initgroups(username, pwd->pw_gid);
33536460Sbostic 
33612678Ssam 	quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
33736460Sbostic 	(void)setuid(pwd->pw_uid);
33830606Sbostic 
339*36515Sbostic 	if (*pwd->pw_shell == '\0')
340*36515Sbostic 		pwd->pw_shell = BSHELL;
341*36515Sbostic 	/* turn on new line discipline for the csh */
342*36515Sbostic 	else if (!strcmp(pwd->pw_shell, "/bin/csh")) {
343*36515Sbostic 		ioctlval = NTTYDISC;
344*36515Sbostic 		(void)ioctl(0, TIOCSETD, &ioctlval);
345*36515Sbostic 	}
346*36515Sbostic 
34736460Sbostic 	/* destroy environment unless user has requested preservation */
34818549Ssam 	if (!pflag)
34918549Ssam 		environ = envinit;
350*36515Sbostic 	(void)setenv("HOME", pwd->pw_dir, 1);
351*36515Sbostic 	(void)setenv("SHELL", pwd->pw_shell, 1);
35218549Ssam 	if (term[0] == '\0')
35318549Ssam 		strncpy(term, stypeof(tty), sizeof(term));
354*36515Sbostic 	(void)setenv("TERM", term, 0);
355*36515Sbostic 	(void)setenv("USER", pwd->pw_name, 1);
356*36515Sbostic 	(void)setenv("PATH", "/usr/ucb:/bin:/usr/bin:", 0);
35718549Ssam 
35816453Sroot 	if (tty[sizeof("tty")-1] == 'd')
35918549Ssam 		syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
36018549Ssam 	if (pwd->pw_uid == 0)
36136460Sbostic 		if (hostname)
36225230Smckusick 			syslog(LOG_NOTICE, "ROOT LOGIN %s FROM %.*s",
36336460Sbostic 			    tty, UT_HOSTSIZE, hostname);
36425230Smckusick 		else
36525230Smckusick 			syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
36636460Sbostic 
3676329Swnj 	if (!quietlog) {
36817664Sserge 		struct stat st;
36918549Ssam 
37036460Sbostic 		motd();
37136460Sbostic 		(void)sprintf(tbuf, "%s/%s", MAILDIR, pwd->pw_name);
37236460Sbostic 		if (stat(tbuf, &st) == 0 && st.st_size != 0)
37317664Sserge 			printf("You have %smail.\n",
37436460Sbostic 			    (st.st_mtime > st.st_atime) ? "new " : "");
3752822Swnj 	}
37636460Sbostic 
37736460Sbostic 	(void)signal(SIGALRM, SIG_DFL);
37836460Sbostic 	(void)signal(SIGQUIT, SIG_DFL);
37936460Sbostic 	(void)signal(SIGINT, SIG_DFL);
38036460Sbostic 	(void)signal(SIGTSTP, SIG_IGN);
38136460Sbostic 
38236460Sbostic 	tbuf[0] = '-';
38336460Sbostic 	strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ?
38436460Sbostic 	    p + 1 : pwd->pw_shell);
38536460Sbostic 	execlp(pwd->pw_shell, tbuf, 0);
386*36515Sbostic 	fprintf(stderr, "login: no shell: ");
3872822Swnj 	perror(pwd->pw_shell);
3881043Sbill 	exit(0);
3891043Sbill }
3901043Sbill 
39136460Sbostic getloginname()
39212687Ssam {
39336460Sbostic 	register int ch;
39436460Sbostic 	register char *p;
39536460Sbostic 	static char nbuf[UT_NAMESIZE + 1];
39612687Ssam 
39736460Sbostic 	for (;;) {
39812712Ssam 		printf("login: ");
399*36515Sbostic 		for (p = nbuf; (ch = getchar()) != '\n'; ) {
40036460Sbostic 			if (ch == EOF)
40112687Ssam 				exit(0);
402*36515Sbostic 			if (p < nbuf + UT_NAMESIZE)
40336460Sbostic 				*p++ = ch;
40412687Ssam 		}
40536460Sbostic 		if (p > nbuf)
40636460Sbostic 			if (nbuf[0] == '-')
40736460Sbostic 				fprintf(stderr,
40836460Sbostic 				    "login names may not start with '-'.\n");
40936460Sbostic 			else {
41036460Sbostic 				*p = '\0';
41136460Sbostic 				username = nbuf;
412*36515Sbostic 				break;
41336460Sbostic 			}
41412687Ssam 	}
41512687Ssam }
41612687Ssam 
41712687Ssam timedout()
41812687Ssam {
41936460Sbostic 	fprintf(stderr, "Login timed out after %d seconds\n", timeout);
42012687Ssam 	exit(0);
42112687Ssam }
42212687Ssam 
42336460Sbostic rootterm(tty)
42436460Sbostic 	char *tty;
4251043Sbill {
42636460Sbostic 	struct ttyent *t;
4276466Swnj 
42836460Sbostic 	return((t = getttynam(tty)) && t->ty_status&TTY_SECURE);
4291043Sbill }
4301043Sbill 
431*36515Sbostic jmp_buf motdinterrupt;
432*36515Sbostic 
43336460Sbostic motd()
4342822Swnj {
435*36515Sbostic 	register int fd, nchars;
43636460Sbostic 	int (*oldint)(), sigint();
437*36515Sbostic 	char tbuf[8192];
4382822Swnj 
439*36515Sbostic 	if ((fd = open(MOTDFILE, O_RDONLY, 0)) < 0)
44036460Sbostic 		return;
44136460Sbostic 	oldint = signal(SIGINT, sigint);
442*36515Sbostic 	if (setjmp(motdinterrupt) == 0)
443*36515Sbostic 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
444*36515Sbostic 			(void)write(fileno(stdout), tbuf, nchars);
44536460Sbostic 	(void)signal(SIGINT, oldint);
446*36515Sbostic 	(void)close(fd);
44736460Sbostic }
44836460Sbostic 
44936460Sbostic sigint()
45036460Sbostic {
451*36515Sbostic 	longjmp(motdinterrupt, 1);
45236460Sbostic }
45336460Sbostic 
45436460Sbostic checknologin()
45536460Sbostic {
45636460Sbostic 	register int fd, nchars;
457*36515Sbostic 	char tbuf[8192];
45836460Sbostic 
45936460Sbostic 	if ((fd = open(NOLOGIN, O_RDONLY, 0)) >= 0) {
46036460Sbostic 		while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0)
46136460Sbostic 			(void)write(fileno(stdout), tbuf, nchars);
46236460Sbostic 		sleepexit(0);
4632822Swnj 	}
4642822Swnj }
4652822Swnj 
46636460Sbostic dolastlog(quiet, tty)
46736460Sbostic 	int quiet;
46836460Sbostic 	char *tty;
4691043Sbill {
47036460Sbostic 	struct lastlog ll;
47136460Sbostic 	int fd;
4721043Sbill 
47336460Sbostic 	if ((fd = open(LASTLOG, O_RDWR, 0)) >= 0) {
474*36515Sbostic 		(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
47536460Sbostic 		if (!quiet) {
47636460Sbostic 			if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) &&
47736460Sbostic 			    ll.ll_time != 0) {
47836460Sbostic 				printf("Last login: %.*s ",
47936460Sbostic 				    24-5, (char *)ctime(&ll.ll_time));
48036460Sbostic 				if (*ll.ll_host != '\0')
48136460Sbostic 					printf("from %.*s\n",
48236460Sbostic 					    sizeof(ll.ll_host), ll.ll_host);
48336460Sbostic 				else
48436460Sbostic 					printf("on %.*s\n",
48536460Sbostic 					    sizeof(ll.ll_line), ll.ll_line);
48636460Sbostic 			}
487*36515Sbostic 			(void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET);
48836460Sbostic 		}
48936460Sbostic 		(void)time(&ll.ll_time);
49036460Sbostic 		strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
49136460Sbostic 		strncpy(ll.ll_host, hostname, sizeof(ll.ll_host));
49236460Sbostic 		(void)write(fd, (char *)&ll, sizeof(ll));
49336460Sbostic 		(void)close(fd);
4941043Sbill 	}
4951043Sbill }
4961043Sbill 
4972822Swnj #undef	UNKNOWN
49836460Sbostic #define	UNKNOWN	"su"
4991043Sbill 
5001043Sbill char *
5011043Sbill stypeof(ttyid)
50212687Ssam 	char *ttyid;
5031043Sbill {
50436460Sbostic 	struct ttyent *t;
5051043Sbill 
50636460Sbostic 	return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN);
5071043Sbill }
5086005Swnj 
50912687Ssam doremotelogin(host)
51012687Ssam 	char *host;
51112687Ssam {
51236460Sbostic 	static char lusername[UT_NAMESIZE+1];
51336460Sbostic 	char rusername[UT_NAMESIZE+1];
51436460Sbostic 
51536460Sbostic 	getstr(rusername, sizeof(rusername), "remuser");
51636460Sbostic 	getstr(lusername, sizeof(lusername), "locuser");
51718549Ssam 	getstr(term, sizeof(term), "Terminal type");
51836460Sbostic 	username = lusername;
51936460Sbostic 	pwd = getpwnam(username);
520*36515Sbostic 	if (pwd == NULL)
52124712Sbloom 		return(-1);
52236460Sbostic 	return(ruserok(host, (pwd->pw_uid == 0), rusername, username));
52312687Ssam }
52412687Ssam 
5256005Swnj getstr(buf, cnt, err)
52636460Sbostic 	char *buf, *err;
5276005Swnj 	int cnt;
5286005Swnj {
52936460Sbostic 	char ch;
5306005Swnj 
5316005Swnj 	do {
53236460Sbostic 		if (read(0, &ch, sizeof(ch)) != sizeof(ch))
5336005Swnj 			exit(1);
5346005Swnj 		if (--cnt < 0) {
53536460Sbostic 			fprintf(stderr, "%s too long\r\n", err);
53636460Sbostic 			sleepexit(1);
5376005Swnj 		}
53836460Sbostic 		*buf++ = ch;
53936460Sbostic 	} while (ch);
5406005Swnj }
5416329Swnj 
54236460Sbostic char *speeds[] = {
54336460Sbostic 	"0", "50", "75", "110", "134", "150", "200", "300", "600",
54436460Sbostic 	"1200", "1800", "2400", "4800", "9600", "19200", "38400",
54536460Sbostic };
54636460Sbostic #define	NSPEEDS	(sizeof(speeds) / sizeof(speeds[0]))
54712687Ssam 
54836460Sbostic doremoteterm(tp)
54912687Ssam 	struct sgttyb *tp;
55012687Ssam {
55118549Ssam 	register char *cp = index(term, '/'), **cpp;
55218549Ssam 	char *speed;
55312687Ssam 
55412687Ssam 	if (cp) {
55518549Ssam 		*cp++ = '\0';
55618549Ssam 		speed = cp;
55718549Ssam 		cp = index(speed, '/');
55818549Ssam 		if (cp)
55918549Ssam 			*cp++ = '\0';
56018549Ssam 		for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
56118549Ssam 			if (strcmp(*cpp, speed) == 0) {
56218549Ssam 				tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
56312687Ssam 				break;
56412687Ssam 			}
56512687Ssam 	}
56612687Ssam 	tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
56712687Ssam }
56818549Ssam 
56936460Sbostic sleepexit(eval)
57036460Sbostic 	int eval;
57126862Smckusick {
57236460Sbostic 	sleep((u_int)5);
57336460Sbostic 	exit(eval);
57426862Smckusick }
575