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