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: }