xref: /original-bsd/usr.bin/login/login.c.1 (revision 264c46cb)
1#ifndef lint
2static	char *sccsid = "@(#)login.c.1	4.31 (Berkeley) 83/06/30";
3#endif
4
5/*
6 * login [ name ]
7 * login -r hostname (for rlogind)
8 * login -h hostname (for telnetd, etc.)
9 */
10
11#include <sys/param.h>
12#include <sys/quota.h>
13#include <sys/stat.h>
14#include <sys/time.h>
15#include <sys/resource.h>
16
17#include <sgtty.h>
18#include <utmp.h>
19#include <signal.h>
20#include <pwd.h>
21#include <stdio.h>
22#include <lastlog.h>
23#include <errno.h>
24
25#define	SCPYN(a, b)	strncpy(a, b, sizeof(a))
26
27#define NMAX	sizeof(utmp.ut_name)
28
29#define	FALSE	0
30#define	TRUE	-1
31
32char	nolog[] =	"/etc/nologin";
33char	qlog[]  =	".hushlogin";
34char	securetty[] =	"/etc/securetty";
35char	maildir[30] =	"/usr/spool/mail/";
36char	lastlog[] =	"/usr/adm/lastlog";
37struct	passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" };
38struct	sgttyb ttyb;
39struct	utmp utmp;
40char	minusnam[16] = "-";
41/*
42 * This bounds the time given to login.  We initialize it here
43 * so it can be patched on machines where it's too small.
44 */
45int	timeout = 60;
46
47char	homedir[64] = "HOME=";
48char	shell[64] = "SHELL=";
49char	term[64] = "TERM=";
50char	user[20] = "USER=";
51
52char	*envinit[] =
53    { homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", term, user, 0 };
54
55struct	passwd *pwd;
56struct	passwd *getpwnam();
57char	*strcat(), *rindex(), *index();
58int	setpwent();
59int	timedout();
60char	*ttyname();
61char	*crypt();
62char	*getpass();
63char	*stypeof();
64extern	char **environ;
65extern	int errno;
66
67struct	tchars tc = {
68	CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
69};
70struct	ltchars ltc = {
71	CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT
72};
73
74int	rflag;
75char	rusername[NMAX+1], lusername[NMAX+1];
76char	rpassword[NMAX+1];
77char	name[NMAX+1];
78char	*rhost;
79
80main(argc, argv)
81	char *argv[];
82{
83	register char *namep;
84	int t, f, c, i;
85	int invalid, quietlog;
86	FILE *nlfd;
87	char *ttyn;
88	int ldisc = 0, zero = 0;
89
90	signal(SIGALRM, timedout);
91	alarm(timeout);
92	signal(SIGQUIT, SIG_IGN);
93	signal(SIGINT, SIG_IGN);
94	setpriority(PRIO_PROCESS, 0, 0);
95	quota(Q_SETUID, 0, 0, 0);
96	/*
97	 * -r is used by rlogind to cause the autologin protocol;
98	 * -h is used by other servers to pass the name of the
99	 * remote host to login so that it may be placed in utmp and wtmp
100	 */
101	if (argc > 1) {
102		if (strcmp(argv[1], "-r") == 0) {
103			rflag = doremotelogin(argv[2]);
104			SCPYN(utmp.ut_host, argv[2]);
105			argc = 0;
106		}
107		if (strcmp(argv[1], "-h") == 0 && getuid() == 0) {
108			SCPYN(utmp.ut_host, argv[2]);
109			argc = 0;
110		}
111	}
112	ioctl(0, TIOCLSET, &zero);
113	ioctl(0, TIOCNXCL, 0);
114	ioctl(0, FIONBIO, &zero);
115	ioctl(0, FIOASYNC, &zero);
116	ioctl(0, TIOCGETP, &ttyb);
117	/*
118	 * If talking to an rlogin process,
119	 * propagate the terminal type and
120	 * baud rate across the network.
121	 */
122	if (rflag)
123		doremoteterm(term, &ttyb);
124	ioctl(0, TIOCSLTC, &ltc);
125	ioctl(0, TIOCSETC, &tc);
126	ioctl(0, TIOCSETP, &ttyb);
127	for (t = getdtablesize(); t > 3; t--)
128		close(t);
129	ttyn = ttyname(0);
130	if (ttyn==(char *)0)
131		ttyn = "/dev/tty??";
132	do {
133		ldisc = 0;
134		ioctl(0, TIOCSETD, &ldisc);
135		invalid = FALSE;
136		SCPYN(utmp.ut_name, "");
137		/*
138		 * Name specified, take it.
139		 */
140		if (argc > 1) {
141			SCPYN(utmp.ut_name, argv[1]);
142			argc = 0;
143		}
144		/*
145		 * If remote login take given name,
146		 * otherwise prompt user for something.
147		 */
148		if (rflag) {
149			SCPYN(utmp.ut_name, lusername);
150			/* autologin failed, prompt for passwd */
151			if (rflag == -1)
152				rflag = 0;
153		} else
154			getloginname(&utmp);
155		if (!strcmp(pwd->pw_shell, "/bin/csh")) {
156			ldisc = NTTYDISC;
157			ioctl(0, TIOCSETD, &ldisc);
158		}
159		/*
160		 * If no remote login authentication and
161		 * a password exists for this user, prompt
162		 * for one and verify it.
163		 */
164		if (!rflag && *pwd->pw_passwd != '\0') {
165			char *pp;
166
167			setpriority(PRIO_PROCESS, 0, -4);
168			pp = getpass("Password:");
169			namep = crypt(pp, pwd->pw_passwd);
170			setpriority(PRIO_PROCESS, 0, 0);
171			if (strcmp(namep, pwd->pw_passwd))
172				invalid = TRUE;
173		}
174		/*
175		 * If user not super-user, check for logins disabled.
176		 */
177		if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) {
178			while ((c = getc(nlfd)) != EOF)
179				putchar(c);
180			fflush(stdout);
181			sleep(5);
182			exit(0);
183		}
184		/*
185		 * If valid so far and root is logging in,
186		 * see if root logins on this terminal are permitted.
187		 */
188		if (!invalid && pwd->pw_uid == 0 &&
189		    !rootterm(ttyn+sizeof("/dev/")-1)) {
190			logerr("ROOT LOGIN REFUSED %s",
191			    ttyn+sizeof("/dev/")-1);
192			invalid = TRUE;
193		}
194		if (invalid) {
195			printf("Login incorrect\n");
196			if (ttyn[sizeof("/dev/tty")-1] == 'd')
197				logerr("BADDIALUP %s %s\n",
198				    ttyn+sizeof("/dev/")-1, utmp.ut_name);
199		}
200		if (*pwd->pw_shell == '\0')
201			pwd->pw_shell = "/bin/sh";
202		i = strlen(pwd->pw_shell);
203		if (chdir(pwd->pw_dir) < 0 && !invalid ) {
204			if (chdir("/") < 0) {
205				printf("No directory!\n");
206				invalid = TRUE;
207			} else {
208				printf("No directory! %s\n",
209				   "Logging in with home=/");
210				pwd->pw_dir = "/";
211			}
212		}
213		/*
214		 * Remote login invalid must have been because
215		 * of a restriction of some sort, no extra chances.
216		 */
217		if (rflag && invalid)
218			exit(1);
219	} while (invalid);
220/* committed to login turn off timeout */
221	alarm(0);
222
223	if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0) {
224		if (errno == EUSERS)
225			printf("%s.\n%s.\n",
226			   "Too many users logged on already",
227			   "Try again later");
228		else if (errno == EPROCLIM)
229			printf("You have too many processes running.\n");
230		else
231			perror("setuid");
232		sleep(5);
233		exit(0);
234	}
235	time(&utmp.ut_time);
236	t = ttyslot();
237	if (t > 0 && (f = open("/etc/utmp", 1)) >= 0) {
238		lseek(f, (long)(t*sizeof(utmp)), 0);
239		SCPYN(utmp.ut_line, rindex(ttyn, '/')+1);
240		write(f, (char *)&utmp, sizeof(utmp));
241		close(f);
242	}
243	if (t > 0 && (f = open("/usr/adm/wtmp", 1)) >= 0) {
244		lseek(f, 0L, 2);
245		write(f, (char *)&utmp, sizeof(utmp));
246		close(f);
247	}
248	quietlog = access(qlog, 0) == 0;
249	if ((f = open(lastlog, 2)) >= 0) {
250		struct lastlog ll;
251
252		lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
253		if (read(f, (char *) &ll, sizeof ll) == sizeof ll &&
254		    ll.ll_time != 0 && !quietlog) {
255			printf("Last login: %.*s ",
256			    24-5, (char *)ctime(&ll.ll_time));
257			if (*ll.ll_host != '\0')
258				printf("from %.*s\n",
259				    sizeof (ll.ll_host), ll.ll_host);
260			else
261				printf("on %.*s\n",
262				    sizeof (ll.ll_line), ll.ll_line);
263		}
264		lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
265		time(&ll.ll_time);
266		SCPYN(ll.ll_line, rindex(ttyn, '/')+1);
267		SCPYN(ll.ll_host, utmp.ut_host);
268		write(f, (char *) &ll, sizeof ll);
269		close(f);
270	}
271	chown(ttyn, pwd->pw_uid, pwd->pw_gid);
272	chmod(ttyn, 0622);
273	setgid(pwd->pw_gid);
274	strncpy(name, utmp.ut_name, NMAX);
275	name[NMAX] = '\0';
276	initgroups(name, pwd->pw_gid);
277	quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
278	setuid(pwd->pw_uid);
279	environ = envinit;
280	strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
281	strncat(shell, pwd->pw_shell, sizeof(shell)-7);
282	if (term[strlen("TERM=")] == 0)
283		strncat(term, stypeof(ttyn), sizeof(term)-6);
284	strncat(user, pwd->pw_name, sizeof(user)-6);
285	if ((namep = rindex(pwd->pw_shell, '/')) == NULL)
286		namep = pwd->pw_shell;
287	else
288		namep++;
289	strcat(minusnam, namep);
290	umask(022);
291	if (ttyn[sizeof("/dev/tty")-1] == 'd')
292		logerr("DIALUP %s %s\n", ttyn+sizeof("/dev/")-1, pwd->pw_name);
293	if (!quietlog) {
294		showmotd();
295		strcat(maildir, pwd->pw_name);
296		if (access(maildir,4)==0) {
297			struct stat statb;
298			stat(maildir, &statb);
299			if (statb.st_size)
300				printf("You have mail.\n");
301		}
302	}
303	signal(SIGALRM, SIG_DFL);
304	signal(SIGQUIT, SIG_DFL);
305	signal(SIGINT, SIG_DFL);
306	signal(SIGTSTP, SIG_IGN);
307	execlp(pwd->pw_shell, minusnam, 0);
308	perror(pwd->pw_shell);
309	printf("No shell\n");
310	exit(0);
311}
312
313getloginname(up)
314	register struct utmp *up;
315{
316	register char *namep;
317	char c;
318
319	while (up->ut_name[0] == '\0') {
320		namep = utmp.ut_name;
321		printf("login: ");
322		while ((c = getchar()) != '\n') {
323			if (c == ' ')
324				c = '_';
325			if (c == EOF)
326				exit(0);
327			if (namep < up->ut_name+NMAX)
328				*namep++ = c;
329		}
330	}
331	setpwent();
332	if ((pwd = getpwnam(utmp.ut_name)) == NULL)
333		pwd = &nouser;
334	endpwent();
335}
336
337timedout()
338{
339
340	printf("Login timed out after %d seconds\n", timeout);
341	exit(0);
342}
343
344int	stopmotd;
345catch()
346{
347
348	signal(SIGINT, SIG_IGN);
349	stopmotd++;
350}
351
352rootterm(tty)
353	char *tty;
354{
355	register FILE *fd;
356	char buf[100];
357
358	if ((fd = fopen(securetty, "r")) == NULL)
359		return(1);
360	while (fgets(buf, sizeof buf, fd) != NULL) {
361		buf[strlen(buf)-1] = '\0';
362		if (strcmp(tty, buf) == 0) {
363			fclose(fd);
364			return(1);
365		}
366	}
367	fclose(fd);
368	return(0);
369}
370
371showmotd()
372{
373	FILE *mf;
374	register c;
375
376	signal(SIGINT, catch);
377	if ((mf = fopen("/etc/motd","r")) != NULL) {
378		while ((c = getc(mf)) != EOF && stopmotd == 0)
379			putchar(c);
380		fclose(mf);
381	}
382	signal(SIGINT, SIG_IGN);
383}
384
385#undef	UNKNOWN
386#define UNKNOWN "su"
387
388char *
389stypeof(ttyid)
390	char *ttyid;
391{
392	static char typebuf[16];
393	char buf[50];
394	register FILE *f;
395	register char *p, *t, *q;
396
397	if (ttyid == NULL)
398		return (UNKNOWN);
399	f = fopen("/etc/ttytype", "r");
400	if (f == NULL)
401		return (UNKNOWN);
402	/* split off end of name */
403	for (p = q = ttyid; *p != 0; p++)
404		if (*p == '/')
405			q = p + 1;
406
407	/* scan the file */
408	while (fgets(buf, sizeof buf, f) != NULL) {
409		for (t = buf; *t != ' ' && *t != '\t'; t++)
410			;
411		*t++ = 0;
412		while (*t == ' ' || *t == '\t')
413			t++;
414		for (p = t; *p > ' '; p++)
415			;
416		*p = 0;
417		if (strcmp(q,t) == 0) {
418			strcpy(typebuf, buf);
419			fclose(f);
420			return (typebuf);
421		}
422	}
423	fclose (f);
424	return (UNKNOWN);
425}
426
427doremotelogin(host)
428	char *host;
429{
430	FILE *hostf;
431	int first = 1;
432
433	getstr(rusername, sizeof (rusername), "remuser");
434	getstr(lusername, sizeof (lusername), "locuser");
435	getstr(term+5, sizeof(term)-5, "Terminal type");
436	if (getuid()) {
437		pwd = &nouser;
438		goto bad;
439	}
440	setpwent();
441	pwd = getpwnam(lusername);
442	endpwent();
443	if (pwd == NULL) {
444		pwd = &nouser;
445		goto bad;
446	}
447	hostf = pwd->pw_uid ? fopen("/etc/hosts.equiv", "r") : 0;
448again:
449	if (hostf) {
450		char ahost[32];
451
452		while (fgets(ahost, sizeof (ahost), hostf)) {
453			char *user;
454
455			if ((user = index(ahost, '\n')) != 0)
456				*user++ = '\0';
457			if ((user = index(ahost, ' ')) != 0)
458				*user++ = '\0';
459			if (!strcmp(host, ahost) &&
460			    !strcmp(rusername, user ? user : lusername)) {
461				fclose(hostf);
462				return (1);
463			}
464		}
465		fclose(hostf);
466	}
467	if (first == 1) {
468		char *rhosts = ".rhosts";
469		struct stat sbuf;
470
471		first = 0;
472		if (chdir(pwd->pw_dir) < 0)
473			goto again;
474		if (lstat(rhosts, &sbuf) < 0)
475			goto again;
476		if ((sbuf.st_mode & S_IFMT) == S_IFLNK) {
477			printf("login: .rhosts is a soft link.\r\n");
478			goto bad;
479		}
480		hostf = fopen(rhosts, "r");
481		fstat(fileno(hostf), &sbuf);
482		if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) {
483			printf("login: Bad .rhosts ownership.\r\n");
484			fclose(hostf);
485			goto bad;
486		}
487		goto again;
488	}
489bad:
490	return (-1);
491}
492
493getstr(buf, cnt, err)
494	char *buf;
495	int cnt;
496	char *err;
497{
498	char c;
499
500	do {
501		if (read(0, &c, 1) != 1)
502			exit(1);
503		if (--cnt < 0) {
504			printf("%s too long\r\n", err);
505			exit(1);
506		}
507		*buf++ = c;
508	} while (c != 0);
509}
510
511char	*speeds[] =
512    { "0", "50", "75", "110", "134", "150", "200", "300",
513      "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
514#define	NSPEEDS	(sizeof (speeds) / sizeof (speeds[0]))
515
516doremoteterm(term, tp)
517	char *term;
518	struct sgttyb *tp;
519{
520	char *cp = index(term, '/');
521	register int i;
522
523	if (cp) {
524		*cp++ = 0;
525		for (i = 0; i < NSPEEDS; i++)
526			if (!strcmp(speeds[i], cp)) {
527				tp->sg_ispeed = tp->sg_ospeed = i;
528				break;
529			}
530	}
531	tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
532}
533
534logerr(fmt, a1, a2, a3)
535	char *fmt, *a1, *a2, *a3;
536{
537#ifdef LOGERR
538	FILE *cons = fopen("/dev/console", "w");
539
540	if (cons != NULL) {
541		fprintf(cons, fmt, a1, a2, a3);
542		fputc('\r', cons);
543		fclose(cons);
544	}
545#endif
546}
547