Annotation of 43BSD/bin/login.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.