# 2.11BSD#431 - /usr/src/bin/chpass/chpass.c

##### Functions

    check             X
    copy              X
    edit              X
    info              X
    loadpw            X
    main              X
    makedb            X
    prompt            X
    usage             X

##### Variables

    copyright         X
    e1                X
    e2                X
    list              X
    uid               X

##### Macros

    E_BPHONE          X
    E_HPHONE          X
    E_LOCATE          X
    E_NAME            X

       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
       6:  * provided that the above copyright notice and this paragraph are
       7:  * duplicated in all such forms and that any documentation,
       8:  * advertising materials, and other materials related to such
       9:  * distribution and use acknowledge that the software was developed
      10:  * by the University of California, Berkeley.  The name of the
      11:  * University may not be used to endorse or promote products derived
      12:  * from this software without specific prior written permission.
      13:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
      14:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
      15:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
      16:  */
      17:
      18: #if !defined(lint) && defined(DOSCCS)
      19: char copyright[] =
      20: "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
      21:  All rights reserved.\n";
      22:
      23: static char sccsid[] = "@(#)chpass.c	5.10.1 (2.11BSD) 1996/1/12";
      24: #endif /* not lint */
      25:
      26: #include <sys/param.h>
      27: #include <sys/file.h>
      28: #include <sys/stat.h>
      29: #include <sys/signal.h>
      30: #include <sys/time.h>
      31: #include <sys/resource.h>
      32: #include <pwd.h>
      33: #include <errno.h>
      34: #include <stdio.h>
      35: #include <ctype.h>
      36: #include <chpass.h>
      37: #include <strings.h>
      38: #include <stdlib.h>
      39:
      40: char e1[] = ": ";
      41: char e2[] = ":,";
      42:
      43: int p_change(), p_class(), p_expire(), p_gecos(), p_gid(), p_hdir();
      44: int p_login(), p_passwd(), p_shell(), p_uid();
      45:
      46: struct entry list[] = {
      47:     { "Login",      p_login,  1,   5, e1,   },
      48:     { "Password",       p_passwd, 1,   8, e1,   },
      49:     { "Uid",        p_uid,    1,   3, e1,   },
      50:     { "Gid",        p_gid,    1,   3, e1,   },
      51:     { "Class",      p_class,  1,   5, e1,   },
      52:     { "Change",     p_change, 1,   6, NULL, },
      53:     { "Expire",     p_expire, 1,   6, NULL, },
      54: #define E_NAME      7
      55:     { "Full Name",      p_gecos,  0,   9, e2,   },
      56: #define E_BPHONE    8
      57:     { "Office Phone",   p_gecos,  0,  12, e2,   },
      58: #define E_HPHONE    9
      59:     { "Home Phone",     p_gecos,  0,  10, e2,   },
      60: #define E_LOCATE    10
      61:     { "Location",       p_gecos,  0,   8, e2,   },
      62:     { "Home directory", p_hdir,   1,  14, e1,   },
      63:     { "Shell",      p_shell,  0,   5, e1,   },
      64:     { NULL, 0, },
      65: };
      66:
      67: uid_t uid;
      68:
      69: main(argc, argv)
      70:     int argc;
      71:     char **argv;
      72: {
      73:     extern int errno, optind;
      74:     extern char *optarg;
      75:     register char *p;
      76:     struct passwd lpw, *pw;
      77:     struct rlimit rlim;
      78:     FILE *temp_fp;
      79:     int aflag, ch, fd;
      80:     char *fend, *passwd, *temp, *tend;
      81:     char from[MAXPATHLEN], to[MAXPATHLEN];
      82:     char *getusershell();
      83:
      84:     uid = getuid();
      85:     aflag = 0;
      86:     while ((ch = getopt(argc, argv, "a:")) != EOF)
      87:         switch(ch) {
      88:         case 'a':
      89:             if (uid) {
      90:                 (void)fprintf(stderr,
      91:                     "chpass: %s\n", strerror(EACCES));
      92:                 exit(1);
      93:             }
      94:             loadpw(optarg, pw = &lpw);
      95:             aflag = 1;
      96:             break;
      97:         case '?':
      98:         default:
      99:             usage();
     100:         }
     101:     argc -= optind;
     102:     argv += optind;
     103:
     104:     if (!aflag)
     105:         switch(argc) {
     106:         case 0:
     107:             if (!(pw = getpwuid(uid))) {
     108:                 (void)fprintf(stderr,
     109:                     "chpass: unknown user: uid %u\n", uid);
     110:                 exit(1);
     111:             }
     112:             break;
     113:         case 1:
     114:             if (!(pw = getpwnam(*argv))) {
     115:                 (void)fprintf(stderr,
     116:                     "chpass: unknown user %s.\n", *argv);
     117:                 exit(1);
     118:             }
     119:             if (uid && uid != pw->pw_uid) {
     120:                 (void)fprintf(stderr,
     121:                     "chpass: %s\n", strerror(EACCES));
     122:                 exit(1);
     123:             }
     124:             break;
     125:         default:
     126:             usage();
     127:         }
     128:
     129:     (void)signal(SIGHUP, SIG_IGN);
     130:     (void)signal(SIGINT, SIG_IGN);
     131:     (void)signal(SIGQUIT, SIG_IGN);
     132:     (void)signal(SIGTSTP, SIG_IGN);
     133:
     134:     rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
     135:     (void)setrlimit(RLIMIT_CPU, &rlim);
     136:     (void)setrlimit(RLIMIT_FSIZE, &rlim);
     137:
     138:     (void)umask(0);
     139:
     140:     temp = _PATH_PTMP;
     141:     if ((fd = open(temp, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) {
     142:         if (errno == EEXIST) {
     143:             (void)fprintf(stderr,
     144:                 "chpass: password file busy -- try again later.\n");
     145:             exit(1);
     146:         }
     147:         (void)fprintf(stderr, "chpass: %s: %s; ",
     148:             temp, strerror(errno));
     149:         goto bad;
     150:     }
     151:     if (!(temp_fp = fdopen(fd, "w"))) {
     152:         (void)fprintf(stderr, "chpass: can't write %s; ", temp);
     153:         goto bad;
     154:     }
     155:
     156:     if (!aflag && !info(pw))
     157:         goto bad;
     158:
     159:     /* root should have a 0 uid and a reasonable shell */
     160:     if (!strcmp(pw->pw_name, "root")) {
     161:         if (pw->pw_uid) {
     162:             (void)fprintf(stderr, "chpass: root uid should be 0.");
     163:             exit(1);
     164:         }
     165:         setusershell();
     166:         for (;;)
     167:             if (!(p = getusershell())) {
     168:                 (void)fprintf(stderr,
     169:                     "chpass: warning, unknown root shell.");
     170:                 break;
     171:             }
     172:             else if (!strcmp(pw->pw_shell, p))
     173:                 break;
     174:     }
     175:
     176:     passwd = _PATH_MASTERPASSWD;
     177:     if (!freopen(passwd, "r", stdin)) {
     178:         (void)fprintf(stderr, "chpass: can't read %s; ", passwd);
     179:         goto bad;
     180:     }
     181:     if (!copy(pw, temp_fp))
     182:         goto bad;
     183:
     184:     (void)fclose(temp_fp);
     185:     (void)fclose(stdin);
     186:
     187:     switch(fork()) {
     188:     case 0:
     189:         break;
     190:     case -1:
     191:         (void)fprintf(stderr, "chpass: can't fork; ");
     192:         goto bad;
     193:         /* NOTREACHED */
     194:     default:
     195:         exit(0);
     196:         /* NOTREACHED */
     197:     }
     198:
     199:     if (makedb(temp)) {
     200:         (void)fprintf(stderr, "chpass: mkpasswd failed; ");
     201: bad:        (void)fprintf(stderr, "%s unchanged.\n", _PATH_MASTERPASSWD);
     202:         (void)unlink(temp);
     203:         exit(1);
     204:     }
     205:
     206:     /*
     207: 	 * possible race; have to rename four files, and someone could slip
     208: 	 * in between them.  LOCK_EX and rename the ``passwd.dir'' file first
     209: 	 * so that getpwent(3) can't slip in; the lock should never fail and
     210: 	 * it's unclear what to do if it does.  Rename ``ptmp'' last so that
     211: 	 * passwd/vipw/chpass can't slip in.
     212: 	 */
     213:     (void)setpriority(PRIO_PROCESS, 0, -20);
     214:     fend = strcpy(from, temp) + strlen(temp);
     215:     tend = strcpy(to, _PATH_PASSWD) + strlen(_PATH_PASSWD);
     216:     bcopy(".dir", fend, 5);
     217:     bcopy(".dir", tend, 5);
     218:     if ((fd = open(from, O_RDONLY, 0)) >= 0)
     219:         (void)flock(fd, LOCK_EX);
     220:     /* here we go... */
     221:     (void)rename(from, to);
     222:     bcopy(".pag", fend, 5);
     223:     bcopy(".pag", tend, 5);
     224:     (void)rename(from, to);
     225:     bcopy(".orig", fend, 6);
     226:     (void)rename(from, _PATH_PASSWD);
     227:     (void)rename(temp, passwd);
     228:     /* done! */
     229:     exit(0);
     230: }
     231:
     232: info(pw)
     233:     struct passwd *pw;
     234: {
     235:     struct stat begin, end;
     236:     FILE *fp;
     237:     int fd, rval;
     238:     char *tfile;
     239:
     240:     tfile = "/tmp/passwd.XXXXXX";
     241:     if ((fd = mkstemp(tfile)) == -1 || !(fp = fdopen(fd, "w+"))) {
     242:         (void)fprintf(stderr, "chpass: no temporary file");
     243:         return(0);
     244:     }
     245:
     246:     print(fp, pw);
     247:     (void)fflush(fp);
     248:
     249:     /*
     250: 	 * give the file to the real user; setuid permissions
     251: 	 * are discarded in edit()
     252: 	 */
     253:     (void)fchown(fd, getuid(), getgid());
     254:
     255:     for (rval = 0;;) {
     256:         (void)fstat(fd, &begin);
     257:         if (edit(tfile)) {
     258:             (void)fprintf(stderr, "chpass: edit failed; ");
     259:             break;
     260:         }
     261:         (void)fstat(fd, &end);
     262:         if (begin.st_mtime == end.st_mtime) {
     263:             (void)fprintf(stderr, "chpass: no changes made; ");
     264:             break;
     265:         }
     266:         (void)rewind(fp);
     267:         if (check(fp, pw)) {
     268:             rval = 1;
     269:             break;
     270:         }
     271:         (void)fflush(stderr);
     272:         if (prompt())
     273:             break;
     274:     }
     275:     (void)fclose(fp);
     276:     (void)unlink(tfile);
     277:     return(rval);
     278: }
     279:
     280: check(fp, pw)
     281:     FILE *fp;
     282:     struct passwd *pw;
     283: {
     284:     register struct entry *ep;
     285:     register char *p;
     286:     static char buf[256];
     287:
     288:     while (fgets(buf, sizeof(buf), fp)) {
     289:         if (!buf[0] || buf[0] == '#')
     290:             continue;
     291:         if (!(p = index(buf, '\n'))) {
     292:             (void)fprintf(stderr, "chpass: line too long.\n");
     293:             return(0);
     294:         }
     295:         *p = '\0';
     296:         for (ep = list;; ++ep) {
     297:             if (!ep->prompt) {
     298:                 (void)fprintf(stderr,
     299:                     "chpass: unrecognized field.\n");
     300:                 return(0);
     301:             }
     302:             if (!strncasecmp(buf, ep->prompt, ep->len)) {
     303:                 if (ep->restricted && uid)
     304:                     break;
     305:                 if (!(p = index(buf, ':'))) {
     306:                     (void)fprintf(stderr,
     307:                         "chpass: line corrupted.\n");
     308:                     return(0);
     309:                 }
     310:                 while (isspace(*++p));
     311:                 if (ep->except && strpbrk(p, ep->except)) {
     312:                     (void)fprintf(stderr,
     313:                        "chpass: illegal character in the \"%s\" field.\n",
     314:                         ep->prompt);
     315:                     return(0);
     316:                 }
     317:                 if ((ep->func)(p, pw, ep))
     318:                     return(0);
     319:                 break;
     320:             }
     321:         }
     322:     }
     323:     /*
     324: 	 * special checks...
     325: 	 *
     326: 	 * there has to be a limit on the size of the gecos fields,
     327: 	 * otherwise getpwent(3) can choke.
     328: 	 * ``if I swallow anything evil, put your fingers down my throat...''
     329: 	 *	-- The Who
     330: 	 */
     331:     if (strlen(list[E_NAME].save) + strlen(list[E_BPHONE].save) +
     332:         strlen(list[E_HPHONE].save) + strlen(list[E_LOCATE].save)
     333:         > 128) {
     334:         (void)fprintf(stderr, "chpass: gecos field too large.\n");
     335:         exit(1);
     336:     }
     337:     (void)sprintf(pw->pw_gecos = buf, "%s,%s,%s,%s",
     338:         list[E_NAME].save, list[E_LOCATE].save, list[E_BPHONE].save,
     339:         list[E_HPHONE].save);
     340:     return(1);
     341: }
     342:
     343: copy(pw, fp)
     344:     struct passwd *pw;
     345:     FILE *fp;
     346: {
     347:     register int done;
     348:     register char *p;
     349:     char buf[256];
     350:
     351:     for (done = 0; fgets(buf, sizeof(buf), stdin);) {
     352:         /* skip lines that are too big */
     353:         if (!index(buf, '\n')) {
     354:             (void)fprintf(stderr, "chpass: line too long; ");
     355:             return(0);
     356:         }
     357:         if (done) {
     358:             (void)fprintf(fp, "%s", buf);
     359:             continue;
     360:         }
     361:         if (!(p = index(buf, ':'))) {
     362:             (void)fprintf(stderr, "chpass: corrupted entry; ");
     363:             return(0);
     364:         }
     365:         *p = '\0';
     366:         if (strcmp(buf, pw->pw_name)) {
     367:             *p = ':';
     368:             (void)fprintf(fp, "%s", buf);
     369:             continue;
     370:         }
     371:         (void)fprintf(fp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
     372:             pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
     373:             pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
     374:             pw->pw_dir, pw->pw_shell);
     375:         done = 1;
     376:     }
     377:     if (!done)
     378:         (void)fprintf(fp, "%s:%s:%d:%d:%s:%ld:%ld:%s:%s:%s\n",
     379:             pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
     380:             pw->pw_class, pw->pw_change, pw->pw_expire, pw->pw_gecos,
     381:             pw->pw_dir, pw->pw_shell);
     382:     return(1);
     383: }
     384:
     385: makedb(file)
     386:     char *file;
     387: {
     388:     int status, pid, w;
     389:
     390:     if (!(pid = vfork())) {
     391:         execl(_PATH_MKPASSWD, "mkpasswd", "-p", file, NULL);
     392:         _exit(127);
     393:     }
     394:     while ((w = wait(&status)) != pid && w != -1);
     395:     return(w == -1 || status);
     396: }
     397:
     398: edit(file)
     399:     char *file;
     400: {
     401:     int status, pid, w;
     402:     char *p, *editor, *getenv();
     403:
     404:     if (editor = getenv("EDITOR")) {
     405:         if (p = rindex(editor, '/'))
     406:             ++p;
     407:         else
     408:             p = editor;
     409:     }
     410:     else
     411:         p = editor = "vi";
     412:     if (!(pid = vfork())) {
     413:         (void)setgid(getgid());
     414:         (void)setuid(getuid());
     415:         execlp(editor, p, file, NULL);
     416:         _exit(127);
     417:     }
     418:     while ((w = wait(&status)) != pid && w != -1);
     419:     return(w == -1 || status);
     420: }
     421:
     422: loadpw(arg, pw)
     423:     char *arg;
     424:     register struct passwd *pw;
     425: {
     426:     register char *cp;
     427:     char    *bp = arg;
     428:
     429:     pw->pw_name = strsep(&bp, ":");
     430:     pw->pw_passwd = strsep(&bp, ":");
     431:     if (!(cp = strsep(&bp, ":")))
     432:         goto bad;
     433:     pw->pw_uid = atoi(cp);
     434:     if (!(cp = strsep(&bp, ":")))
     435:         goto bad;
     436:     pw->pw_gid = atoi(cp);
     437:     pw->pw_class = strsep(&bp, ":");
     438:     if (!(cp = strsep(&bp, ":")))
     439:         goto bad;
     440:     pw->pw_change = atol(cp);
     441:     if (!(cp = strsep(&bp, ":")))
     442:         goto bad;
     443:     pw->pw_expire = atol(cp);
     444:     pw->pw_gecos = strsep(&bp, ":");
     445:     pw->pw_dir = strsep(&bp, ":");
     446:     pw->pw_shell = strsep(&bp, ":");
     447:     if (!pw->pw_shell || strsep(&bp, ":")) {
     448: bad:        (void)fprintf(stderr, "chpass: bad password list.\n");
     449:         exit(1);
     450:     }
     451: }
     452:
     453: prompt()
     454: {
     455:     register int c;
     456:
     457:     for (;;) {
     458:         (void)printf("re-edit the password file? [y]: ");
     459:         (void)fflush(stdout);
     460:         c = getchar();
     461:         if (c != EOF && c != (int)'\n')
     462:             while (getchar() != (int)'\n');
     463:         return(c == (int)'n');
     464:     }
     465:     /* NOTREACHED */
     466: }
     467:
     468: usage()
     469: {
     470:     (void)fprintf(stderr, "usage: chpass [-a list] [user]\n");
     471:     exit(1);
     472: }

#### Defined functions

check defined in line 280; used 1 times

- in line 267

copy defined in line 343; used 1 times

- in line 181

edit defined in line 398; used 1 times

- in line 257

info defined in line 232; used 1 times

- in line 156

loadpw defined in line 422; used 1 times

- in line 94

main defined in line 69; never used
makedb defined in line 385; used 1 times

- in line 199

prompt defined in line 453; used 4 times

- in line 272, 297-302(2), 314

usage defined in line 468; used 2 times

- in line 99, 126

#### Defined variables

copyright defined in line 19; never used
e1 defined in line 40; used 7 times

- in line 47-51(5), 62-63(2)

e2 defined in line 41; used 4 times

- in line 55-61(4)

list defined in line 46; used 9 times

- in line 296, 331-332(4), 338-339(4)

sccsid defined in line 23; never used
uid defined in line 67; used 7 times

- in line 84-89(2), 107-109(2), 119(2), 303

#### Defined macros

E_BPHONE defined in line 56; used 2 times

- in line 331, 338

E_HPHONE defined in line 58; used 2 times

- in line 332, 339

E_LOCATE defined in line 60; used 2 times

- in line 332, 338

E_NAME defined in line 54; used 2 times

- in line 331, 338

Last modified: 1996-01-13 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1997 |