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