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