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