Annotation of 43BSDReno/usr.bin/login/login.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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