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, &ltc);
 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: }

Defined functions

catch defined in line 427; used 1 times
doremotelogin defined in line 474; used 1 times
doremoteterm defined in line 515; used 1 times
getloginname defined in line 395; used 1 times
getstr defined in line 492; used 3 times
main defined in line 96; never used
rootterm defined in line 434; used 1 times
setenv defined in line 544; used 5 times
showmotd defined in line 446; used 1 times
stypeof defined in line 463; used 2 times
timedout defined in line 419; used 2 times
tty_gid defined in line 574; used 1 times
  • in line 42

Defined variables

copyright defined in line 8; never used
envinit defined in line 61; used 1 times
lastlog defined in line 56; used 1 times
ltc defined in line 83; used 1 times
lusername defined in line 91; used 8 times
maildir defined in line 55; used 2 times
minusnam defined in line 60; used 2 times
name defined in line 93; used 3 times
nolog defined in line 53; used 1 times
nouser defined in line 57; used 3 times
pwd defined in line 70; used 36 times
qlog defined in line 54; used 1 times
rflag defined in line 89; used 6 times
rhost defined in line 94; never used
rpassword defined in line 92; never used
rusername defined in line 91; used 3 times
sccsid defined in line 14; never used
speeds defined in line 510; used 5 times
stopmotd defined in line 426; used 2 times
tc defined in line 80; used 1 times
term defined in line 68; used 10 times
timeout defined in line 66; used 2 times
ttyb defined in line 58; used 5 times
usererr defined in line 90; used 3 times
utmp defined in line 59; used 25 times
win defined in line 87; used 1 times

Defined macros

FALSE defined in line 50; used 2 times
HMAX defined in line 48; used 3 times
NMAX defined in line 47; used 11 times
NSPEEDS defined in line 513; used 1 times
SCMPN defined in line 44; never used
SCPYN defined in line 45; used 8 times
TRUE defined in line 51; used 3 times
TTYGID defined in line 42; used 1 times
TTYGRPNAME defined in line 41; used 1 times
UNKNOWN defined in line 461; used 2 times
Last modified: 1986-04-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1705
Valid CSS Valid XHTML 1.0 Strict