xref: /original-bsd/usr.bin/login/login.c.1 (revision 23a40993)
1#ifndef lint
2static	char *sccsid = "@(#)login.c.1	4.32 (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",
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",
293		    ttyn+sizeof("/dev/")-1, pwd->pw_name);
294	if (!quietlog) {
295		showmotd();
296		strcat(maildir, pwd->pw_name);
297		if (access(maildir,4)==0) {
298			struct stat statb;
299			stat(maildir, &statb);
300			if (statb.st_size)
301				printf("You have mail.\n");
302		}
303	}
304	signal(SIGALRM, SIG_DFL);
305	signal(SIGQUIT, SIG_DFL);
306	signal(SIGINT, SIG_DFL);
307	signal(SIGTSTP, SIG_IGN);
308	execlp(pwd->pw_shell, minusnam, 0);
309	perror(pwd->pw_shell);
310	printf("No shell\n");
311	exit(0);
312}
313
314getloginname(up)
315	register struct utmp *up;
316{
317	register char *namep;
318	char c;
319
320	while (up->ut_name[0] == '\0') {
321		namep = utmp.ut_name;
322		printf("login: ");
323		while ((c = getchar()) != '\n') {
324			if (c == ' ')
325				c = '_';
326			if (c == EOF)
327				exit(0);
328			if (namep < up->ut_name+NMAX)
329				*namep++ = c;
330		}
331	}
332	setpwent();
333	if ((pwd = getpwnam(utmp.ut_name)) == NULL)
334		pwd = &nouser;
335	endpwent();
336}
337
338timedout()
339{
340
341	printf("Login timed out after %d seconds\n", timeout);
342	exit(0);
343}
344
345int	stopmotd;
346catch()
347{
348
349	signal(SIGINT, SIG_IGN);
350	stopmotd++;
351}
352
353rootterm(tty)
354	char *tty;
355{
356	register FILE *fd;
357	char buf[100];
358
359	if ((fd = fopen(securetty, "r")) == NULL)
360		return(1);
361	while (fgets(buf, sizeof buf, fd) != NULL) {
362		buf[strlen(buf)-1] = '\0';
363		if (strcmp(tty, buf) == 0) {
364			fclose(fd);
365			return(1);
366		}
367	}
368	fclose(fd);
369	return(0);
370}
371
372showmotd()
373{
374	FILE *mf;
375	register c;
376
377	signal(SIGINT, catch);
378	if ((mf = fopen("/etc/motd","r")) != NULL) {
379		while ((c = getc(mf)) != EOF && stopmotd == 0)
380			putchar(c);
381		fclose(mf);
382	}
383	signal(SIGINT, SIG_IGN);
384}
385
386#undef	UNKNOWN
387#define UNKNOWN "su"
388
389char *
390stypeof(ttyid)
391	char *ttyid;
392{
393	static char typebuf[16];
394	char buf[50];
395	register FILE *f;
396	register char *p, *t, *q;
397
398	if (ttyid == NULL)
399		return (UNKNOWN);
400	f = fopen("/etc/ttytype", "r");
401	if (f == NULL)
402		return (UNKNOWN);
403	/* split off end of name */
404	for (p = q = ttyid; *p != 0; p++)
405		if (*p == '/')
406			q = p + 1;
407
408	/* scan the file */
409	while (fgets(buf, sizeof buf, f) != NULL) {
410		for (t = buf; *t != ' ' && *t != '\t'; t++)
411			;
412		*t++ = 0;
413		while (*t == ' ' || *t == '\t')
414			t++;
415		for (p = t; *p > ' '; p++)
416			;
417		*p = 0;
418		if (strcmp(q,t) == 0) {
419			strcpy(typebuf, buf);
420			fclose(f);
421			return (typebuf);
422		}
423	}
424	fclose (f);
425	return (UNKNOWN);
426}
427
428doremotelogin(host)
429	char *host;
430{
431	FILE *hostf;
432	int first = 1;
433
434	getstr(rusername, sizeof (rusername), "remuser");
435	getstr(lusername, sizeof (lusername), "locuser");
436	getstr(term+5, sizeof(term)-5, "Terminal type");
437	if (getuid()) {
438		pwd = &nouser;
439		goto bad;
440	}
441	setpwent();
442	pwd = getpwnam(lusername);
443	endpwent();
444	if (pwd == NULL) {
445		pwd = &nouser;
446		goto bad;
447	}
448	hostf = pwd->pw_uid ? fopen("/etc/hosts.equiv", "r") : 0;
449again:
450	if (hostf) {
451		char ahost[32];
452
453		while (fgets(ahost, sizeof (ahost), hostf)) {
454			char *user;
455
456			if ((user = index(ahost, '\n')) != 0)
457				*user++ = '\0';
458			if ((user = index(ahost, ' ')) != 0)
459				*user++ = '\0';
460			if (!strcmp(host, ahost) &&
461			    !strcmp(rusername, user ? user : lusername)) {
462				fclose(hostf);
463				return (1);
464			}
465		}
466		fclose(hostf);
467	}
468	if (first == 1) {
469		char *rhosts = ".rhosts";
470		struct stat sbuf;
471
472		first = 0;
473		if (chdir(pwd->pw_dir) < 0)
474			goto again;
475		if (lstat(rhosts, &sbuf) < 0)
476			goto again;
477		if ((sbuf.st_mode & S_IFMT) == S_IFLNK) {
478			printf("login: .rhosts is a soft link.\r\n");
479			goto bad;
480		}
481		hostf = fopen(rhosts, "r");
482		fstat(fileno(hostf), &sbuf);
483		if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) {
484			printf("login: Bad .rhosts ownership.\r\n");
485			fclose(hostf);
486			goto bad;
487		}
488		goto again;
489	}
490bad:
491	return (-1);
492}
493
494getstr(buf, cnt, err)
495	char *buf;
496	int cnt;
497	char *err;
498{
499	char c;
500
501	do {
502		if (read(0, &c, 1) != 1)
503			exit(1);
504		if (--cnt < 0) {
505			printf("%s too long\r\n", err);
506			exit(1);
507		}
508		*buf++ = c;
509	} while (c != 0);
510}
511
512char	*speeds[] =
513    { "0", "50", "75", "110", "134", "150", "200", "300",
514      "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
515#define	NSPEEDS	(sizeof (speeds) / sizeof (speeds[0]))
516
517doremoteterm(term, tp)
518	char *term;
519	struct sgttyb *tp;
520{
521	char *cp = index(term, '/');
522	register int i;
523
524	if (cp) {
525		*cp++ = 0;
526		for (i = 0; i < NSPEEDS; i++)
527			if (!strcmp(speeds[i], cp)) {
528				tp->sg_ispeed = tp->sg_ospeed = i;
529				break;
530			}
531	}
532	tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
533}
534
535logerr(fmt, a1, a2, a3)
536	char *fmt, *a1, *a2, *a3;
537{
538#ifdef LOGERR
539	FILE *cons = fopen("/dev/console", "w");
540
541	if (cons != NULL) {
542		fprintf(cons, fmt, a1, a2, a3);
543		fprintf(cons, "\n\r");
544		fclose(cons);
545	}
546#endif
547}
548