|
|
1.1 ! root 1: /*- ! 2: * Copyright (c) 1980, 1987, 1988 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)login.c 5.63 (Berkeley) 6/29/90"; ! 28: #endif /* not lint */ ! 29: ! 30: /* ! 31: * login [ name ] ! 32: * login -h hostname (for telnetd, etc.) ! 33: * login -f name (for pre-authenticated login: datakit, xterm, etc.) ! 34: */ ! 35: ! 36: #include <sys/param.h> ! 37: #include <sys/stat.h> ! 38: #include <sys/time.h> ! 39: #include <sys/resource.h> ! 40: #include <sys/file.h> ! 41: #include <sgtty.h> ! 42: ! 43: #include <utmp.h> ! 44: #include <signal.h> ! 45: #include <errno.h> ! 46: #include <ttyent.h> ! 47: #include <syslog.h> ! 48: #include <grp.h> ! 49: #include <pwd.h> ! 50: #include <setjmp.h> ! 51: #include <stdio.h> ! 52: #include <string.h> ! 53: #include <tzfile.h> ! 54: #include "pathnames.h" ! 55: ! 56: #define TTYGRPNAME "tty" /* name of group to own ttys */ ! 57: ! 58: /* ! 59: * This bounds the time given to login. Not a define so it can ! 60: * be patched on machines where it's too small. ! 61: */ ! 62: int timeout = 300; ! 63: #ifdef KERBEROS ! 64: int notickets = 1; ! 65: #endif ! 66: ! 67: struct passwd *pwd; ! 68: int failures; ! 69: char term[64], *envinit[1], *hostname, *username, *tty; ! 70: ! 71: main(argc, argv) ! 72: int argc; ! 73: char **argv; ! 74: { ! 75: extern int optind; ! 76: extern char *optarg, **environ; ! 77: struct timeval tp; ! 78: struct group *gr; ! 79: register int ch; ! 80: register char *p; ! 81: int ask, fflag, hflag, pflag, cnt, uid; ! 82: int quietlog, rval; ! 83: char *domain, *salt, *ttyn; ! 84: char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; ! 85: char localhost[MAXHOSTNAMELEN]; ! 86: char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); ! 87: time_t time(); ! 88: off_t lseek(); ! 89: void timedout(); ! 90: ! 91: (void)signal(SIGALRM, timedout); ! 92: (void)alarm((u_int)timeout); ! 93: (void)signal(SIGQUIT, SIG_IGN); ! 94: (void)signal(SIGINT, SIG_IGN); ! 95: (void)setpriority(PRIO_PROCESS, 0, 0); ! 96: ! 97: openlog("login", LOG_ODELAY, LOG_AUTH); ! 98: ! 99: /* ! 100: * -p is used by getty to tell login not to destroy the environment ! 101: * -f is used to skip a second login authentication ! 102: * -h is used by other servers to pass the name of the remote ! 103: * host to login so that it may be placed in utmp and wtmp ! 104: */ ! 105: domain = NULL; ! 106: if (gethostname(localhost, sizeof(localhost)) < 0) ! 107: syslog(LOG_ERR, "couldn't get local hostname: %m"); ! 108: else ! 109: domain = index(localhost, '.'); ! 110: ! 111: fflag = hflag = pflag = 0; ! 112: uid = getuid(); ! 113: while ((ch = getopt(argc, argv, "fh:p")) != EOF) ! 114: switch (ch) { ! 115: case 'f': ! 116: fflag = 1; ! 117: break; ! 118: case 'h': ! 119: if (uid) { ! 120: (void)fprintf(stderr, ! 121: "login: -h for super-user only.\n"); ! 122: exit(1); ! 123: } ! 124: hflag = 1; ! 125: if (domain && (p = index(optarg, '.')) && ! 126: strcasecmp(p, domain) == 0) ! 127: *p = 0; ! 128: hostname = optarg; ! 129: break; ! 130: case 'p': ! 131: pflag = 1; ! 132: break; ! 133: case '?': ! 134: default: ! 135: if (!uid) ! 136: syslog(LOG_ERR, "invalid flag %c", ch); ! 137: (void)fprintf(stderr, ! 138: "usage: login [-fp] [username]\n"); ! 139: exit(1); ! 140: } ! 141: argc -= optind; ! 142: argv += optind; ! 143: if (*argv) { ! 144: username = *argv; ! 145: if (strlen(username) > UT_NAMESIZE) ! 146: username[UT_NAMESIZE] = '\0'; ! 147: ask = 0; ! 148: } else ! 149: ask = 1; ! 150: ! 151: for (cnt = getdtablesize(); cnt > 2; cnt--) ! 152: close(cnt); ! 153: ! 154: ttyn = ttyname(0); ! 155: if (ttyn == NULL || *ttyn == '\0') { ! 156: (void)sprintf(tname, "%s??", _PATH_TTY); ! 157: ttyn = tname; ! 158: } ! 159: if (tty = rindex(ttyn, '/')) ! 160: ++tty; ! 161: else ! 162: tty = ttyn; ! 163: ! 164: for (cnt = 0;; ask = 1) { ! 165: if (ask) { ! 166: fflag = 0; ! 167: getloginname(); ! 168: } ! 169: /* ! 170: * Note if trying multiple user names; log failures for ! 171: * previous user name, but don't bother logging one failure ! 172: * for nonexistent name (mistyped username). ! 173: */ ! 174: if (failures && strcmp(tbuf, username)) { ! 175: if (failures > (pwd ? 0 : 1)) ! 176: badlogin(tbuf); ! 177: failures = 0; ! 178: } ! 179: (void)strcpy(tbuf, username); ! 180: ! 181: if (pwd = getpwnam(username)) ! 182: salt = pwd->pw_passwd; ! 183: else ! 184: salt = "xx"; ! 185: ! 186: /* ! 187: * if we have a valid account name, and it doesn't have a ! 188: * password, or the -f option was specified and the caller ! 189: * is root or the caller isn't changing their uid, don't ! 190: * authenticate. ! 191: */ ! 192: if (pwd && (*pwd->pw_passwd == '\0' || ! 193: fflag && (uid == 0 || uid == pwd->pw_uid))) ! 194: break; ! 195: fflag = 0; ! 196: ! 197: /* ! 198: * If trying to log in as root, but with insecure terminal, ! 199: * refuse the login attempt. ! 200: */ ! 201: if (pwd && pwd->pw_uid == 0 && !rootterm(tty)) { ! 202: (void)fprintf(stderr, ! 203: "%s login refused on this terminal.\n", ! 204: pwd->pw_name); ! 205: if (hostname) ! 206: syslog(LOG_NOTICE, ! 207: "LOGIN %s REFUSED FROM %s ON TTY %s", ! 208: pwd->pw_name, hostname, tty); ! 209: else ! 210: syslog(LOG_NOTICE, ! 211: "LOGIN %s REFUSED ON TTY %s", ! 212: pwd->pw_name, tty); ! 213: continue; ! 214: } ! 215: ! 216: (void)setpriority(PRIO_PROCESS, 0, -4); ! 217: ! 218: p = getpass("Password:"); ! 219: ! 220: if (pwd) { ! 221: #ifdef KERBEROS ! 222: rval = klogin(pwd, localhost, p); ! 223: if (rval == 1) ! 224: rval = strcmp(crypt(p, salt), pwd->pw_passwd); ! 225: #else ! 226: rval = strcmp(crypt(p, salt), pwd->pw_passwd); ! 227: #endif ! 228: } ! 229: bzero(p, strlen(p)); ! 230: ! 231: (void)setpriority(PRIO_PROCESS, 0, 0); ! 232: ! 233: if (pwd && !rval) ! 234: break; ! 235: ! 236: (void)printf("Login incorrect\n"); ! 237: failures++; ! 238: /* we allow 10 tries, but after 3 we start backing off */ ! 239: if (++cnt > 3) { ! 240: if (cnt >= 10) { ! 241: badlogin(username); ! 242: sleepexit(1); ! 243: } ! 244: sleep((u_int)((cnt - 3) * 5)); ! 245: } ! 246: } ! 247: ! 248: /* committed to login -- turn off timeout */ ! 249: (void)alarm((u_int)0); ! 250: ! 251: /* paranoia... */ ! 252: endpwent(); ! 253: ! 254: /* if user not super-user, check for disabled logins */ ! 255: if (pwd->pw_uid) ! 256: checknologin(); ! 257: ! 258: if (chdir(pwd->pw_dir) < 0) { ! 259: (void)printf("No directory %s!\n", pwd->pw_dir); ! 260: if (chdir("/")) ! 261: exit(0); ! 262: pwd->pw_dir = "/"; ! 263: (void)printf("Logging in with home = \"/\".\n"); ! 264: } ! 265: ! 266: quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; ! 267: ! 268: if (pwd->pw_change || pwd->pw_expire) ! 269: (void)gettimeofday(&tp, (struct timezone *)NULL); ! 270: if (pwd->pw_change) ! 271: if (tp.tv_sec >= pwd->pw_change) { ! 272: (void)printf("Sorry -- your password has expired.\n"); ! 273: sleepexit(1); ! 274: } ! 275: else if (pwd->pw_change - tp.tv_sec < ! 276: 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) ! 277: (void)printf("Warning: your password expires on %s", ! 278: ctime(&pwd->pw_expire)); ! 279: if (pwd->pw_expire) ! 280: if (tp.tv_sec >= pwd->pw_expire) { ! 281: (void)printf("Sorry -- your account has expired.\n"); ! 282: sleepexit(1); ! 283: } ! 284: else if (pwd->pw_expire - tp.tv_sec < ! 285: 2 * DAYSPERWEEK * SECSPERDAY && !quietlog) ! 286: (void)printf("Warning: your account expires on %s", ! 287: ctime(&pwd->pw_expire)); ! 288: ! 289: /* nothing else left to fail -- really log in */ ! 290: { ! 291: struct utmp utmp; ! 292: ! 293: bzero((void *)&utmp, sizeof(utmp)); ! 294: (void)time(&utmp.ut_time); ! 295: strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); ! 296: if (hostname) ! 297: strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); ! 298: strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); ! 299: login(&utmp); ! 300: } ! 301: ! 302: dolastlog(quietlog); ! 303: ! 304: (void)chown(ttyn, pwd->pw_uid, ! 305: (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); ! 306: (void)chmod(ttyn, 0620); ! 307: (void)setgid(pwd->pw_gid); ! 308: ! 309: initgroups(username, pwd->pw_gid); ! 310: ! 311: if (*pwd->pw_shell == '\0') ! 312: pwd->pw_shell = _PATH_BSHELL; ! 313: ! 314: /* destroy environment unless user has requested preservation */ ! 315: if (!pflag) ! 316: environ = envinit; ! 317: (void)setenv("HOME", pwd->pw_dir, 1); ! 318: (void)setenv("SHELL", pwd->pw_shell, 1); ! 319: if (term[0] == '\0') ! 320: strncpy(term, stypeof(tty), sizeof(term)); ! 321: (void)setenv("TERM", term, 0); ! 322: (void)setenv("USER", pwd->pw_name, 1); ! 323: (void)setenv("PATH", _PATH_DEFPATH, 0); ! 324: ! 325: if (tty[sizeof("tty")-1] == 'd') ! 326: syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); ! 327: /* if fflag is on, assume caller/authenticator has logged root login */ ! 328: if (pwd->pw_uid == 0 && fflag == 0) ! 329: if (hostname) ! 330: syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", ! 331: tty, hostname); ! 332: else ! 333: syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); ! 334: ! 335: #ifdef KERBEROS ! 336: if (!quietlog && notickets == 1) ! 337: (void)printf("Warning: no Kerberos tickets issued.\n"); ! 338: #endif ! 339: ! 340: if (!quietlog) { ! 341: struct stat st; ! 342: ! 343: motd(); ! 344: (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); ! 345: if (stat(tbuf, &st) == 0 && st.st_size != 0) ! 346: (void)printf("You have %smail.\n", ! 347: (st.st_mtime > st.st_atime) ? "new " : ""); ! 348: } ! 349: ! 350: (void)signal(SIGALRM, SIG_DFL); ! 351: (void)signal(SIGQUIT, SIG_DFL); ! 352: (void)signal(SIGINT, SIG_DFL); ! 353: (void)signal(SIGTSTP, SIG_IGN); ! 354: ! 355: tbuf[0] = '-'; ! 356: strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? ! 357: p + 1 : pwd->pw_shell); ! 358: ! 359: if (setlogin(pwd->pw_name) < 0) ! 360: syslog(LOG_ERR, "setlogin() failure: %m"); ! 361: ! 362: /* discard permissions last so can't get killed and drop core */ ! 363: (void)setuid(pwd->pw_uid); ! 364: ! 365: execlp(pwd->pw_shell, tbuf, 0); ! 366: (void)fprintf(stderr, "login: no shell: %s.\n", strerror(errno)); ! 367: exit(0); ! 368: } ! 369: ! 370: getloginname() ! 371: { ! 372: register int ch; ! 373: register char *p; ! 374: static char nbuf[UT_NAMESIZE + 1]; ! 375: ! 376: for (;;) { ! 377: (void)printf("login: "); ! 378: for (p = nbuf; (ch = getchar()) != '\n'; ) { ! 379: if (ch == EOF) { ! 380: badlogin(username); ! 381: exit(0); ! 382: } ! 383: if (p < nbuf + UT_NAMESIZE) ! 384: *p++ = ch; ! 385: } ! 386: if (p > nbuf) ! 387: if (nbuf[0] == '-') ! 388: (void)fprintf(stderr, ! 389: "login names may not start with '-'.\n"); ! 390: else { ! 391: *p = '\0'; ! 392: username = nbuf; ! 393: break; ! 394: } ! 395: } ! 396: } ! 397: ! 398: void ! 399: timedout() ! 400: { ! 401: (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); ! 402: exit(0); ! 403: } ! 404: ! 405: rootterm(ttyn) ! 406: char *ttyn; ! 407: { ! 408: struct ttyent *t; ! 409: ! 410: return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); ! 411: } ! 412: ! 413: jmp_buf motdinterrupt; ! 414: ! 415: motd() ! 416: { ! 417: register int fd, nchars; ! 418: sig_t oldint; ! 419: int sigint(); ! 420: char tbuf[8192]; ! 421: ! 422: if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) ! 423: return; ! 424: oldint = signal(SIGINT, sigint); ! 425: if (setjmp(motdinterrupt) == 0) ! 426: while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) ! 427: (void)write(fileno(stdout), tbuf, nchars); ! 428: (void)signal(SIGINT, oldint); ! 429: (void)close(fd); ! 430: } ! 431: ! 432: sigint() ! 433: { ! 434: longjmp(motdinterrupt, 1); ! 435: } ! 436: ! 437: checknologin() ! 438: { ! 439: register int fd, nchars; ! 440: char tbuf[8192]; ! 441: ! 442: if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { ! 443: while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) ! 444: (void)write(fileno(stdout), tbuf, nchars); ! 445: sleepexit(0); ! 446: } ! 447: } ! 448: ! 449: dolastlog(quiet) ! 450: int quiet; ! 451: { ! 452: struct lastlog ll; ! 453: int fd; ! 454: char *ctime(); ! 455: ! 456: if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { ! 457: (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); ! 458: if (!quiet) { ! 459: if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && ! 460: ll.ll_time != 0) { ! 461: (void)printf("Last login: %.*s ", ! 462: 24-5, (char *)ctime(&ll.ll_time)); ! 463: if (*ll.ll_host != '\0') ! 464: (void)printf("from %.*s\n", ! 465: sizeof(ll.ll_host), ll.ll_host); ! 466: else ! 467: (void)printf("on %.*s\n", ! 468: sizeof(ll.ll_line), ll.ll_line); ! 469: } ! 470: (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); ! 471: } ! 472: bzero((void *)&ll, sizeof(ll)); ! 473: (void)time(&ll.ll_time); ! 474: strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); ! 475: if (hostname) ! 476: strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); ! 477: (void)write(fd, (char *)&ll, sizeof(ll)); ! 478: (void)close(fd); ! 479: } ! 480: } ! 481: ! 482: badlogin(name) ! 483: char *name; ! 484: { ! 485: if (failures == 0) ! 486: return; ! 487: if (hostname) ! 488: syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", ! 489: failures, failures > 1 ? "S" : "", hostname, name); ! 490: else ! 491: syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", ! 492: failures, failures > 1 ? "S" : "", tty, name); ! 493: } ! 494: ! 495: #undef UNKNOWN ! 496: #define UNKNOWN "su" ! 497: ! 498: char * ! 499: stypeof(ttyid) ! 500: char *ttyid; ! 501: { ! 502: struct ttyent *t; ! 503: ! 504: return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); ! 505: } ! 506: ! 507: sleepexit(eval) ! 508: int eval; ! 509: { ! 510: sleep((u_int)5); ! 511: exit(eval); ! 512: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.