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

1.1       root        1: /*
                      2:  * Copyright (c) 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) 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[] = "@(#)passwd.c   4.42 (Berkeley) 6/19/90";
                     28: #endif /* not lint */
                     29: 
                     30: #include <sys/param.h>
                     31: #include <sys/file.h>
                     32: #include <sys/signal.h>
                     33: #include <sys/time.h>
                     34: #include <sys/resource.h>
                     35: #include <sys/wait.h>
                     36: #include <errno.h>
                     37: #include <pwd.h>
                     38: #include <stdio.h>
                     39: #include <ctype.h>
                     40: #include <string.h>
                     41: 
                     42: #ifdef KERBEROS
                     43: #include <sys/types.h>
                     44: #include <sys/socket.h>
                     45: #include <netinet/in.h>
                     46: #include <netdb.h>
                     47: #include <kerberosIV/des.h>
                     48: #include <kerberosIV/krb.h>
                     49: #include "kpasswd_proto.h"
                     50: int use_kerberos = 1;
                     51: #define ARGSTR "l"
                     52: #else
                     53: #define ARGSTR ""
                     54: #endif
                     55: 
                     56: uid_t uid;
                     57: 
                     58: main(argc, argv)
                     59:        int argc;
                     60:        char **argv;
                     61: {
                     62:        register int ch;
                     63:        extern int errno, optind;
                     64:        extern char *optarg;
                     65:        struct passwd *pw;
                     66:        struct rlimit rlim;
                     67:        FILE *temp_fp;
                     68:        int fd;
                     69:        char *fend, *np, *passwd, *temp, *tend, *uname;
                     70:        char from[MAXPATHLEN], to[MAXPATHLEN];
                     71:        char *getnewpasswd(), *getlogin();
                     72: 
                     73:        uid = getuid();
                     74:        uname = getlogin();
                     75: 
                     76: #ifdef KERBEROS
                     77:        while ((ch = getopt(argc, argv, ARGSTR)) != EOF)
                     78:                switch (ch) {
                     79:                /* change local password file */
                     80:                case 'l':
                     81:                        use_kerberos = 0;
                     82:                        break;
                     83:                default:
                     84:                case '?':
                     85:                        usage();
                     86:                        exit(1);
                     87:                }
                     88: 
                     89:        argc -= optind;
                     90:        argv += optind;
                     91: #endif
                     92: 
                     93:        switch(argc) {
                     94:        case 0:
                     95:                break;
                     96:        case 1:
                     97: #ifdef KERBEROS
                     98:                if (use_kerberos && (strcmp(argv[1],uname) != 0)) { 
                     99:                        fprintf(stderr,
                    100:                                "must kinit to change another's password\n");
                    101:                        exit(1);
                    102:                }
                    103: #endif
                    104:                uname = argv[0];
                    105:                break;
                    106:        default:
                    107:                usage();
                    108:                exit(1);
                    109:        }
                    110: 
                    111: #ifdef KERBEROS
                    112:        if (use_kerberos) {
                    113:                exit(do_krb_passwd());
                    114:                /* NOTREACHED */
                    115:        }
                    116: #endif
                    117: 
                    118:        if (!(pw = getpwnam(uname))) {
                    119:                fprintf(stderr, "passwd: unknown user %s.\n", uname);
                    120:                exit(1);
                    121:        }
                    122:        if (uid && uid != pw->pw_uid) {
                    123:                fprintf(stderr, "passwd: %s\n", strerror(EACCES));
                    124:                exit(1);
                    125:        }
                    126: 
                    127:        (void)signal(SIGHUP, SIG_IGN);
                    128:        (void)signal(SIGINT, SIG_IGN);
                    129:        (void)signal(SIGQUIT, SIG_IGN);
                    130:        (void)signal(SIGTSTP, SIG_IGN);
                    131: 
                    132:        rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
                    133:        (void)setrlimit(RLIMIT_CPU, &rlim);
                    134:        (void)setrlimit(RLIMIT_FSIZE, &rlim);
                    135: 
                    136:        (void)umask(0);
                    137: 
                    138:        temp = _PATH_PTMP;
                    139:        if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) {
                    140:                if (errno == EEXIST) {
                    141:                        fprintf(stderr,
                    142:                            "passwd: password file busy -- try again later.\n");
                    143:                        exit(0);
                    144:                }
                    145:                fprintf(stderr, "passwd: %s: %s", temp, strerror(errno));
                    146:                goto bad;
                    147:        }
                    148:        if (!(temp_fp = fdopen(fd, "w"))) {
                    149:                fprintf(stderr, "passwd: can't write %s", temp);
                    150:                goto bad;
                    151:        }
                    152:        passwd = _PATH_MASTERPASSWD;
                    153:        if (!freopen(passwd, "r", stdin)) {
                    154:                fprintf(stderr, "passwd: can't read %s", passwd);
                    155:                goto bad;
                    156:        }
                    157: 
                    158:        printf("Changing local password for %s.\n", pw->pw_name);
                    159:        np = getnewpasswd(pw, temp);
                    160: 
                    161:        if (!copy(pw->pw_name, np, temp_fp, pw))
                    162:                goto bad;
                    163: 
                    164:        (void)fclose(temp_fp);
                    165:        (void)fclose(stdin);
                    166: 
                    167:        switch(fork()) {
                    168:        case 0:
                    169:                break;
                    170:        case -1:
                    171:                fprintf(stderr, "passwd: can't fork");
                    172:                goto bad;
                    173:                /* NOTREACHED */
                    174:        default:
                    175:                exit(0);
                    176:                /* NOTREACHED */
                    177:        }
                    178: 
                    179:        if (makedb(temp)) {
                    180:                fprintf(stderr, "passwd: mkpasswd failed");
                    181: bad:           fprintf(stderr, "; password unchanged.\n");
                    182:                (void)unlink(temp);
                    183:                exit(1);
                    184:        }
                    185: 
                    186:        /*
                    187:         * possible race; have to rename four files, and someone could slip
                    188:         * in between them.  LOCK_EX and rename the ``passwd.dir'' file first
                    189:         * so that getpwent(3) can't slip in; the lock should never fail and
                    190:         * it's unclear what to do if it does.  Rename ``ptmp'' last so that
                    191:         * passwd/vipw/chpass can't slip in.
                    192:         */
                    193:        (void)setpriority(PRIO_PROCESS, 0, -20);
                    194:        fend = strcpy(from, temp) + strlen(temp);
                    195:        tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD);
                    196:        bcopy(".dir", fend, 5);
                    197:        bcopy(".dir", tend, 5);
                    198:        if ((fd = open(from, O_RDONLY, 0)) >= 0)
                    199:                (void)flock(fd, LOCK_EX);
                    200:        /* here we go... */
                    201:        (void)rename(from, to);
                    202:        bcopy(".pag", fend, 5);
                    203:        bcopy(".pag", tend, 5);
                    204:        (void)rename(from, to);
                    205:        bcopy(".orig", fend, 6);
                    206:        (void)rename(from, _PATH_PASSWD);
                    207:        (void)rename(temp, passwd);
                    208:        /* done! */
                    209:        exit(0);
                    210: }
                    211: 
                    212: copy(name, np, fp, pw)
                    213:        char *name, *np;
                    214:        FILE *fp;
                    215:        struct passwd *pw;
                    216: {
                    217:        register int done;
                    218:        register char *p;
                    219:        char buf[1024];
                    220: 
                    221:        for (done = 0; fgets(buf, sizeof(buf), stdin);) {
                    222:                /* skip lines that are too big */
                    223:                if (!index(buf, '\n')) {
                    224:                        fprintf(stderr, "passwd: line too long.\n");
                    225:                        return(0);
                    226:                }
                    227:                if (done) {
                    228:                        fprintf(fp, "%s", buf);
                    229:                        continue;
                    230:                }
                    231:                if (!(p = index(buf, ':'))) {
                    232:                        fprintf(stderr, "passwd: corrupted entry.\n");
                    233:                        return(0);
                    234:                }
                    235:                *p = '\0';
                    236:                if (strcmp(buf, name)) {
                    237:                        *p = ':';
                    238:                        fprintf(fp, "%s", buf);
                    239:                        continue;
                    240:                }
                    241:                if (!(p = index(++p, ':'))) {
                    242:                        fprintf(stderr, "passwd: corrupted entry.\n");
                    243:                        return(0);
                    244:                }
                    245:                /*
                    246:                 * reset change time to zero; when classes are implemented,
                    247:                 * go and get the "offset" value for this class and reset
                    248:                 * the timer.
                    249:                 */
                    250:                fprintf(fp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
                    251:                    pw->pw_name, np, pw->pw_uid, pw->pw_gid,
                    252:                    pw->pw_class, 0L, pw->pw_expire, pw->pw_gecos,
                    253:                    pw->pw_dir, pw->pw_shell);
                    254:                done = 1;
                    255:        }
                    256:        return(1);
                    257: }
                    258: 
                    259: char *
                    260: getnewpasswd(pw, temp)
                    261:        register struct passwd *pw;
                    262:        char *temp;
                    263: {
                    264:        register char *p, *t;
                    265:        char buf[_PASSWORD_LEN+1], salt[2], *crypt(), *getpass();
                    266:        int tries = 0;
                    267:        time_t time();
                    268: 
                    269:        if (uid && pw->pw_passwd &&
                    270:            strcmp(crypt(getpass("Old password:"), pw->pw_passwd),
                    271:            pw->pw_passwd)) {
                    272:                (void)printf("passwd: %s.\n", strerror(EACCES));
                    273:                (void)unlink(temp);
                    274:                exit(1);
                    275:        }
                    276: 
                    277:        for (buf[0] = '\0';;) {
                    278:                p = getpass("New password:");
                    279:                if (!*p) {
                    280:                        (void)printf("Password unchanged.\n");
                    281:                        (void)unlink(temp);
                    282:                        exit(0);
                    283:                }
                    284:                if (strlen(p) <= 5 && (uid != 0 || tries++ < 2)) {
                    285:                        printf("Please enter a longer password.\n");
                    286:                        continue;
                    287:                }
                    288:                for (t = p; *t && islower(*t); ++t);
                    289:                if (!*t && (uid != 0 || tries++ < 2)) {
                    290:                        printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n");
                    291:                        continue;
                    292:                }
                    293:                (void)strcpy(buf, p);
                    294:                if (!strcmp(buf, getpass("Retype new password:")))
                    295:                        break;
                    296:                printf("Mismatch; try again, EOF to quit.\n");
                    297:        }
                    298:        /* grab a random printable character that isn't a colon */
                    299:        (void)srandom((int)time((time_t *)NULL));
                    300: #ifdef NEWSALT
                    301:        salt[0] = '_';
                    302:        to64(&salt[1], (long)(29*25), 4);
                    303:        to64(&salt[5], (long)random(), 4);
                    304: #else
                    305:        to64(&salt[0], (long)random(), 2);
                    306: #endif
                    307:        return(crypt(buf, salt));
                    308: }
                    309: 
                    310: static unsigned char itoa64[] =                /* 0..63 => ascii-64 */
                    311:        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
                    312: 
                    313: to64(s, v, n)
                    314:        register char *s;
                    315:        register long v;
                    316:        register int n;
                    317: {
                    318:        while (--n >= 0) {
                    319:                *s++ = itoa64[v&0x3f];
                    320:                v >>= 6;
                    321:        }
                    322: }
                    323: 
                    324: makedb(file)
                    325:        char *file;
                    326: {
                    327:        union wait pstat;
                    328:        pid_t pid, waitpid();
                    329: 
                    330:        if (!(pid = vfork())) {
                    331:                execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL);
                    332:                _exit(127);
                    333:        }
                    334:        return(waitpid(pid, &pstat, 0) == -1 ? -1 : pstat.w_status);
                    335: }
                    336: 
                    337: usage()
                    338: {
                    339: #ifdef KERBEROS
                    340:        fprintf(stderr, "usage: passwd [-l] user\n");
                    341: #else
                    342:        fprintf(stderr, "usage: passwd user\n");
                    343: #endif
                    344: }
                    345: 
                    346: 
                    347: #ifdef KERBEROS 
                    348: KTEXT_ST       ticket;
                    349: long           authopts = 0L;
                    350: Key_schedule   random_schedule;
                    351: char           realm[REALM_SZ], krbhst[MAX_HSTNM];
                    352: static         struct  kpasswd_data    proto_data;
                    353: static         des_cblock              okey;
                    354: static         Key_schedule    osched;
                    355: int            sock;
                    356: int            finish();
                    357: #define                PROTO   "tcp"
                    358: 
                    359: static struct timeval  timeout = { CLIENT_KRB_TIMEOUT, 0 };
                    360: 
                    361: do_krb_passwd()
                    362: {
                    363:        struct servent *se;
                    364:        struct hostent *host;
                    365:        struct sockaddr_in sin;
                    366:        int rval;
                    367:        char pass[_PASSWORD_LEN], password[_PASSWORD_LEN];
                    368:        fd_set readfds;
                    369:        CREDENTIALS     cred;
                    370: 
                    371:        static struct rlimit rl = { 0, 0 };
                    372: 
                    373:        (void)signal(SIGHUP, SIG_IGN);
                    374:        (void)signal(SIGINT, SIG_IGN);
                    375:        (void)signal(SIGTSTP, SIG_IGN);
                    376: 
                    377:        if (setrlimit(RLIMIT_CORE, &rl) < 0) {
                    378:                perror("setrlimit");
                    379:                return(1);
                    380:        }
                    381: 
                    382:        if ((se = getservbyname(SERVICE, PROTO)) == NULL) {
                    383:                fprintf(stderr, "couldn't find entry for service %s/%s\n",
                    384:                        SERVICE, PROTO);
                    385:                return(1);
                    386:        }
                    387: 
                    388:        if ((rval = krb_get_lrealm(realm,1)) != KSUCCESS) {
                    389:                fprintf(stderr, "couldn't get local Kerberos realm: %s\n",
                    390:                        krb_err_txt[rval]);
                    391:                return(1);
                    392:        }
                    393: 
                    394:        if ((rval = krb_get_krbhst(krbhst, realm, 1)) != KSUCCESS) {
                    395:                fprintf(stderr, "couldn't get Kerberos host: %s\n",
                    396:                        krb_err_txt[rval]);
                    397:                return(1);
                    398:        }
                    399: 
                    400:        if ((host = gethostbyname(krbhst)) == NULL) {
                    401:                fprintf(stderr, "couldn't get host entry for krb host %s\n",
                    402:                        krbhst);
                    403:                return(1);
                    404:        }
                    405: 
                    406:        sin.sin_family = host->h_addrtype;
                    407:        bcopy(host->h_addr, (char *) &sin.sin_addr, host->h_length);
                    408:        sin.sin_port = se->s_port;
                    409: 
                    410:        if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
                    411:                perror("socket");
                    412:                return(1);
                    413:        }
                    414: 
                    415:        if (connect(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
                    416:                perror("connect");
                    417:                close(sock);
                    418:                return(1);
                    419:        }
                    420: 
                    421:        rval = krb_sendauth(
                    422:                authopts,               /* NOT mutual */
                    423:                sock,
                    424:                &ticket,                /* (filled in) */
                    425:                SERVICE,
                    426:                krbhst,                 /* instance (krbhst) */
                    427:                realm,                  /* dest realm */
                    428:                (u_long) getpid(),      /* checksum */
                    429:                NULL,                   /* msg data */
                    430:                NULL,                   /* credentials */ 
                    431:                NULL,                   /* schedule */
                    432:                NULL,                   /* local addr */
                    433:                NULL,                   /* foreign addr */
                    434:                "KPWDV0.1"
                    435:        );
                    436: 
                    437: 
                    438:        if (rval != KSUCCESS) {
                    439:                fprintf(stderr, "Kerberos sendauth error: %s\n",
                    440:                        krb_err_txt[rval]);
                    441:                return(1);
                    442:        }
                    443: 
                    444:        krb_get_cred("krbtgt", realm, realm, &cred);
                    445: 
                    446:        printf("Changing Kerberos password for %s.%s@%s.\n",
                    447:                cred.pname, cred.pinst, realm);
                    448: 
                    449:        if (des_read_pw_string(pass,
                    450:            sizeof(pass)-1, "Old Kerberos password:", 0)) {
                    451:                fprintf(stderr,
                    452:                        "error reading old Kerberos password\n");
                    453:                return(1);
                    454:        }
                    455: 
                    456:        (void)des_string_to_key(pass, okey);
                    457:        (void)des_key_sched(okey, osched);
                    458:        (void)des_set_key(okey, osched);
                    459: 
                    460:        /* wait on the verification string */
                    461: 
                    462:        FD_ZERO(&readfds);
                    463:        FD_SET(sock, &readfds);
                    464: 
                    465:        rval =
                    466:          select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout);
                    467: 
                    468:        if ((rval < 1) || !FD_ISSET(sock, &readfds)) {
                    469:                if(rval == 0) {
                    470:                        fprintf(stderr, "timed out (aborted)\n");
                    471:                        cleanup();
                    472:                        return(1);
                    473:                }
                    474:                fprintf(stderr, "select failed (aborted)\n");
                    475:                cleanup();
                    476:                return(1);
                    477:        }
                    478: 
                    479:        /* read verification string */
                    480: 
                    481:        if (des_read(sock, &proto_data, sizeof(proto_data)) !=
                    482:            sizeof(proto_data)) {
                    483:                fprintf(stderr,
                    484:                    "couldn't read verification string (aborted)\n");
                    485:                cleanup();
                    486:                return(1);
                    487:        }
                    488: 
                    489:        (void)signal(SIGHUP, finish);
                    490:        (void)signal(SIGINT, finish);
                    491: 
                    492:        if (strcmp(SECURE_STRING, proto_data.secure_msg) != 0) {
                    493:                cleanup();
                    494:                /* don't complain loud if user just hit return */
                    495:                if (pass == NULL || (!*pass))
                    496:                        return(0);
                    497:                fprintf(stderr, "Sorry\n");
                    498:                return(1);
                    499:        }
                    500: 
                    501:        (void)des_key_sched(proto_data.random_key, random_schedule);
                    502:        (void)des_set_key(proto_data.random_key, random_schedule);
                    503:        (void)bzero(pass, sizeof(pass));
                    504: 
                    505:        if (des_read_pw_string(pass,
                    506:            sizeof(pass)-1, "New Kerberos password:", 0)) {
                    507:                fprintf(stderr,
                    508:                        "error reading new Kerberos password (aborted)\n");
                    509:                cleanup();
                    510:                return(1);
                    511:        }
                    512: 
                    513:        if (des_read_pw_string(password,
                    514:            sizeof(password)-1, "Retype new Kerberos password:", 0)) {
                    515:                fprintf(stderr,
                    516:                        "error reading new Kerberos password (aborted)\n");
                    517:                cleanup();
                    518:                return(1);
                    519:        }
                    520: 
                    521:        if (strcmp(password, pass) != 0) {
                    522:                fprintf(stderr, "password mismatch (aborted)\n");
                    523:                cleanup();
                    524:                return(1);
                    525:        }
                    526: 
                    527:        if (strlen(pass) == 0)
                    528:                printf("using NULL password\n");
                    529: 
                    530:        send_update(sock, password, SECURE_STRING);
                    531: 
                    532:        /* wait for ACK */
                    533: 
                    534:        FD_ZERO(&readfds);
                    535:        FD_SET(sock, &readfds);
                    536: 
                    537:        rval =
                    538:          select(sock + 1, &readfds, (fd_set *) 0, (fd_set *) 0, &timeout);
                    539:        if ((rval < 1) || !FD_ISSET(sock, &readfds)) {
                    540:                if(rval == 0) {
                    541:                        fprintf(stderr, "timed out reading ACK (aborted)\n");
                    542:                        cleanup();
                    543:                        exit(1);
                    544:                }
                    545:                fprintf(stderr, "select failed (aborted)\n");
                    546:                cleanup();
                    547:                exit(1);
                    548:        }
                    549: 
                    550:        recv_ack(sock);
                    551:        cleanup();
                    552:        exit(0);
                    553: }
                    554: 
                    555: send_update(dest, pwd, str)
                    556:        int     dest;
                    557:        char    *pwd, *str;
                    558: {
                    559:        static struct   update_data     ud;
                    560:        strncpy(ud.secure_msg, str, _PASSWORD_LEN);
                    561:        strncpy(ud.pw, pwd, sizeof(ud.pw));
                    562:        if (des_write(dest, &ud, sizeof(ud)) != sizeof(ud)) {
                    563:                fprintf(stderr, "couldn't write pw update (abort)\n");
                    564:                bzero(ud, sizeof(ud));
                    565:                cleanup();
                    566:                exit(1);
                    567:        }
                    568: }
                    569: 
                    570: recv_ack(remote)
                    571:        int     remote;
                    572: {
                    573:        int     cc;
                    574:        char    buf[BUFSIZ];
                    575:        cc = des_read(remote, buf, sizeof(buf));
                    576:        if (cc <= 0) {
                    577:                fprintf(stderr, "error reading acknowledgement (aborted)\n");
                    578:                cleanup();
                    579:                exit(1);
                    580:        }
                    581:        printf("%s", buf);
                    582: }
                    583: 
                    584: cleanup()
                    585: {
                    586:        (void)bzero(&proto_data, sizeof(proto_data));
                    587:        (void)bzero(okey, sizeof(okey));
                    588:        (void)bzero(osched, sizeof(osched));
                    589:        (void)bzero(random_schedule, sizeof(random_schedule));
                    590: }
                    591: 
                    592: finish()
                    593: {
                    594:        (void)close(sock);
                    595:        exit(1);
                    596: }
                    597: 
                    598: #endif /* KERBEROS */

unix.superglobalmegacorp.com

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