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