ask for login name second time around on rlogin
[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
9c90878c 14static char sccsid[] = "@(#)login.c 5.8 (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;
96aec705 173 invalid = FALSE;
f570e1ff
BJ
174 do {
175 ldisc = 0;
c95ed2b2 176 ioctl(0, TIOCSETD, &ldisc);
f570e1ff 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 */
96aec705 189 if (rflag && !invalid)
3479a16a 190 SCPYN(utmp.ut_name, lusername);
a8fb897a 191 else
3b8dd95e 192 getloginname(&utmp);
96aec705 193 invalid = FALSE;
f570e1ff
BJ
194 if (!strcmp(pwd->pw_shell, "/bin/csh")) {
195 ldisc = NTTYDISC;
196 ioctl(0, TIOCSETD, &ldisc);
197 }
3b8dd95e
SL
198 /*
199 * If no remote login authentication and
200 * a password exists for this user, prompt
201 * for one and verify it.
202 */
95a2c263 203 if (usererr == -1 && *pwd->pw_passwd != '\0') {
3b8dd95e
SL
204 char *pp;
205
206 setpriority(PRIO_PROCESS, 0, -4);
207 pp = getpass("Password:");
208 namep = crypt(pp, pwd->pw_passwd);
209 setpriority(PRIO_PROCESS, 0, 0);
210 if (strcmp(namep, pwd->pw_passwd))
211 invalid = TRUE;
f570e1ff 212 }
3b8dd95e
SL
213 /*
214 * If user not super-user, check for logins disabled.
215 */
f570e1ff 216 if (pwd->pw_uid != 0 && (nlfd = fopen(nolog, "r")) > 0) {
f570e1ff
BJ
217 while ((c = getc(nlfd)) != EOF)
218 putchar(c);
219 fflush(stdout);
220 sleep(5);
221 exit(0);
222 }
3b8dd95e
SL
223 /*
224 * If valid so far and root is logging in,
225 * see if root logins on this terminal are permitted.
226 */
9479aa87 227 if (!invalid && pwd->pw_uid == 0 && !rootterm(tty)) {
076ae92c 228 syslog(LOG_CRIT, "ROOT LOGIN REFUSED %s", tty);
f570e1ff
BJ
229 invalid = TRUE;
230 }
231 if (invalid) {
88a01c09 232 printf("Login incorrect\n");
9479aa87 233 if (++t >= 5) {
076ae92c 234 syslog(LOG_CRIT,
9479aa87
BJ
235 "REPEATED LOGIN FAILURES %s, %s",
236 tty, utmp.ut_name);
237 ioctl(0, TIOCHPCL, (struct sgttyb *) 0);
d3737d51 238 close(0), close(1), close(2);
9479aa87
BJ
239 sleep(10);
240 exit(1);
241 }
88a01c09 242 }
f570e1ff
BJ
243 if (*pwd->pw_shell == '\0')
244 pwd->pw_shell = "/bin/sh";
f570e1ff
BJ
245 if (chdir(pwd->pw_dir) < 0 && !invalid ) {
246 if (chdir("/") < 0) {
247 printf("No directory!\n");
248 invalid = TRUE;
249 } else {
3b8dd95e
SL
250 printf("No directory! %s\n",
251 "Logging in with home=/");
f570e1ff
BJ
252 pwd->pw_dir = "/";
253 }
88a01c09 254 }
3b8dd95e
SL
255 /*
256 * Remote login invalid must have been because
257 * of a restriction of some sort, no extra chances.
258 */
95a2c263 259 if (!usererr && invalid)
86eb6c9e 260 exit(1);
f570e1ff 261 } while (invalid);
3b8dd95e
SL
262/* committed to login turn off timeout */
263 alarm(0);
88a01c09 264
790c9c8b 265 if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) {
22d4760e
SL
266 if (errno == EUSERS)
267 printf("%s.\n%s.\n",
268 "Too many users logged on already",
269 "Try again later");
270 else if (errno == EPROCLIM)
271 printf("You have too many processes running.\n");
272 else
6821e9c5 273 perror("quota (Q_SETUID)");
22d4760e
SL
274 sleep(5);
275 exit(0);
276 }
88a01c09
BJ
277 time(&utmp.ut_time);
278 t = ttyslot();
9479aa87 279 if (t > 0 && (f = open("/etc/utmp", O_WRONLY)) >= 0) {
88a01c09 280 lseek(f, (long)(t*sizeof(utmp)), 0);
9479aa87 281 SCPYN(utmp.ut_line, tty);
88a01c09
BJ
282 write(f, (char *)&utmp, sizeof(utmp));
283 close(f);
284 }
9479aa87 285 if ((f = open("/usr/adm/wtmp", O_WRONLY|O_APPEND)) >= 0) {
88a01c09
BJ
286 write(f, (char *)&utmp, sizeof(utmp));
287 close(f);
288 }
9479aa87
BJ
289 quietlog = access(qlog, F_OK) == 0;
290 if ((f = open(lastlog, O_RDWR)) >= 0) {
f570e1ff
BJ
291 struct lastlog ll;
292
293 lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
294 if (read(f, (char *) &ll, sizeof ll) == sizeof ll &&
3b8dd95e
SL
295 ll.ll_time != 0 && !quietlog) {
296 printf("Last login: %.*s ",
297 24-5, (char *)ctime(&ll.ll_time));
298 if (*ll.ll_host != '\0')
299 printf("from %.*s\n",
300 sizeof (ll.ll_host), ll.ll_host);
301 else
302 printf("on %.*s\n",
303 sizeof (ll.ll_line), ll.ll_line);
f570e1ff
BJ
304 }
305 lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
306 time(&ll.ll_time);
9479aa87 307 SCPYN(ll.ll_line, tty);
3b8dd95e 308 SCPYN(ll.ll_host, utmp.ut_host);
f570e1ff
BJ
309 write(f, (char *) &ll, sizeof ll);
310 close(f);
311 }
88a01c09 312 chown(ttyn, pwd->pw_uid, pwd->pw_gid);
c32fb087 313 if (!hflag && !rflag) /* XXX */
d3737d51 314 ioctl(0, TIOCSWINSZ, &win);
3479a16a 315 chmod(ttyn, 0622);
88a01c09 316 setgid(pwd->pw_gid);
e5321f7b
KM
317 strncpy(name, utmp.ut_name, NMAX);
318 name[NMAX] = '\0';
b1198826 319 initgroups(name, pwd->pw_gid);
22d4760e 320 quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0);
88a01c09 321 setuid(pwd->pw_uid);
d3737d51
SL
322 /* destroy environment unless user has asked to preserve it */
323 if (!pflag)
324 environ = envinit;
325
326 /* set up environment, this time without destruction */
327 /* copy the environment before setenving */
328 i = 0;
329 while (environ[i] != NULL)
330 i++;
331 envnew = (char **) malloc(sizeof (char *) * (i + 1));
332 for (; i >= 0; i--)
333 envnew[i] = environ[i];
334 environ = envnew;
335
bed177dc
MK
336 setenv("HOME=", pwd->pw_dir, 1);
337 setenv("SHELL=", pwd->pw_shell, 1);
d3737d51
SL
338 if (term[0] == '\0')
339 strncpy(term, stypeof(tty), sizeof(term));
bed177dc
MK
340 setenv("TERM=", term, 0);
341 setenv("USER=", pwd->pw_name, 1);
342 setenv("PATH=", ":/usr/ucb:/bin:/usr/bin", 0);
d3737d51 343
88a01c09
BJ
344 if ((namep = rindex(pwd->pw_shell, '/')) == NULL)
345 namep = pwd->pw_shell;
346 else
347 namep++;
348 strcat(minusnam, namep);
9479aa87 349 if (tty[sizeof("tty")-1] == 'd')
d3737d51
SL
350 syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name);
351 if (pwd->pw_uid == 0)
076ae92c 352 syslog(LOG_NOTICE, "ROOT LOGIN %s", tty);
4f8d3876 353 if (!quietlog) {
6821e9c5 354 struct stat st;
d3737d51 355
f570e1ff
BJ
356 showmotd();
357 strcat(maildir, pwd->pw_name);
6821e9c5
S
358 if (stat(maildir, &st) == 0 && st.st_size != 0)
359 printf("You have %smail.\n",
d3737d51 360 (st.st_mtime > st.st_atime) ? "new " : "");
f570e1ff 361 }
3b8dd95e 362 signal(SIGALRM, SIG_DFL);
88a01c09
BJ
363 signal(SIGQUIT, SIG_DFL);
364 signal(SIGINT, SIG_DFL);
5f87416f 365 signal(SIGTSTP, SIG_IGN);
88a01c09 366 execlp(pwd->pw_shell, minusnam, 0);
f570e1ff 367 perror(pwd->pw_shell);
88a01c09
BJ
368 printf("No shell\n");
369 exit(0);
370}
371
3b8dd95e
SL
372getloginname(up)
373 register struct utmp *up;
374{
375 register char *namep;
5a786176 376 char c;
3b8dd95e 377
3b8dd95e 378 while (up->ut_name[0] == '\0') {
d910ab7f 379 namep = up->ut_name;
5a786176 380 printf("login: ");
3b8dd95e
SL
381 while ((c = getchar()) != '\n') {
382 if (c == ' ')
383 c = '_';
384 if (c == EOF)
385 exit(0);
386 if (namep < up->ut_name+NMAX)
387 *namep++ = c;
388 }
389 }
d910ab7f
EW
390 strncpy(lusername, up->ut_name, NMAX);
391 lusername[NMAX] = 0;
d910ab7f 392 if ((pwd = getpwnam(lusername)) == NULL)
3b8dd95e 393 pwd = &nouser;
3b8dd95e
SL
394}
395
396timedout()
397{
398
399 printf("Login timed out after %d seconds\n", timeout);
400 exit(0);
401}
402
88a01c09
BJ
403int stopmotd;
404catch()
405{
1886582e 406
88a01c09
BJ
407 signal(SIGINT, SIG_IGN);
408 stopmotd++;
409}
410
f570e1ff 411rootterm(tty)
1886582e 412 char *tty;
f570e1ff 413{
9479aa87
BJ
414 register struct ttyent *t;
415
416 if ((t = getttynam(tty)) != NULL) {
417 if (t->ty_status & TTY_SECURE)
418 return (1);
f570e1ff 419 }
9479aa87 420 return (0);
f570e1ff
BJ
421}
422
88a01c09
BJ
423showmotd()
424{
425 FILE *mf;
426 register c;
427
428 signal(SIGINT, catch);
9479aa87 429 if ((mf = fopen("/etc/motd", "r")) != NULL) {
f570e1ff 430 while ((c = getc(mf)) != EOF && stopmotd == 0)
88a01c09
BJ
431 putchar(c);
432 fclose(mf);
433 }
434 signal(SIGINT, SIG_IGN);
435}
436
f570e1ff 437#undef UNKNOWN
88a01c09
BJ
438#define UNKNOWN "su"
439
440char *
441stypeof(ttyid)
3b8dd95e 442 char *ttyid;
88a01c09 443{
9479aa87 444 register struct ttyent *t;
88a01c09 445
9479aa87 446 if (ttyid == NULL || (t = getttynam(ttyid)) == NULL)
88a01c09 447 return (UNKNOWN);
9479aa87 448 return (t->ty_type);
88a01c09 449}
86eb6c9e 450
3b8dd95e
SL
451doremotelogin(host)
452 char *host;
453{
3b8dd95e
SL
454 getstr(rusername, sizeof (rusername), "remuser");
455 getstr(lusername, sizeof (lusername), "locuser");
d3737d51 456 getstr(term, sizeof(term), "Terminal type");
4cf9fc9e
SL
457 if (getuid()) {
458 pwd = &nouser;
95a2c263 459 return(-1);
4cf9fc9e 460 }
3b8dd95e 461 pwd = getpwnam(lusername);
4cf9fc9e
SL
462 if (pwd == NULL) {
463 pwd = &nouser;
95a2c263 464 return(-1);
3b8dd95e 465 }
95a2c263 466 return(ruserok(host, (pwd->pw_uid == 0), rusername, lusername));
3b8dd95e
SL
467}
468
86eb6c9e
BJ
469getstr(buf, cnt, err)
470 char *buf;
471 int cnt;
472 char *err;
473{
474 char c;
475
476 do {
477 if (read(0, &c, 1) != 1)
478 exit(1);
479 if (--cnt < 0) {
480 printf("%s too long\r\n", err);
481 exit(1);
482 }
483 *buf++ = c;
484 } while (c != 0);
485}
4f8d3876 486
3b8dd95e
SL
487char *speeds[] =
488 { "0", "50", "75", "110", "134", "150", "200", "300",
489 "600", "1200", "1800", "2400", "4800", "9600", "19200", "38400" };
490#define NSPEEDS (sizeof (speeds) / sizeof (speeds[0]))
491
492doremoteterm(term, tp)
493 char *term;
494 struct sgttyb *tp;
495{
d3737d51
SL
496 register char *cp = index(term, '/'), **cpp;
497 char *speed;
3b8dd95e
SL
498
499 if (cp) {
d3737d51
SL
500 *cp++ = '\0';
501 speed = cp;
502 cp = index(speed, '/');
503 if (cp)
504 *cp++ = '\0';
505 for (cpp = speeds; cpp < &speeds[NSPEEDS]; cpp++)
506 if (strcmp(*cpp, speed) == 0) {
507 tp->sg_ispeed = tp->sg_ospeed = cpp-speeds;
3b8dd95e
SL
508 break;
509 }
c32fb087 510 compatsiz(cp);
3b8dd95e
SL
511 }
512 tp->sg_flags = ECHO|CRMOD|ANYP|XTABS;
513}
d3737d51 514
c32fb087
KM
515/* BEGIN TRASH
516 *
517 * This is here only long enough to get us by to the revised rlogin
518 */
519compatsiz(cp)
520 char *cp;
521{
522 struct winsize ws;
523
524 ws.ws_row = ws.ws_col = -1;
525 ws.ws_xpixel = ws.ws_ypixel = -1;
526 if (cp) {
527 ws.ws_row = atoi(cp);
528 cp = index(cp, ',');
529 if (cp == 0)
530 goto done;
531 ws.ws_col = atoi(++cp);
532 cp = index(cp, ',');
533 if (cp == 0)
534 goto done;
535 ws.ws_xpixel = atoi(++cp);
536 cp = index(cp, ',');
537 if (cp == 0)
538 goto done;
539 ws.ws_ypixel = atoi(++cp);
540 }
541done:
542 if (ws.ws_row != -1 && ws.ws_col != -1 &&
543 ws.ws_xpixel != -1 && ws.ws_ypixel != -1)
544 ioctl(0, TIOCSWINSZ, &ws);
545}
546/* END TRASH */
547
d3737d51
SL
548/*
549 * Set the value of var to be arg in the Unix 4.2 BSD environment env.
550 * Var should end with '='.
551 * (bindings are of the form "var=value")
552 * This procedure assumes the memory for the first level of environ
553 * was allocated using malloc.
554 */
bed177dc 555setenv(var, value, clobber)
d3737d51
SL
556 char *var, *value;
557{
558 extern char **environ;
559 int index = 0;
560 int varlen = strlen(var);
561 int vallen = strlen(value);
562
563 for (index = 0; environ[index] != NULL; index++) {
564 if (strncmp(environ[index], var, varlen) == 0) {
565 /* found it */
bed177dc
MK
566 if (!clobber)
567 return;
d3737d51
SL
568 environ[index] = malloc(varlen + vallen + 1);
569 strcpy(environ[index], var);
570 strcat(environ[index], value);
571 return;
572 }
573 }
574 environ = (char **) realloc(environ, sizeof (char *) * (index + 2));
575 if (environ == NULL) {
576 fprintf(stderr, "login: malloc out of memory\n");
577 exit(1);
578 }
579 environ[index] = malloc(varlen + vallen + 1);
580 strcpy(environ[index], var);
581 strcat(environ[index], value);
582 environ[++index] = NULL;
583}