xref: /original-bsd/usr.bin/login/login.c.1 (revision c94524dd)
1#ifndef lint
2static	char *sccsid = "@(#)login.c.1	4.26 (Berkeley) 83/05/23";
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/types.h>
12#define	QUOTA
13#include <sys/quota.h>
14#include <sys/stat.h>
15#include <sys/time.h>
16#include <sys/resource.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
26#define	SCPYN(a, b)	strncpy(a, b, sizeof(a))
27
28#define NMAX	sizeof(utmp.ut_name)
29
30#define	FALSE	0
31#define	TRUE	-1
32
33char	nolog[] =	"/etc/nologin";
34char	qlog[]  =	".hushlogin";
35char	securetty[] =	"/etc/securetty";
36char	maildir[30] =	"/usr/spool/mail/";
37char	lastlog[] =	"/usr/adm/lastlog";
38struct	passwd nouser = {"", "nope", -1, -1, -1, "", "", "", "" };
39struct	sgttyb ttyb;
40struct	utmp utmp;
41char	minusnam[16] = "-";
42/*
43 * This bounds the time given to login.  We initialize it here
44 * so it can be patched on machines where it's too small.
45 */
46int	timeout = 60;
47
48char	homedir[64] = "HOME=";
49char	shell[64] = "SHELL=";
50char	term[64] = "TERM=";
51char	user[20] = "USER=";
52
53char	*envinit[] =
54    { homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", term, user, 0 };
55
56struct	passwd *pwd;
57struct	passwd *getpwnam();
58char	*strcat(), *rindex(), *index();
59int	setpwent();
60int	timedout();
61char	*ttyname();
62char	*crypt();
63char	*getpass();
64char	*stypeof();
65extern	char **environ;
66extern	int errno;
67
68struct	ttychars tc = {
69	CERASE,	CKILL,	CINTR,	CQUIT,	CSTART,
70	CSTOP,	CEOF,	CBRK,	CSUSP,	CDSUSP,
71	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);	/* XXX */
113	ioctl(0, TIOCNXCL, 0);
114	ioctl(0, FIONBIO, &zero);
115	ioctl(0, FIOASYNC, &zero);
116	ioctl(0, TIOCGETP, &ttyb);	/* XXX */
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, TIOCSETP, &ttyb);	/* XXX */
125	ioctl(0, TIOCCSET, &tc);
126	for (t = getdtablesize(); t > 3; t--)
127		close(t);
128	ttyn = ttyname(0);
129	if (ttyn==(char *)0)
130		ttyn = "/dev/tty??";
131	do {
132		ldisc = 0;
133		ioctl(0, TIOCSETD, &ldisc);
134		invalid = FALSE;
135		SCPYN(utmp.ut_name, "");
136		/*
137		 * Name specified, take it.
138		 */
139		if (argc > 1) {
140			SCPYN(utmp.ut_name, argv[1]);
141			argc = 0;
142		}
143		/*
144		 * If remote login take given name,
145		 * otherwise prompt user for something.
146		 */
147		if (rflag) {
148			SCPYN(utmp.ut_name, lusername);
149			/* autologin failed, prompt for passwd */
150			if (rflag == -1)
151				rflag = 0;
152		} else {
153			getloginname(&utmp);
154		}
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 hostname[32], c;
318
319	gethostname(hostname, sizeof (hostname));
320	while (up->ut_name[0] == '\0') {
321		namep = utmp.ut_name;
322		printf("%s login: ", hostname);
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		goto bad;
439	setpwent();
440	pwd = getpwnam(lusername);
441	endpwent();
442	if (pwd == NULL)
443		goto bad;
444	hostf = pwd->pw_uid ? fopen("/etc/hosts.equiv", "r") : 0;
445again:
446	if (hostf) {
447		char ahost[32];
448
449		while (fgets(ahost, sizeof (ahost), hostf)) {
450			char *user;
451
452			if ((user = index(ahost, '\n')) != 0)
453				*user++ = '\0';
454			if ((user = index(ahost, ' ')) != 0)
455				*user++ = '\0';
456			if (!strcmp(host, ahost) &&
457			    !strcmp(rusername, user ? user : lusername)) {
458				fclose(hostf);
459				return (1);
460			}
461		}
462		fclose(hostf);
463	}
464	if (first == 1) {
465		char *rhosts = ".rhosts";
466		struct stat sbuf;
467
468		first = 0;
469		if (chdir(pwd->pw_dir) < 0)
470			goto again;
471		if (lstat(rhosts, &sbuf) < 0)
472			goto again;
473		if ((sbuf.st_mode & S_IFMT) == S_IFLNK) {
474			printf("login: .rhosts is a soft link.\r\n");
475			goto bad;
476		}
477		hostf = fopen(rhosts, "r");
478		fstat(fileno(hostf), &sbuf);
479		if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid) {
480			printf("login: Bad .rhosts ownership.\r\n");
481			fclose(hostf);
482			goto bad;
483		}
484		goto again;
485	}
486bad:
487	return (-1);
488}
489
490getstr(buf, cnt, err)
491	char *buf;
492	int cnt;
493	char *err;
494{
495	char c;
496
497	do {
498		if (read(0, &c, 1) != 1)
499			exit(1);
500		if (--cnt < 0) {
501			printf("%s too long\r\n", err);
502			exit(1);
503		}
504		*buf++ = c;
505	} while (c != 0);
506}
507
508char	*speeds[] =
509    { "0", "50", "75", "110", "134", "150", "200", "300",
510      "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
511#define	NSPEEDS	(sizeof (speeds) / sizeof (speeds[0]))
512
513doremoteterm(term, tp)
514	char *term;
515	struct sgttyb *tp;
516{
517	char *cp = index(term, '/');
518	register int i;
519
520	if (cp) {
521		*cp++ = 0;
522		for (i = 0; i < NSPEEDS; i++)
523			if (!strcmp(speeds[i], cp)) {
524				tp->sg_ispeed = tp->sg_ospeed = i;
525				break;
526			}
527	}
528	tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
529}
530
531logerr(fmt, a1, a2, a3)
532	char *fmt, *a1, *a2, *a3;
533{
534#ifdef LOGERR
535	FILE *cons = fopen("/dev/console", "w");
536
537	if (cons != NULL) {
538		fprintf(cons, fmt, a1, a2, a3);
539		fputc('\r', cons);
540		fclose(cons);
541	}
542#endif
543}
544