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