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 6: * provided that the above copyright notice and this paragraph are 7: * duplicated in all such forms and that any documentation, 8: * advertising materials, and other materials related to such 9: * distribution and use acknowledge that the software was developed 10: * by the University of California, Berkeley. The name of the 11: * University may not be used to endorse or promote products derived 12: * from this software without specific prior written permission. 13: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16: */ 17: 18: #if defined(DOSCCS) && !defined(lint) 19: char copyright[] = 20: "@(#) Copyright (c) 1980, 1987, 1988 The Regents of the University of California.\n\ 21: All rights reserved.\n"; 22: 23: static char sccsid[] = "@(#)login.c 5.40.2 (2.11BSD GTE) 1997/9/26"; 24: #endif 25: 26: /* 27: * login [ name ] 28: * login -h hostname (for telnetd, etc.) 29: * login -f name (for pre-authenticated login: datakit, xterm, etc.) 30: */ 31: 32: #include <sys/param.h> 33: #include <sys/quota.h> 34: #include <sys/stat.h> 35: #include <sys/time.h> 36: #include <sys/resource.h> 37: #include <sys/file.h> 38: #include <sgtty.h> 39: 40: #include <utmp.h> 41: #include <signal.h> 42: #include <errno.h> 43: #include <ttyent.h> 44: #include <syslog.h> 45: #include <grp.h> 46: #include <pwd.h> 47: #include <setjmp.h> 48: #include <stdio.h> 49: #include <strings.h> 50: #include <netdb.h> 51: #include <tzfile.h> 52: #include <lastlog.h> 53: #include "pathnames.h" 54: 55: #ifdef KERBEROS 56: #include <kerberos/krb.h> 57: #include <sys/termios.h> 58: char realm[REALM_SZ]; 59: int kerror = KSUCCESS, notickets = 1; 60: #endif 61: 62: #define TTYGRPNAME "tty" /* name of group to own ttys */ 63: 64: /* 65: * This bounds the time given to login. Not a define so it can 66: * be patched on machines where it's too small. 67: */ 68: int timeout = 300; 69: 70: struct passwd *pwd; 71: int failures; 72: char term[64], *hostname, *username, *tty; 73: 74: struct sgttyb sgttyb; 75: struct tchars tc = { 76: CINTR, CQUIT, CSTART, CSTOP, CEOT, CBRK 77: }; 78: struct ltchars ltc = { 79: CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT 80: }; 81: 82: char *months[] = 83: { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", 84: "Sep", "Oct", "Nov", "Dec" }; 85: 86: main(argc, argv) 87: int argc; 88: char **argv; 89: { 90: extern int errno, optind; 91: extern char *optarg, **environ; 92: struct timeval tp; 93: struct tm *ttp; 94: struct group *gr; 95: register int ch; 96: register char *p; 97: int ask, fflag, hflag, pflag, cnt; 98: int quietlog, passwd_req, ioctlval, timedout(); 99: char *domain, *salt, *envinit[1], *ttyn, *pp; 100: char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; 101: char *ctime(), *ttyname(), *stypeof(), *crypt(), *getpass(); 102: time_t time(); 103: off_t lseek(); 104: 105: (void)signal(SIGALRM, timedout); 106: (void)alarm((u_int)timeout); 107: (void)signal(SIGQUIT, SIG_IGN); 108: (void)signal(SIGINT, SIG_IGN); 109: (void)setpriority(PRIO_PROCESS, 0, 0); 110: (void)quota(Q_SETUID, 0, 0, 0); 111: 112: /* 113: * -p is used by getty to tell login not to destroy the environment 114: * -f is used to skip a second login authentication 115: * -h is used by other servers to pass the name of the remote 116: * host to login so that it may be placed in utmp and wtmp 117: */ 118: (void)gethostname(tbuf, sizeof(tbuf)); 119: domain = index(tbuf, '.'); 120: 121: fflag = hflag = pflag = 0; 122: passwd_req = 1; 123: while ((ch = getopt(argc, argv, "fh:p")) != EOF) 124: switch (ch) { 125: case 'f': 126: fflag = 1; 127: break; 128: case 'h': 129: if (getuid()) { 130: (void)fprintf(stderr, 131: "login: -h for super-user only.\n"); 132: exit(1); 133: } 134: hflag = 1; 135: if (domain && (p = index(optarg, '.')) && 136: strcasecmp(p, domain) == 0) 137: *p = 0; 138: hostname = optarg; 139: break; 140: case 'p': 141: pflag = 1; 142: break; 143: case '?': 144: default: 145: (void)fprintf(stderr, 146: "usage: login [-fp] [username]\n"); 147: exit(1); 148: } 149: argc -= optind; 150: argv += optind; 151: if (*argv) { 152: username = *argv; 153: ask = 0; 154: } else 155: ask = 1; 156: 157: ioctlval = 0; 158: (void)ioctl(0, TIOCLSET, &ioctlval); 159: (void)ioctl(0, TIOCNXCL, 0); 160: (void)fcntl(0, F_SETFL, ioctlval); 161: (void)ioctl(0, TIOCGETP, &sgttyb); 162: sgttyb.sg_erase = CERASE; 163: sgttyb.sg_kill = CKILL; 164: (void)ioctl(0, TIOCSLTC, <c); 165: (void)ioctl(0, TIOCSETC, &tc); 166: (void)ioctl(0, TIOCSETP, &sgttyb); 167: 168: for (cnt = getdtablesize(); cnt > 2; cnt--) 169: close(cnt); 170: 171: ttyn = ttyname(0); 172: if (ttyn == NULL || *ttyn == '\0') { 173: (void)sprintf(tname, "%s??", _PATH_TTY); 174: ttyn = tname; 175: } 176: if (tty = rindex(ttyn, '/')) 177: ++tty; 178: else 179: tty = ttyn; 180: 181: openlog("login", LOG_ODELAY, LOG_AUTH); 182: 183: for (cnt = 0;; ask = 1) { 184: ioctlval = 0; 185: (void)ioctl(0, TIOCSETD, &ioctlval); 186: 187: if (ask) { 188: fflag = 0; 189: getloginname(); 190: } 191: /* 192: * Note if trying multiple user names; 193: * log failures for previous user name, 194: * but don't bother logging one failure 195: * for nonexistent name (mistyped username). 196: */ 197: if (failures && strcmp(tbuf, username)) { 198: if (failures > (pwd ? 0 : 1)) 199: badlogin(tbuf); 200: failures = 0; 201: } 202: (void)strcpy(tbuf, username); 203: if (pwd = getpwnam(username)) 204: salt = pwd->pw_passwd; 205: else 206: salt = "xx"; 207: 208: /* if user not super-user, check for disabled logins */ 209: if (pwd == NULL || pwd->pw_uid) 210: checknologin(); 211: 212: /* 213: * Disallow automatic login to root; if not invoked by 214: * root, disallow if the uid's differ. 215: */ 216: if (fflag && pwd) { 217: int uid = getuid(); 218: 219: passwd_req = pwd->pw_uid == 0 || 220: (uid && uid != pwd->pw_uid); 221: } 222: 223: /* 224: * If trying to log in as root, but with insecure terminal, 225: * refuse the login attempt. 226: */ 227: if (pwd->pw_uid == 0 && !rootterm(tty)) { 228: (void)fprintf(stderr, 229: "%s login refused on this terminal.\n", 230: pwd->pw_name); 231: if (hostname) 232: syslog(LOG_NOTICE, 233: "LOGIN %s REFUSED FROM %s ON TTY %s", 234: pwd->pw_name, hostname, tty); 235: else 236: syslog(LOG_NOTICE, 237: "LOGIN %s REFUSED ON TTY %s", 238: pwd->pw_name, tty); 239: continue; 240: } 241: 242: /* 243: * If no pre-authentication and a password exists 244: * for this user, prompt for one and verify it. 245: */ 246: if (!passwd_req || (pwd && !*pwd->pw_passwd)) 247: break; 248: 249: setpriority(PRIO_PROCESS, 0, -4); 250: pp = getpass("Password:"); 251: p = crypt(pp, salt); 252: setpriority(PRIO_PROCESS, 0, 0); 253: 254: #ifdef KERBEROS 255: 256: /* 257: * If not present in pw file, act as we normally would. 258: * If we aren't Kerberos-authenticated, try the normal 259: * pw file for a password. If that's ok, log the user 260: * in without issueing any tickets. 261: */ 262: 263: if (pwd && !krb_get_lrealm(realm,1)) { 264: /* 265: * get TGT for local realm; be careful about uid's 266: * here for ticket file ownership 267: */ 268: (void)setreuid(geteuid(),pwd->pw_uid); 269: kerror = krb_get_pw_in_tkt(pwd->pw_name, "", realm, 270: "krbtgt", realm, DEFAULT_TKT_LIFE, pp); 271: (void)setuid(0); 272: if (kerror == INTK_OK) { 273: bzero(pp, strlen(pp)); 274: notickets = 0; /* user got ticket */ 275: break; 276: } 277: } 278: #endif 279: (void) bzero(pp, strlen(pp)); 280: if (pwd && !strcmp(p, pwd->pw_passwd)) 281: break; 282: 283: (void)printf("Login incorrect\n"); 284: failures++; 285: /* we allow 10 tries, but after 3 we start backing off */ 286: if (++cnt > 3) { 287: if (cnt >= 10) { 288: badlogin(username); 289: (void)ioctl(0, TIOCHPCL, (struct sgttyb *)NULL); 290: sleepexit(1); 291: } 292: sleep((u_int)((cnt - 3) * 5)); 293: } 294: } 295: 296: /* committed to login -- turn off timeout */ 297: (void)alarm((u_int)0); 298: 299: /* paranoia... */ 300: endpwent(); 301: 302: if (quota(Q_SETUID, pwd->pw_uid, 0, 0) < 0 && errno != EINVAL) { 303: switch(errno) { 304: case EUSERS: 305: (void)fprintf(stderr, 306: "Too many users logged on already.\nTry again later.\n"); 307: break; 308: case EPROCLIM: 309: (void)fprintf(stderr, 310: "You have too many processes running.\n"); 311: break; 312: default: 313: perror("quota (Q_SETUID)"); 314: } 315: sleepexit(0); 316: } 317: 318: if (chdir(pwd->pw_dir) < 0) { 319: (void)printf("No directory %s!\n", pwd->pw_dir); 320: if (chdir("/")) 321: exit(0); 322: pwd->pw_dir = "/"; 323: (void)printf("Logging in with home = \"/\".\n"); 324: } 325: 326: quietlog = access(_PATH_HUSHLOGIN, F_OK) == 0; 327: 328: #ifdef KERBEROS 329: if (notickets && !quietlog) 330: (void)printf("Warning: no Kerberos tickets issued\n"); 331: #endif 332: 333: #define TWOWEEKS (14*24*60*60) 334: if (pwd->pw_change || pwd->pw_expire) 335: (void)gettimeofday(&tp, (struct timezone *)NULL); 336: if (pwd->pw_change) 337: if (tp.tv_sec >= pwd->pw_change) { 338: (void)printf("Sorry -- your password has expired.\n"); 339: sleepexit(1); 340: } 341: else if (pwd->pw_change - tp.tv_sec < TWOWEEKS && !quietlog) { 342: ttp = localtime(&pwd->pw_change); 343: (void)printf("Warning: your password expires on %s %d, %d\n", 344: months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year); 345: } 346: if (pwd->pw_expire) 347: if (tp.tv_sec >= pwd->pw_expire) { 348: (void)printf("Sorry -- your account has expired.\n"); 349: sleepexit(1); 350: } 351: else if (pwd->pw_expire - tp.tv_sec < TWOWEEKS && !quietlog) { 352: ttp = localtime(&pwd->pw_expire); 353: (void)printf("Warning: your account expires on %s %d, %d\n", 354: months[ttp->tm_mon], ttp->tm_mday, TM_YEAR_BASE + ttp->tm_year); 355: } 356: 357: /* nothing else left to fail -- really log in */ 358: { 359: struct utmp utmp; 360: 361: bzero((char *)&utmp, sizeof(utmp)); 362: (void)time(&utmp.ut_time); 363: strncpy(utmp.ut_name, username, sizeof(utmp.ut_name)); 364: if (hostname) 365: strncpy(utmp.ut_host, hostname, sizeof(utmp.ut_host)); 366: strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line)); 367: login(&utmp); 368: } 369: 370: dolastlog(quietlog); 371: 372: if (!hflag) { /* XXX */ 373: static struct winsize win = { 0, 0, 0, 0 }; 374: 375: (void)ioctl(0, TIOCSWINSZ, &win); 376: } 377: 378: (void)chown(ttyn, pwd->pw_uid, 379: (gr = getgrnam(TTYGRPNAME)) ? gr->gr_gid : pwd->pw_gid); 380: (void)chmod(ttyn, 0620); 381: (void)setgid(pwd->pw_gid); 382: 383: initgroups(username, pwd->pw_gid); 384: 385: quota(Q_DOWARN, pwd->pw_uid, (dev_t)-1, 0); 386: 387: if (*pwd->pw_shell == '\0') 388: pwd->pw_shell = _PATH_BSHELL; 389: /* turn on new line discipline for the csh */ 390: else if (!strcmp(pwd->pw_shell, _PATH_CSHELL)) { 391: ioctlval = NTTYDISC; 392: (void)ioctl(0, TIOCSETD, &ioctlval); 393: } 394: 395: /* destroy environment unless user has requested preservation */ 396: if (!pflag) 397: environ = envinit; 398: (void)setenv("HOME", pwd->pw_dir, 1); 399: (void)setenv("SHELL", pwd->pw_shell, 1); 400: if (term[0] == '\0') 401: strncpy(term, stypeof(tty), sizeof(term)); 402: (void)setenv("TERM", term, 0); 403: (void)setenv("USER", pwd->pw_name, 1); 404: (void)setenv("PATH", _PATH_DEFPATH, 0); 405: 406: if (tty[sizeof("tty")-1] == 'd') 407: syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); 408: if (pwd->pw_uid == 0) 409: if (hostname) 410: syslog(LOG_NOTICE, "ROOT LOGIN ON %s FROM %s", 411: tty, hostname); 412: else 413: syslog(LOG_NOTICE, "ROOT LOGIN ON %s", tty); 414: 415: if (!quietlog) { 416: struct stat st; 417: 418: motd(); 419: (void)sprintf(tbuf, "%s/%s", _PATH_MAILDIR, pwd->pw_name); 420: if (stat(tbuf, &st) == 0 && st.st_size != 0) 421: (void)printf("You have %smail.\n", 422: (st.st_mtime > st.st_atime) ? "new " : ""); 423: } 424: 425: (void)signal(SIGALRM, SIG_DFL); 426: (void)signal(SIGQUIT, SIG_DFL); 427: (void)signal(SIGINT, SIG_DFL); 428: (void)signal(SIGTSTP, SIG_IGN); 429: 430: tbuf[0] = '-'; 431: strcpy(tbuf + 1, (p = rindex(pwd->pw_shell, '/')) ? 432: p + 1 : pwd->pw_shell); 433: 434: if (setlogin(pwd->pw_name) < 0) 435: fprintf(stderr, "login: setlogin(): %s\n", strerror(errno)); 436: 437: /* discard permissions last so can't get killed and drop core */ 438: (void)setuid(pwd->pw_uid); 439: 440: execlp(pwd->pw_shell, tbuf, 0); 441: (void)fprintf(stderr, "login: no shell: %s\n", strerror(errno)); 442: exit(0); 443: } 444: 445: getloginname() 446: { 447: register int ch; 448: register char *p; 449: static char nbuf[UT_NAMESIZE + 1]; 450: 451: for (;;) { 452: (void)printf("login: "); 453: for (p = nbuf; (ch = getchar()) != '\n'; ) { 454: if (ch == EOF) { 455: badlogin(username); 456: exit(0); 457: } 458: if (p < nbuf + UT_NAMESIZE) 459: *p++ = ch; 460: } 461: if (p > nbuf) 462: if (nbuf[0] == '-') 463: (void)fprintf(stderr, 464: "login names may not start with '-'.\n"); 465: else { 466: *p = '\0'; 467: username = nbuf; 468: break; 469: } 470: } 471: } 472: 473: timedout() 474: { 475: (void)fprintf(stderr, "Login timed out after %d seconds\n", timeout); 476: exit(0); 477: } 478: 479: rootterm(ttyn) 480: char *ttyn; 481: { 482: struct ttyent *t; 483: 484: return((t = getttynam(ttyn)) && t->ty_status&TTY_SECURE); 485: } 486: 487: jmp_buf motdinterrupt; 488: 489: motd() 490: { 491: register int fd, nchars; 492: int (*oldint)(), sigint(); 493: char tbuf[BUFSIZ]; 494: 495: if ((fd = open(_PATH_MOTDFILE, O_RDONLY, 0)) < 0) 496: return; 497: oldint = signal(SIGINT, sigint); 498: if (setjmp(motdinterrupt) == 0) 499: while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 500: (void)write(fileno(stdout), tbuf, nchars); 501: (void)signal(SIGINT, oldint); 502: (void)close(fd); 503: } 504: 505: sigint() 506: { 507: longjmp(motdinterrupt, 1); 508: } 509: 510: checknologin() 511: { 512: register int fd, nchars; 513: char tbuf[BUFSIZ]; 514: 515: if ((fd = open(_PATH_NOLOGIN, O_RDONLY, 0)) >= 0) { 516: while ((nchars = read(fd, tbuf, sizeof(tbuf))) > 0) 517: (void)write(fileno(stdout), tbuf, nchars); 518: sleepexit(0); 519: } 520: } 521: 522: dolastlog(quiet) 523: int quiet; 524: { 525: struct lastlog ll; 526: int fd; 527: char *ctime(); 528: 529: if ((fd = open(_PATH_LASTLOG, O_RDWR, 0)) >= 0) { 530: (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 531: if (!quiet) { 532: if (read(fd, (char *)&ll, sizeof(ll)) == sizeof(ll) && 533: ll.ll_time != 0) { 534: (void)printf("Last login: %.*s ", 535: 24-5, (char *)ctime(&ll.ll_time)); 536: if (*ll.ll_host != '\0') 537: (void)printf("from %.*s\n", 538: sizeof(ll.ll_host), ll.ll_host); 539: else 540: (void)printf("on %.*s\n", 541: sizeof(ll.ll_line), ll.ll_line); 542: } 543: (void)lseek(fd, (off_t)pwd->pw_uid * sizeof(ll), L_SET); 544: } 545: bzero((char *)&ll, sizeof(ll)); 546: (void)time(&ll.ll_time); 547: strncpy(ll.ll_line, tty, sizeof(ll.ll_line)); 548: if (hostname) 549: strncpy(ll.ll_host, hostname, sizeof(ll.ll_host)); 550: (void)write(fd, (char *)&ll, sizeof(ll)); 551: (void)close(fd); 552: } 553: } 554: 555: badlogin(name) 556: char *name; 557: { 558: if (failures == 0) 559: return; 560: if (hostname) 561: syslog(LOG_NOTICE, "%d LOGIN FAILURE%s FROM %s, %s", 562: failures, failures > 1 ? "S" : "", hostname, name); 563: else 564: syslog(LOG_NOTICE, "%d LOGIN FAILURE%s ON %s, %s", 565: failures, failures > 1 ? "S" : "", tty, name); 566: } 567: 568: #undef UNKNOWN 569: #define UNKNOWN "su" 570: 571: char * 572: stypeof(ttyid) 573: char *ttyid; 574: { 575: struct ttyent *t; 576: 577: return(ttyid && (t = getttynam(ttyid)) ? t->ty_type : UNKNOWN); 578: } 579: 580: getstr(buf, cnt, err) 581: char *buf, *err; 582: int cnt; 583: { 584: char ch; 585: 586: do { 587: if (read(0, &ch, sizeof(ch)) != sizeof(ch)) 588: exit(1); 589: if (--cnt < 0) { 590: (void)fprintf(stderr, "%s too long\r\n", err); 591: sleepexit(1); 592: } 593: *buf++ = ch; 594: } while (ch); 595: } 596: 597: sleepexit(eval) 598: int eval; 599: { 600: sleep((u_int)5); 601: exit(eval); 602: }