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