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