xref: /original-bsd/usr.bin/login/login.c (revision d19c88bc)
1 static	char *sccsid = "@(#)login.c	4.14 82/03/15";
2 /*
3  * login [ name ]
4  * login -r
5  * login -r [ rhost ]
6  */
7 
8 #include <sys/types.h>
9 #include <sgtty.h>
10 #include <utmp.h>
11 #include <signal.h>
12 #include <pwd.h>
13 #include <stdio.h>
14 #include <sys/stat.h>
15 #include <lastlog.h>
16 
17 #define	SCPYN(a, b)	strncpy(a, b, sizeof(a))
18 
19 #define NMAX	sizeof(utmp.ut_name)
20 #define LMAX	sizeof(utmp.ut_line)
21 
22 #define	FALSE	0
23 #define	TRUE	-1
24 
25 char	nolog[] =	"/etc/nologin";
26 char	qlog[]  =	".hushlogin";
27 char	securetty[] =	"/etc/securetty";
28 char	maildir[30] =	"/usr/spool/mail/";
29 char	lastlog[] =	"/usr/adm/lastlog";
30 struct	passwd nouser = {"", "nope"};
31 struct	sgttyb ttyb;
32 struct	utmp utmp;
33 char	minusnam[16] = "-";
34 
35 char	homedir[64] = "HOME=";
36 char	shell[64] = "SHELL=";
37 char	term[64] = "TERM=";
38 char	user[20] = "USER=";
39 char	*speeds[] =
40     { "0", "50", "75", "110", "134", "150", "200", "300",
41       "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
42 #define	NSPEEDS	(sizeof (speeds) / sizeof (speeds[0]))
43 
44 char	*envinit[] =
45     {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", term, user, 0};
46 
47 struct	passwd *pwd;
48 struct	passwd *getpwnam();
49 char	*strcat(), *rindex(), *index();
50 int	setpwent();
51 char	*ttyname();
52 char	*crypt();
53 char	*getpass();
54 char	*rindex();
55 char	*stypeof();
56 extern	char **environ;
57 
58 #define	CTRL(c)	('c'&037)
59 #define	CERASE	'#'
60 #define	CEOT	CTRL(d)
61 #define	CKILL	'@'
62 #define	CQUIT	034		/* FS, cntl shift L */
63 #define	CINTR	0177		/* DEL */
64 #define	CSTOP	CTRL(s)
65 #define	CSTART	CTRL(q)
66 #define	CBRK	0377
67 struct	tchars tc = {
68 	CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK
69 };
70 struct	ltchars ltc = {
71 	CTRL(z), CTRL(y), CTRL(r), CTRL(o), CTRL(w), CTRL(v)
72 };
73 
74 int	rflag;
75 char	rusername[NMAX+1], lusername[NMAX+1];
76 char	rpassword[NMAX+1];
77 char	*rhost;
78 
79 main(argc, argv)
80 char **argv;
81 {
82 	register char *namep;
83 	int t, f, c;
84 	int invalid;
85 	int quietlog;
86 	int i;
87 	FILE *nlfd;
88 	char *ttyn;
89 	int ldisc = 0, zero = 0;
90 	FILE *hostf; int first = 1;
91 
92 	alarm(60);
93 	signal(SIGQUIT, SIG_IGN);
94 	signal(SIGINT, SIG_IGN);
95 	nice(-100);
96 	nice(20);
97 	nice(0);
98 	if (argc > 0 && !strcmp(argv[1], "-r")) {
99 		rflag++;
100 		if (argc > 1)
101 			rhost = argv[2];
102 		argc = 1;
103 		if (rhost) {
104 			getstr(rusername, sizeof (rusername), "remuser");
105 			getstr(lusername, sizeof (lusername), "locuser");
106 		} else {
107 			getstr(lusername, sizeof (lusername), "Username");
108 			getstr(rpassword, sizeof (rpassword), "Password");
109 		}
110 		getstr(term+5, sizeof(term)-5, "Terminal type");
111 		if (rhost == 0)
112 			goto normal;
113 		if (getuid()) {
114 			rflag = 0;
115 			goto normal;
116 		}
117 		setpwent();
118 		pwd = getpwnam(lusername);
119 		if (pwd == NULL) {
120 			fprintf(stderr, "Login incorrect.\n");
121 			exit(1);
122 		}
123 		endpwent();
124 		hostf = fopen("/etc/hosts.equiv", "r");
125 	again:
126 		if (hostf) {
127 		  char ahost[32];
128 		  while (fgets(ahost, sizeof (ahost), hostf)) {
129 			char *user;
130 			if (index(ahost, '\n'))
131 				*index(ahost, '\n') = 0;
132 			user = index(ahost, ' ');
133 			if (user)
134 				*user++ = 0;
135 			if (!strcmp(rhost, ahost) &&
136 			    !strcmp(rusername, user ? user : lusername))
137 				goto normal;
138 		  }
139 		  fclose(hostf);
140 		}
141 		if (first == 1) {
142 			first = 0;
143 			if (chdir(pwd->pw_dir) < 0)
144 				goto again;
145 			hostf = fopen(".rhosts", "r");
146 			goto again;
147 		}
148 		rhost = 0;
149 		rflag = -1;
150 	}
151 normal:
152 	ioctl(0, TIOCLSET, &zero);
153 	ioctl(0, TIOCNXCL, 0);
154 	gtty(0, &ttyb);
155 	if (rflag) {
156 		char *cp = index(term, '/');
157 		if (cp) {
158 			int i;
159 			*cp++ = 0;
160 			for (i = 0; i < NSPEEDS; i++)
161 				if (!strcmp(speeds[i], cp)) {
162 					ttyb.sg_ispeed = ttyb.sg_ospeed = i;
163 					break;
164 				}
165 		}
166 		ttyb.sg_flags = ECHO|CRMOD|ANYP|XTABS;
167 	}
168 	if (rflag == -1)
169 		rflag = 0;
170 	ttyb.sg_erase = CERASE;
171 	ttyb.sg_kill = CKILL;
172 	stty(0, &ttyb);
173 	ioctl(0, TIOCSETC, &tc);
174 	ioctl(0, TIOCSLTC, &ltc);
175 	for (t=3; t<20; t++)
176 		close(t);
177 	ttyn = ttyname(0);
178 	if (ttyn==(char *)0)
179 		ttyn = "/dev/tty??";
180 	do {
181 		ldisc = 0;
182 		ioctl(0, TIOCSETD, &ldisc);
183 		invalid = FALSE;
184 		SCPYN(utmp.ut_name, "");
185 		if (argc>1) {
186 			SCPYN(utmp.ut_name, argv[1]);
187 			argc = 0;
188 		}
189 		if (rflag)
190 			strcpy(utmp.ut_name, lusername);
191 		else
192 			while (utmp.ut_name[0] == '\0') {
193 				namep = utmp.ut_name;
194 				{ char hostname[32];
195 				  gethostname(hostname, sizeof (hostname));
196 				  printf("%s login: ", hostname); }
197 				while ((c = getchar()) != '\n') {
198 					if (c == ' ')
199 						c = '_';
200 					if (c == EOF)
201 						exit(0);
202 					if (namep < utmp.ut_name+NMAX)
203 						*namep++ = c;
204 				}
205 			}
206 		if (rhost == 0) {
207 			setpwent();
208 			if ((pwd = getpwnam(utmp.ut_name)) == NULL)
209 				pwd = &nouser;
210 			endpwent();
211 		}
212 		if (!strcmp(pwd->pw_shell, "/bin/csh")) {
213 			ldisc = NTTYDISC;
214 			ioctl(0, TIOCSETD, &ldisc);
215 		}
216 		if (rhost == 0) {
217 			if (*pwd->pw_passwd != '\0') {
218 				char *pp;
219 				nice(-4);
220 				if (rflag == 0)
221 					pp = getpass("Password:");
222 				else
223 					pp = rpassword;
224 				namep = crypt(pp,pwd->pw_passwd);
225 				nice(4);
226 				if (strcmp(namep, pwd->pw_passwd))
227 					invalid = TRUE;
228 			}
229 		}
230 		if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) {
231 			/* logins are disabled except for root */
232 			while ((c = getc(nlfd)) != EOF)
233 				putchar(c);
234 			fflush(stdout);
235 			sleep(5);
236 			exit(0);
237 		}
238 		if (!invalid && pwd->pw_uid == 0 &&
239 		    !rootterm(ttyn+sizeof("/dev/")-1)) {
240 			FILE *console = fopen("/dev/console", "w");
241 			if (console != NULL) {
242 				fprintf(console, "\r\nROOT LOGIN REFUSED %s\r\n"
243 				    , ttyn+sizeof("/dev/")-1
244 				);
245 				fclose(console);
246 			}
247 			invalid = TRUE;
248 		}
249 		if (invalid) {
250 			printf("Login incorrect\n");
251 			if (ttyn[sizeof("/dev/tty")-1] == 'd') {
252 				FILE *console = fopen("/dev/console", "w");
253 				if (console != NULL) {
254 					fprintf(console, "\r\nBADDIALUP %s %s\r\n"
255 					    , ttyn+sizeof("/dev/")-1
256 					    , utmp.ut_name);
257 					fclose(console);
258 				}
259 			}
260 		}
261 		if (*pwd->pw_shell == '\0')
262 			pwd->pw_shell = "/bin/sh";
263 		i = strlen(pwd->pw_shell);
264 		if (chdir(pwd->pw_dir) < 0 && !invalid ) {
265 			if (chdir("/") < 0) {
266 				printf("No directory!\n");
267 				invalid = TRUE;
268 			} else {
269 				printf("No directory!  Logging in with home=/\n");
270 				pwd->pw_dir = "/";
271 			}
272 		}
273 		if (rflag && invalid)
274 			exit(1);
275 	} while (invalid);
276 
277 
278 	time(&utmp.ut_time);
279 	t = ttyslot();
280 	if (t>0 && (f = open("/etc/utmp", 1)) >= 0) {
281 		lseek(f, (long)(t*sizeof(utmp)), 0);
282 		SCPYN(utmp.ut_line, rindex(ttyn, '/')+1);
283 		write(f, (char *)&utmp, sizeof(utmp));
284 		close(f);
285 	}
286 	if (t>0 && (f = open("/usr/adm/wtmp", 1)) >= 0) {
287 		lseek(f, 0L, 2);
288 		write(f, (char *)&utmp, sizeof(utmp));
289 		close(f);
290 	}
291 	quietlog = FALSE;
292 	if (access(qlog, 0) == 0)
293 		quietlog = TRUE;
294 	if ( !quietlog && (f = open(lastlog, 2)) >= 0 ) {
295 		struct lastlog ll;
296 
297 		lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
298 		if (read(f, (char *) &ll, sizeof ll) == sizeof ll &&
299 		    ll.ll_time != 0) {
300 			printf("Last login: %.*s on %.*s\n"
301 			    , 24-5
302 			    , (char *) ctime(&ll.ll_time)
303 			    , sizeof(ll.ll_line)
304 			    , ll.ll_line
305 			);
306 		}
307 		lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
308 		time(&ll.ll_time);
309 		SCPYN(ll.ll_line, rindex(ttyn, '/')+1);
310 		write(f, (char *) &ll, sizeof ll);
311 		close(f);
312 	}
313 	chown(ttyn, pwd->pw_uid, pwd->pw_gid);
314 	setgid(pwd->pw_gid);
315 	inigrp(utmp.ut_name, pwd->pw_gid);
316 	setuid(pwd->pw_uid);
317 	environ = envinit;
318 	strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
319 	strncat(shell, pwd->pw_shell, sizeof(shell)-7);
320 	if (rflag == 0)
321 		strncat(term, stypeof(ttyn), sizeof(term)-6);
322 	strncat(user, pwd->pw_name, sizeof(user)-6);
323 	if ((namep = rindex(pwd->pw_shell, '/')) == NULL)
324 		namep = pwd->pw_shell;
325 	else
326 		namep++;
327 	strcat(minusnam, namep);
328 	alarm(0);
329 	umask(022);
330 	if (ttyn[sizeof("/dev/tty")-1] == 'd') {
331 		FILE *console = fopen("/dev/console", "w");
332 		if (console != NULL) {
333 			fprintf(console, "\r\nDIALUP %s %s\r\n"
334 			    , ttyn+sizeof("/dev/")-1
335 			    , pwd->pw_name
336 			);
337 			fclose(console);
338 		}
339 	}
340 	if ( !quietlog ) {
341 		showmotd();
342 		strcat(maildir, pwd->pw_name);
343 		if (access(maildir,4)==0) {
344 			struct stat statb;
345 			stat(maildir, &statb);
346 			if (statb.st_size)
347 				printf("You have mail.\n");
348 		}
349 	}
350 
351 	signal(SIGQUIT, SIG_DFL);
352 	signal(SIGINT, SIG_DFL);
353 	signal(SIGTSTP, SIG_IGN);
354 	execlp(pwd->pw_shell, minusnam, 0);
355 	perror(pwd->pw_shell);
356 	printf("No shell\n");
357 	exit(0);
358 }
359 
360 int	stopmotd;
361 catch()
362 {
363 	signal(SIGINT, SIG_IGN);
364 	stopmotd++;
365 }
366 
367 /*
368  * return true if OK for root to login on this terminal
369  */
370 rootterm(tty)
371 	char	*tty;
372 {
373 	register FILE *fd;
374 	char	buf[100];
375 
376 	if ((fd = fopen(securetty, "r")) == NULL)
377 		return(1);
378 	while (fgets(buf, sizeof buf, fd) != NULL) {
379 		buf[strlen(buf)-1] = '\0';
380 		if (strcmp(tty, buf) == 0) {
381 			fclose(fd);
382 			return(1);
383 		}
384 	}
385 	fclose(fd);
386 	return(0);
387 }
388 
389 showmotd()
390 {
391 	FILE *mf;
392 	register c;
393 
394 	signal(SIGINT, catch);
395 	if ((mf = fopen("/etc/motd","r")) != NULL) {
396 		while ((c = getc(mf)) != EOF && stopmotd == 0)
397 			putchar(c);
398 		fclose(mf);
399 	}
400 	signal(SIGINT, SIG_IGN);
401 }
402 
403 #undef	UNKNOWN
404 #define UNKNOWN "su"
405 
406 char *
407 stypeof(ttyid)
408 char	*ttyid;
409 {
410 	static char	typebuf[16];
411 	char		buf[50];
412 	register FILE	*f;
413 	register char	*p, *t, *q;
414 
415 	if (ttyid == NULL)
416 		return (UNKNOWN);
417 	f = fopen("/etc/ttytype", "r");
418 	if (f == NULL)
419 		return (UNKNOWN);
420 	/* split off end of name */
421 	for (p = q = ttyid; *p != 0; p++)
422 		if (*p == '/')
423 			q = p + 1;
424 
425 	/* scan the file */
426 	while (fgets(buf, sizeof buf, f) != NULL)
427 	{
428 		for (t=buf; *t!=' ' && *t != '\t'; t++)
429 			;
430 		*t++ = 0;
431 		while (*t == ' ' || *t == '\t')
432 			t++;
433 		for (p=t; *p>' '; p++)
434 			;
435 		*p = 0;
436 		if (strcmp(q,t)==0) {
437 			strcpy(typebuf, buf);
438 			fclose(f);
439 			return (typebuf);
440 		}
441 	}
442 	fclose (f);
443 	return (UNKNOWN);
444 }
445 
446 getstr(buf, cnt, err)
447 	char *buf;
448 	int cnt;
449 	char *err;
450 {
451 	char c;
452 
453 	do {
454 		if (read(0, &c, 1) != 1)
455 			exit(1);
456 		if (--cnt < 0) {
457 			printf("%s too long\r\n", err);
458 			exit(1);
459 		}
460 		*buf++ = c;
461 	} while (c != 0);
462 }
463