Annotation of 43BSDReno/sbin/vipw/vipw.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1987 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted
                      6:  * provided that: (1) source distributions retain this entire copyright
                      7:  * notice and comment, and (2) distributions including binaries display
                      8:  * the following acknowledgement:  ``This product includes software
                      9:  * developed by the University of California, Berkeley and its contributors''
                     10:  * in the documentation or other materials provided with the distribution
                     11:  * and in all advertising materials mentioning features or use of this
                     12:  * software. Neither the name of the University nor the names of its
                     13:  * contributors may be used to endorse or promote products derived
                     14:  * from this software without specific prior written permission.
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
                     16:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
                     17:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     18:  */
                     19: 
                     20: #ifndef lint
                     21: char copyright[] =
                     22: "@(#) Copyright (c) 1987 Regents of the University of California.\n\
                     23:  All rights reserved.\n";
                     24: #endif /* not lint */
                     25: 
                     26: #ifndef lint
                     27: static char sccsid[] = "@(#)vipw.c     5.14 (Berkeley) 6/1/90";
                     28: #endif /* not lint */
                     29: 
                     30: #include <sys/param.h>
                     31: #include <sys/stat.h>
                     32: #include <sys/signal.h>
                     33: #include <sys/file.h>
                     34: #include <sys/time.h>
                     35: #include <sys/resource.h>
                     36: #include <errno.h>
                     37: #include <pwd.h>
                     38: #include <stdio.h>
                     39: #include <string.h>
                     40: 
                     41: char *passwd, *temp;
                     42: 
                     43: main()
                     44: {
                     45:        extern int errno;
                     46:        register int n, fd_passwd, fd;
                     47:        struct rlimit rlim;
                     48:        struct stat s1, s2;
                     49:        FILE *tfp;
                     50:        char *fend, *tend;
                     51:        char buf[8*1024], from[MAXPATHLEN], to[MAXPATHLEN];
                     52: 
                     53:        (void)signal(SIGHUP, SIG_IGN);
                     54:        (void)signal(SIGINT, SIG_IGN);
                     55:        (void)signal(SIGQUIT, SIG_IGN);
                     56:        (void)signal(SIGTSTP, SIG_IGN);
                     57: 
                     58:        rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
                     59:        (void)setrlimit(RLIMIT_CPU, &rlim);
                     60:        (void)setrlimit(RLIMIT_FSIZE, &rlim);
                     61: 
                     62:        (void)umask(0);
                     63: 
                     64:        temp = _PATH_PTMP;
                     65:        if ((fd = open(temp, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) {
                     66:                if (errno == EEXIST)
                     67:                        (void)fprintf(stderr, "vipw: password file busy.\n");
                     68:                else
                     69:                        (void)fprintf(stderr,
                     70:                            "vipw: %s: %s\n", temp, strerror(errno));
                     71:                exit(1);
                     72:        }
                     73:        passwd = _PATH_MASTERPASSWD;
                     74:        if ((fd_passwd = open(passwd, O_RDONLY, 0)) < 0) {
                     75:                (void)fprintf(stderr, "vipw: %s: %s\n", passwd,
                     76:                    strerror(errno));
                     77:                exit(1);
                     78:        }
                     79:        while ((n = read(fd_passwd, buf, sizeof(buf))) > 0)
                     80:                if (write(fd, buf, n) != n)
                     81:                        goto syserr;
                     82: 
                     83:        if (n == -1 || close(fd_passwd)) {
                     84: syserr:                (void)fprintf(stderr, "vipw: %s: %s; ",
                     85:                    passwd, strerror(errno));
                     86:                stop(1);
                     87:        }
                     88: 
                     89:        (void)fstat(fd, &s1);
                     90:        (void)close(fd);
                     91:        for (;;) {
                     92:                if (edit()) {
                     93:                        (void)fprintf(stderr, "vipw: edit failed; ");
                     94:                        stop(1);
                     95:                }
                     96:                /*
                     97:                 * close and re-open the file each time we edit it; some
                     98:                 * editors create a new physical file on each edit session.
                     99:                 */
                    100:                if (!(tfp = fopen(temp, "r"))) {
                    101:                        (void)fprintf(stderr, "vipw: %s: %s; ",
                    102:                            temp, strerror(errno));
                    103:                        stop(1);
                    104:                }
                    105:                (void)fstat(fileno(tfp), &s2);
                    106:                if (s1.st_mtime == s2.st_mtime) {
                    107:                        (void)fprintf(stderr, "vipw: no changes made; ");
                    108:                        stop(0);
                    109:                }
                    110:                if (!check(tfp))
                    111:                        break;
                    112:                if (prompt())
                    113:                        stop(0);
                    114:                (void)fstat(fileno(tfp), &s1);
                    115:                (void)fclose(tfp);
                    116:        }
                    117: 
                    118:        switch(fork()) {
                    119:        case 0:
                    120:                break;
                    121:        case -1:
                    122:                (void)fprintf(stderr, "vipw: can't fork; ");
                    123:                stop(1);
                    124:                /* NOTREACHED */
                    125:        default:
                    126:                exit(0);
                    127:                /* NOTREACHED */
                    128:        }
                    129: 
                    130:        if (makedb(temp)) {
                    131:                (void)fprintf(stderr, "vipw: mkpasswd failed; ");
                    132:                stop(1);
                    133:        }
                    134: 
                    135:        /*
                    136:         * possible race; have to rename four files, and someone could slip
                    137:         * in between them.  LOCK_EX and rename the ``passwd.dir'' file first
                    138:         * so that getpwent(3) can't slip in; the lock should never fail and
                    139:         * it's unclear what to do if it does.  Rename ``ptmp'' last so that
                    140:         * passwd/vipw/chpass can't slip in.
                    141:         */
                    142:        (void)setpriority(PRIO_PROCESS, 0, -20);
                    143:        fend = strcpy(from, temp) + strlen(temp);
                    144:        tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD);
                    145:        bcopy(".dir", fend, 5);
                    146:        bcopy(".dir", tend, 5);
                    147:        if ((fd = open(from, O_RDONLY, 0)) >= 0)
                    148:                (void)flock(fd, LOCK_EX);
                    149:        /* here we go... */
                    150:        (void)rename(from, to);
                    151:        bcopy(".pag", fend, 5);
                    152:        bcopy(".pag", tend, 5);
                    153:        (void)rename(from, to);
                    154:        bcopy(".orig", fend, 6);
                    155:        (void)rename(from, _PATH_PASSWD);
                    156:        (void)rename(temp, passwd);
                    157:        /* done! */
                    158:        exit(0);
                    159: }
                    160: 
                    161: check(tfp)
                    162:        FILE *tfp;
                    163: {
                    164:        register long id;
                    165:        register int lcnt, root;
                    166:        register char *p, *sh;
                    167:        long atol();
                    168:        char buf[1024], *bp, *getusershell();
                    169: 
                    170:        for (lcnt = 1; fgets(buf, sizeof(buf), tfp); ++lcnt) {
                    171:                /* skip lines that are too big */
                    172:                if (!(p = index(buf, '\n'))) {
                    173:                        (void)fprintf(stderr, "vipw: line too long");
                    174:                        goto bad;
                    175:                }
                    176:                *p = '\0';
                    177:                bp = buf;
                    178:                if (!(p = strsep(&bp, ":")))            /* login */
                    179:                        goto general;
                    180:                root = !strcmp(p, "root");
                    181:                (void)strsep(&bp, ":"); /* passwd */
                    182:                if (!(p = strsep(&bp, ":")))    /* uid */
                    183:                        goto general;
                    184:                id = atol(p);
                    185:                if (root && id) {
                    186:                        (void)fprintf(stderr, "vipw: root uid should be 0");
                    187:                        goto bad;
                    188:                }
                    189:                if (id > USHRT_MAX) {
                    190:                        (void)fprintf(stderr, "vipw: %s > max uid value (%d)",
                    191:                            p, USHRT_MAX);
                    192:                        goto bad;
                    193:                }
                    194:                if (!(p = strsep(&bp, ":")))    /* gid */
                    195:                        goto general;
                    196:                id = atol(p);
                    197:                if (id > USHRT_MAX) {
                    198:                        (void)fprintf(stderr, "vipw: %s > max gid value (%d)",
                    199:                            p, USHRT_MAX);
                    200:                        goto bad;
                    201:                }
                    202:                (void)strsep(&bp, ":"); /* class */
                    203:                (void)strsep(&bp, ":"); /* change */
                    204:                (void)strsep(&bp, ":"); /* expire */
                    205:                (void)strsep(&bp, ":"); /* gecos */
                    206:                (void)strsep(&bp, ":"); /* directory */
                    207:                if (!(p = strsep(&bp, ":")))    /* shell */
                    208:                        goto general;
                    209:                if (root && *p)                         /* empty == /bin/sh */
                    210:                        for (setusershell();;)
                    211:                                if (!(sh = getusershell())) {
                    212:                                        (void)fprintf(stderr,
                    213:                                            "vipw: warning, unknown root shell.\n");
                    214:                                        break;
                    215:                                }
                    216:                                else if (!strcmp(p, sh))
                    217:                                        break;
                    218:                if (p = strsep(&bp, ":")) {     /* too many */
                    219: (void)fprintf(stderr, "got {%s}\n", p);
                    220: general:               (void)fprintf(stderr, "vipw: corrupted entry");
                    221: bad:                   (void)fprintf(stderr, "; line #%d.\n", lcnt);
                    222:                        (void)fflush(stderr);
                    223:                        return(1);
                    224:                }
                    225:        }
                    226:        return(0);
                    227: }
                    228: 
                    229: makedb(file)
                    230:        char *file;
                    231: {
                    232:        int status, pid, w;
                    233: 
                    234:        if (!(pid = vfork())) {
                    235:                execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL);
                    236:                _exit(127);
                    237:        }
                    238:        while ((w = wait(&status)) != pid && w != -1);
                    239:        return(w == -1 || status);
                    240: }
                    241: 
                    242: edit()
                    243: {
                    244:        extern int errno;
                    245:        int status, pid, w;
                    246:        char *p, *editor, *getenv(), *strerror();
                    247: 
                    248:        if (editor = getenv("EDITOR")) {
                    249:                if (p = rindex(editor, '/'))
                    250:                        ++p;
                    251:                else
                    252:                        p = editor;
                    253:        }
                    254:        else
                    255:                p = editor = "vi";
                    256:        if (!(pid = vfork())) {
                    257:                execlp(editor, p, temp, NULL);
                    258:                (void)fprintf(stderr, "vipw: %s: %s\n", editor,
                    259:                    strerror(errno));
                    260:                _exit(127);
                    261:        }
                    262:        while ((w = wait(&status)) != pid && w != -1);
                    263:        return(w == -1 || status);
                    264: }
                    265: 
                    266: prompt()
                    267: {
                    268:        register int c;
                    269: 
                    270:        for (;;) {
                    271:                (void)printf("re-edit the password file? [y]: ");
                    272:                (void)fflush(stdout);
                    273:                c = getchar();
                    274:                if (c != EOF && c != (int)'\n')
                    275:                        while (getchar() != (int)'\n');
                    276:                return(c == (int)'n');
                    277:        }
                    278:        /* NOTREACHED */
                    279: }
                    280: 
                    281: stop(val)
                    282:        int val;
                    283: {
                    284:        (void)fprintf(stderr, "%s unchanged.\n", passwd);
                    285:        (void)unlink(temp);
                    286:        exit(val);
                    287: }

unix.superglobalmegacorp.com

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