|
|
1.1 ! root 1: static char _version[]="login version 3.2.1"; ! 2: /* ! 3: * Rec'd from Lauren Weinstein, 7-16-84. ! 4: * Hacked by rec to enable remote kludge on pdp11 10-84. ! 5: * Hacked extensively by rec 84-11-02. ! 6: * Added terminal locking and version number October 1991 by piggy. ! 7: * ! 8: * login connects a user terminal: ! 9: * 1) unless executed by /etc/getty, the terminal is set back to ! 10: * default modes and characters while preserving the speeds ! 11: * and the parity. ! 12: * 2) The user name supplied or prompted for is located in the ! 13: * password file, and the password, if any is specified, ! 14: * is prompted for, encrypted, and compared to the specified ! 15: * password. ! 16: * 3) If the user name did not exist, or the password was wrong, the ! 17: * login is reported as incorrect and the procedure repeats. ! 18: * 4) If the tty is identified as 'remote' then: ! 19: * a) at most MAXFAIL attempts are permitted before the tty ! 20: * is hung up. ! 21: * b) at most MAXTIME seconds are permitted for a successful ! 22: * login before the tty is hung up. ! 23: * c) if the user has no password, and the REMACC user in ! 24: * /etc/passwd does have a password, then the REMACC password ! 25: * must be supplied. If this program is compiled with ! 26: * "BBS" defined, then a valid serial number must be supplied ! 27: * at the remote access password prompt. ! 28: * 5) An unsuccessful login appends a utmp record to the file ! 29: * /usr/adm/failed if it exists. ! 30: * It also removes the tty lock from /usr/spool/uucp. ! 31: * 6) A successful login: ! 32: * a-1) Locks the tty in /usr/spool/uucp. ! 33: * a) chdir's to the home directory specified by /etc/passwd ! 34: * b) writes utmp records to /usr/adm/wtmp and /etc/utmp if. ! 35: * possible. ! 36: * c) chowns the tty to be owned by the user. ! 37: * d) chmods the tty to TTYMODE mode. ! 38: * e) sets the user and group id's as specified by /etc/passwd. ! 39: * f) sets USER to the user name matched in /etc/passwd. ! 40: * g) sets HOME to the home directory specified in /etc/passwd. ! 41: * h) sets SHELL to the shell specified in /etc/passwd. ! 42: * i) exec's /bin/sh as "-sh" if and only if the shell ! 43: * specified in /etc/passwd is either blank or /bin/sh, ! 44: * otherwise as "+sh"; the "+/-" is for the benefit of /bin/sh. ! 45: * ! 46: * All other connect procedures and initializations should be performed by ! 47: * including them in /etc/profile or $HOME/.profile which the shell will ! 48: * perform before exec'ing the command interpreter specified by $SHELL. ! 49: * The shell will exit if any signals are received during /etc/profile. ! 50: */ ! 51: #include <stdio.h> ! 52: #include <pwd.h> ! 53: #include <signal.h> ! 54: #include <utmp.h> ! 55: #include <sys/dir.h> ! 56: #include <sys/stat.h> ! 57: #include <sgtty.h> ! 58: #if NEWTTYS ! 59: #include <sys/tty.h> ! 60: #endif ! 61: #include <sys/deftty.h> ! 62: #ifdef BBS ! 63: #include <sys/types.h> ! 64: #endif ! 65: ! 66: extern long lseek(); ! 67: #ifdef BBS ! 68: extern int chk_srlno(); ! 69: extern time_t time(); ! 70: #endif ! 71: ! 72: #define FALSE 0 ! 73: #define TRUE 1 ! 74: ! 75: #define TTYMODE (S_IREAD|S_IWRITE|S_IEXEC) ! 76: #define MAXFAIL 3 /* Maximum permitted failed login attempts */ ! 77: #define MAXTIME 60 /* Maximum seconds permitted for login */ ! 78: #define PASSLEN 13 /* Length of encrypted passwords */ ! 79: #define ACCNAME "remacc" /* Remote access password dummy username */ ! 80: #define NBUF 128 /* Assorted buffers */ ! 81: #define LOGMSG "/etc/logmsg" /* Login message file */ ! 82: #define DEFMSG "Login: " /* Default login message */ ! 83: ! 84: /* ! 85: * Default sgtty and tchars settings. ! 86: */ ! 87: ! 88: struct sgttyb defsgt = { /* Initial sgtty */ ! 89: DEF_SG_ISPEED, ! 90: DEF_SG_OSPEED, ! 91: DEF_SG_ERASE, ! 92: DEF_SG_KILL, ! 93: DEF_SG_FLAGS ! 94: }; ! 95: ! 96: struct tchars deftch = { /* Initial tchars */ ! 97: DEF_T_INTRC, ! 98: DEF_T_QUITC, ! 99: DEF_T_STARTC, ! 100: DEF_T_STOPC, ! 101: DEF_T_EOFC, ! 102: DEF_T_BRKC ! 103: }; ! 104: ! 105: /* ! 106: * Default environment list for shell. ! 107: */ ! 108: #define NDENV 64 ! 109: char euser[NDENV] = "USER=root"; ! 110: char ehome[NDENV] = "HOME=/etc"; ! 111: char eshell[NDENV] = "SHELL="; ! 112: char *defenv0[] = { /* Default environment for super user */ ! 113: euser, ehome, "PATH=/bin:/usr/bin:/etc:", "PS1=# ", eshell, NULL ! 114: }; ! 115: char *defenvn[] = { /* Default environment for other user */ ! 116: euser, ehome, "PATH=:/bin:/usr/bin", "PS1=$ ", eshell, NULL ! 117: }; ! 118: ! 119: /* ! 120: * Assorted data. ! 121: */ ! 122: char faillog[] = "/usr/adm/failed"; /* failed login attempt log */ ! 123: char wholog[] = "/etc/utmp"; /* current login log */ ! 124: char motd[] = "/etc/motd"; /* message of the day */ ! 125: char goodlog[] = "/usr/adm/wtmp"; /* successful login log */ ! 126: #ifdef BBS ! 127: char goodsrl[] = "/usr/adm/wsrl"; /* successful login log */ ! 128: #endif ! 129: char *prompt[] = { ! 130: "Password: ", /* password msg 1 */ ! 131: #ifdef BBS ! 132: "BBS access password: " /* password msg 2 */ ! 133: #else ! 134: "Remote access password: " /* password msg 2 */ ! 135: #endif ! 136: }; ! 137: char buff[NBUF]; /* I/O buffer */ ! 138: char *argv0 = "login"; /* Command name */ ! 139: ! 140: #ifdef BBS ! 141: static int good_serialno; ! 142: FILE * fp_srl; ! 143: time_t tnum; ! 144: #endif ! 145: ! 146: main(argc, argv) int argc; char *argv[]; ! 147: { ! 148: register char *cp; /* Password pointer */ ! 149: register struct passwd *pwp; ! 150: int i, fd; ! 151: int oldtime; /* Alarm temporary */ ! 152: int failed = TRUE; /* Assume cracker */ ! 153: int remote = FALSE; /* Assume not remote tty line */ ! 154: int passcount = 0; /* Password pass */ ! 155: int logcount = 0; /* Login attempt count */ ! 156: char *s_tty; /* tty name */ ! 157: char *s_user; /* user name, saved in euser[] */ ! 158: char *s_dir; /* user directory, saved in ehome[] */ ! 159: char *s_shell; /* user shell, saved in eshell[] */ ! 160: int s_uid; /* user id */ ! 161: int s_gid; /* group id */ ! 162: extern int timeout(); /* Login attempt alarm function */ ! 163: extern char *crypt(); ! 164: extern char *getpass(); ! 165: extern char *ttyname(); ! 166: extern char *strcpy(); ! 167: extern char *index(); ! 168: ! 169: if (argc > 0) ! 170: argv0 = argv[0]; ! 171: ! 172: /* Usage check */ ! 173: if (argc < 1 || argc > 2) { ! 174: fprintf(stderr, "Usage: %s [username]\n", argv0); ! 175: slowexit(1); ! 176: } ! 177: ! 178: /* Login no args, let getty start us from scratch */ ! 179: if (argc == 1 && argv0[0] != '-') ! 180: exit(0); ! 181: ! 182: /* Default signals */ ! 183: for (i=1; i<=NSIG; i++) ! 184: signal(i, SIG_DFL); ! 185: ! 186: /* Default file descriptors */ ! 187: for (i=3; close(i)>=0; i++) ! 188: ; ! 189: ! 190: /* Locate buffers */ ! 191: s_dir = index(ehome, '=') + 1; ! 192: s_user = index(euser, '=') + 1; ! 193: s_shell = index(eshell, '=') + 1; ! 194: ! 195: /* Find out tty, and reset if necessary */ ! 196: if ((s_tty = ttyname(2)) == NULL) { ! 197: fprintf(stderr, "%s: cannot find terminal.\n", argv0); ! 198: slowexit(1); ! 199: } ! 200: ! 201: /* ! 202: * If login has been exec()'d by a login shell, there will ! 203: * already be a lock file. Fortunately, this lock file belongs ! 204: * to us, so we can remove it. If there is a lock file that ! 205: * doesn't belong to us, unlocktty() won't remove it, and the ! 206: * subsequent locktty() will fail, as it should. We are ! 207: * explicitly ignoring the return value of unlocktty(). ! 208: */ ! 209: (void) unlocktty(strrchr(s_tty, '/') + 1); ! 210: ! 211: /* Let's lock this tty, so nobody else grabs it until we log out. */ ! 212: if (-1 == locktty(strrchr(s_tty, '/') + 1) ){ ! 213: fprintf(stderr, "%s: cannot lock terminal.\n", argv0); ! 214: slowexit(1); ! 215: } ! 216: ! 217: if (argv0[0] != '-' /* Not called from /etc/getty */ ! 218: && settty(2) != 0) { /* Reset terminal failed */ ! 219: perror(s_tty); ! 220: slowexit(1); ! 221: } ! 222: ! 223: if (argv0[0] == '-' && argv0[1] == 'r') /* Isolate remote determination */ ! 224: { remote = TRUE; ! 225: signal(SIGALRM, &timeout); /* catch login timeout */ ! 226: alarm(MAXTIME); /* set timeout alarm */ ! 227: } ! 228: ! 229: again: failed = TRUE; /* assume attempt will fail */ ! 230: setpwent(); /* rewind password file */ ! 231: if (remote && (++logcount > MAXFAIL)) /* count remote attempts */ ! 232: slowexit(1); /* exit (and try force hangup) if too many attempts */ ! 233: ! 234: if (passcount == 0) /* first pass?, user name and password */ ! 235: { if (argc > 1) ! 236: { strcpy(buff, argv[1]); /* Use argument once */ ! 237: argc = 0; ! 238: } ! 239: else ! 240: { ! 241: do { ! 242: printprompt(); ! 243: if (fgets(buff, NBUF-1, stdin) == NULL) ! 244: { putchar('\n'); ! 245: slowexit(1); ! 246: } ! 247: } while (buff[0] == '\n' && buff[1] == 0); ! 248: buff[strlen(buff)-1] = 0; /* null terminate over newline */ ! 249: } ! 250: pwp = getpwnam(buff); /* get name entry */ ! 251: if (pwp != NULL) /* if entry found */ ! 252: { ! 253: if (strcmp(pwp->pw_name, ACCNAME) == 0) { ! 254: printf("Login incorrect\n"); /* disallow remacc logins */ ! 255: goto again; ! 256: } ! 257: strcpy(s_user, pwp->pw_name); /* save name */ ! 258: s_uid = pwp->pw_uid; /* save uid */ ! 259: s_gid = pwp->pw_gid; /* save gid */ ! 260: strcpy(s_dir, pwp->pw_dir); /* save directory */ ! 261: strcpy(s_shell, (*pwp->pw_shell == '\0') ? "/bin/sh" ! 262: : pwp->pw_shell); ! 263: } ! 264: } ! 265: else /* second pass, remote access password */ ! 266: { ! 267: #ifdef BBS ! 268: pwp = NULL; ! 269: #else ! 270: pwp = getpwnam(ACCNAME); /* check for remote access entry */ ! 271: if (pwp == NULL || pwp->pw_passwd[0] == 0) /* no access pass? */ ! 272: goto ok; /* all done */ ! 273: #endif ! 274: } ! 275: ! 276: if (pwp == NULL /* Not a user name */ ! 277: || pwp->pw_passwd[0] != 0) /* Password present */ ! 278: { if ((cp = getpass(prompt[passcount])) != NULL && cp[0] != '\0') { ! 279: #ifdef BBS ! 280: if (passcount == 0) { ! 281: #endif ! 282: cp = crypt(cp, pwp==NULL ? "xx" : pwp->pw_passwd); ! 283: if (pwp != NULL ! 284: && strcmp(cp, pwp->pw_passwd) == 0 ! 285: && strcmp(s_user, ACCNAME) != 0 ! 286: && strlen(pwp->pw_passwd) == PASSLEN) ! 287: failed = FALSE; /* success */ ! 288: #ifdef BBS ! 289: } else { /* for BBS, second password is a serial # */ ! 290: if (chk_srlno(cp)) { ! 291: failed = FALSE; /* success */ ! 292: good_serialno = TRUE; ! 293: } ! 294: } ! 295: #endif ! 296: } ! 297: ! 298: if (failed) /* failed attempt? */ ! 299: { oldtime = alarm(0); /* turn off alarm */ ! 300: passcount = 0; /* reset pass count */ ! 301: setutmp(s_tty, buff, faillog, FALSE); /* failed attempt */ ! 302: alarm(oldtime); /* continue timeout */ ! 303: printf("Login incorrect\n"); /* incorrect */ ! 304: goto again; ! 305: } ! 306: } ! 307: ! 308: if (remote && passcount++ == 0) /* need another pass? */ ! 309: { logcount--; /* don't count as login attempt */ ! 310: goto again; /* yes */ ! 311: } ! 312: ! 313: ok: alarm(0); /* turn off login alarm timeout */ ! 314: endpwent(); /* close password file */ ! 315: if (chdir(s_dir) < 0) { /* cd to $HOME */ ! 316: perror(s_dir); ! 317: slowexit(1); ! 318: } ! 319: setutmp(s_tty, buff, goodlog, TRUE); /* successful login */ ! 320: #ifdef BBS ! 321: /* ! 322: * for BBS users, write "xxxxxxxxx time tty" to /usr/adm/wsrl ! 323: * where xxxxxxxxx is the serial number ! 324: * time is decimal long value of clock time at login ! 325: * tty is login device minus "/dev/" ! 326: */ ! 327: if (good_serialno) { ! 328: good_serialno = FALSE; ! 329: if (fp_srl = fopen(goodsrl, "a")) { ! 330: time(&tnum); ! 331: fprintf(fp_srl, "%s %10ld %s\n", cp, tnum, s_tty+5); ! 332: fclose(fp_srl); ! 333: } ! 334: } ! 335: #endif ! 336: chown(s_tty, s_uid, s_gid); /* grab the terminal */ ! 337: chmod(s_tty, TTYMODE); /* initialize its modes */ ! 338: setgid(s_gid); /* set group */ ! 339: setuid(s_uid); /* set user */ ! 340: if ((fd = open(motd, 0)) >= 0) { /* list message of day */ ! 341: while ((i = read(fd, buff, NBUF)) > 0) ! 342: write(2, buff, i); ! 343: close(fd); ! 344: } ! 345: execle("/bin/sh", ! 346: strcmp(s_shell, "/bin/sh") ? "+sh" : "-sh", ! 347: NULL, ! 348: s_uid == 0 ? defenv0 : defenvn); ! 349: fprintf(stderr, "No /bin/sh.\n"); ! 350: slowexit(1); ! 351: } ! 352: ! 353: /* ! 354: * Write out an accounting entry for ! 355: * 'tty' and 'username' into filename pointed to by "filep". ! 356: * If "success" is TRUE (indicating a good login) also write 'utmp' entry. ! 357: */ ! 358: setutmp(tty, username, filep, success) ! 359: char *tty, *username, *filep; ! 360: { ! 361: time_t time(); ! 362: struct utmp utmp; ! 363: struct utmp spare; ! 364: fsize_t freeslot = -1, slot = 0; ! 365: register ufd; ! 366: ! 367: utmp.ut_time = time(NULL); ! 368: strncpy(utmp.ut_line, tty+5, 8); ! 369: strncpy(utmp.ut_name, username, DIRSIZ); ! 370: if ((ufd = open(filep, 1)) >= 0) { ! 371: lseek(ufd, 0L, 2); ! 372: write(ufd, &utmp, sizeof (utmp)); ! 373: close(ufd); ! 374: } ! 375: if (!success) /* failed login attempt? */ ! 376: return; /* all done */ ! 377: ! 378: if ((ufd = open("/etc/utmp", 2)) >= 0) { ! 379: while (read(ufd, &spare, sizeof (spare)) == sizeof (spare)) { ! 380: if (spare.ut_line[0] == '\0') ! 381: freeslot = slot; ! 382: else if (strncmp(spare.ut_line, utmp.ut_line, 8) == 0) { ! 383: freeslot = slot; ! 384: break; ! 385: } ! 386: slot += sizeof (utmp); ! 387: } ! 388: if (freeslot >= 0) ! 389: lseek(ufd, freeslot, 0); ! 390: write(ufd, &utmp, sizeof (utmp)); ! 391: close (ufd); ! 392: } ! 393: } ! 394: ! 395: /* login alarm timeout routine */ ! 396: timeout() ! 397: { ! 398: printf("\n"); /* neatness */ ! 399: slowexit(1); /* exit (and try force hangup for remote line) */ ! 400: } ! 401: ! 402: /* ! 403: * Set the characters for the terminal to the defaults. ! 404: * Return non-zero on error. ! 405: */ ! 406: settty(fd) ! 407: { ! 408: struct sgttyb sgp; ! 409: ! 410: if (ioctl(fd, TIOCGETP, &sgp) < 0) ! 411: return (1); ! 412: defsgt.sg_ispeed = sgp.sg_ispeed; ! 413: defsgt.sg_ospeed = sgp.sg_ospeed; ! 414: defsgt.sg_flags &= ~(EVENP|ODDP); ! 415: defsgt.sg_flags |= sgp.sg_flags&(EVENP|ODDP); ! 416: if (ioctl(fd, TIOCSETN, &defsgt) < 0) ! 417: return(1); ! 418: if (ioctl(fd, TIOCSETC, &deftch) < 0) ! 419: return(1); ! 420: return(0); ! 421: } ! 422: ! 423: /* sleep for 2 seconds to make sure output has flushed, then exit */ ! 424: slowexit(status) ! 425: { ! 426: char *s_tty; ! 427: ! 428: if ((s_tty = ttyname(2)) != NULL) { ! 429: if (-1 == unlocktty(strrchr(s_tty, '/') + 1)) { ! 430: fprintf(stderr, "Trouble unlocking tty %s.\n", s_tty); ! 431: } ! 432: } ! 433: ! 434: sleep(2); ! 435: exit(status); ! 436: } ! 437: ! 438: /* ! 439: * Initial attempt failed, print a new prompt. ! 440: * The prompt is the last line of file LOGMSG or DEFMSG. ! 441: */ ! 442: printprompt() ! 443: { ! 444: #define BSIZE 128 ! 445: static char *msg; ! 446: int msgfd, count; ! 447: long n; ! 448: static char msgbuf[BSIZE+1]; /* login msg buffer */ ! 449: ! 450: if (msg != NULL) { /* Prompt already known. */ ! 451: printf("\r\n%s", msg); ! 452: return; ! 453: } ! 454: if ((msgfd = open(LOGMSG, 0)) < 0) { /* try for login msg file */ ! 455: printf(DEFMSG); ! 456: msg = DEFMSG; ! 457: return; ! 458: } ! 459: n = lseek(msgfd, 0L, 2); ! 460: if (n > BSIZE) ! 461: lseek(msgfd, -(long)BSIZE, 2); ! 462: else ! 463: lseek(msgfd, 0L, 0); ! 464: count = read(msgfd, msgbuf, BSIZE); /* read from file */ ! 465: close(msgfd); ! 466: while (count > 0 && msgbuf[count-1] == '\n') ! 467: --count; /* skip trailing newlines */ ! 468: msgbuf[count] = '\0'; ! 469: if (count == 0) { ! 470: printf(DEFMSG); ! 471: msg = DEFMSG; ! 472: return; ! 473: } ! 474: /* Reprint only the last line of the message file. */ ! 475: for (msg = &msgbuf[count]; msg >= msgbuf && *msg != '\n'; msg--) ! 476: ; ! 477: ++msg; ! 478: printf("\r\n%s", msg); ! 479: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.