144572Smarc /*-
2*66651Spendry * Copyright (c) 1988, 1993, 1994
361940Sbostic * The Regents of the University of California. All rights reserved.
436863Sbostic *
544572Smarc * %sccs.include.redist.c%
636863Sbostic */
736863Sbostic
836863Sbostic #ifndef lint
961940Sbostic static char copyright[] =
10*66651Spendry "@(#) Copyright (c) 1988, 1993, 1994\n\
1161940Sbostic The Regents of the University of California. All rights reserved.\n";
1236863Sbostic #endif /* not lint */
1336863Sbostic
1436863Sbostic #ifndef lint
15*66651Spendry static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 04/02/94";
1636863Sbostic #endif /* not lint */
1736863Sbostic
1836863Sbostic #include <sys/param.h>
1936863Sbostic #include <sys/stat.h>
2036863Sbostic #include <sys/signal.h>
2136863Sbostic #include <sys/time.h>
2236863Sbostic #include <sys/resource.h>
2366621Spendry
2466621Spendry #include <ctype.h>
2566621Spendry #include <err.h>
2666621Spendry #include <errno.h>
2746392Sbostic #include <fcntl.h>
2837136Sbostic #include <pwd.h>
2936863Sbostic #include <stdio.h>
3066621Spendry #include <stdlib.h>
3144572Smarc #include <string.h>
3266621Spendry #include <unistd.h>
3366621Spendry
3466621Spendry #include <pw_scan.h>
3566621Spendry #include <pw_util.h>
3666625Spendry #include "pw_copy.h"
3766621Spendry
3837867Sbostic #include "chpass.h"
3937867Sbostic #include "pathnames.h"
4036863Sbostic
4146392Sbostic char *progname = "chpass";
4246392Sbostic char *tempname;
4337136Sbostic uid_t uid;
4436863Sbostic
4566621Spendry void baduser __P((void));
4666621Spendry void usage __P((void));
4766621Spendry
4866621Spendry int
main(argc,argv)4936863Sbostic main(argc, argv)
5036863Sbostic int argc;
5136863Sbostic char **argv;
5236863Sbostic {
5366621Spendry enum { NEWSH, LOADENTRY, EDITENTRY } op;
5466621Spendry struct passwd *pw, lpw;
5546392Sbostic int ch, pfd, tfd;
5646392Sbostic char *arg;
5736863Sbostic
5846392Sbostic op = EDITENTRY;
5938212Sbostic while ((ch = getopt(argc, argv, "a:s:")) != EOF)
6037136Sbostic switch(ch) {
6137136Sbostic case 'a':
6246392Sbostic op = LOADENTRY;
6346392Sbostic arg = optarg;
6437136Sbostic break;
6538212Sbostic case 's':
6646392Sbostic op = NEWSH;
6746392Sbostic arg = optarg;
6838212Sbostic break;
6937136Sbostic case '?':
7037136Sbostic default:
7137136Sbostic usage();
7236863Sbostic }
7337136Sbostic argc -= optind;
7437136Sbostic argv += optind;
7537136Sbostic
7646392Sbostic uid = getuid();
7746392Sbostic
7846392Sbostic if (op == EDITENTRY || op == NEWSH)
7937136Sbostic switch(argc) {
8037136Sbostic case 0:
8166621Spendry if (!(pw = getpwuid(uid)))
8266621Spendry errx(1, "unknown user: uid %u", uid);
8337136Sbostic break;
8437136Sbostic case 1:
8566621Spendry if (!(pw = getpwnam(*argv)))
8666621Spendry errx(1, "unknown user: %s", *argv);
8738212Sbostic if (uid && uid != pw->pw_uid)
8838212Sbostic baduser();
8937136Sbostic break;
9037136Sbostic default:
9137136Sbostic usage();
9236863Sbostic }
9336863Sbostic
9446392Sbostic if (op == NEWSH) {
9546392Sbostic /* protect p_shell -- it thinks NULL is /bin/sh */
9646392Sbostic if (!arg[0])
9746392Sbostic usage();
9846392Sbostic if (p_shell(arg, pw, (ENTRY *)NULL))
9946392Sbostic pw_error((char *)NULL, 0, 1);
10036863Sbostic }
10136863Sbostic
10246392Sbostic if (op == LOADENTRY) {
10346392Sbostic if (uid)
10446392Sbostic baduser();
10546392Sbostic pw = &lpw;
10646392Sbostic if (!pw_scan(arg, pw))
10736863Sbostic exit(1);
10836863Sbostic }
10936863Sbostic
11036863Sbostic /*
11146952Sbostic * The temporary file/file descriptor usage is a little tricky here.
11246392Sbostic * 1: We start off with two fd's, one for the master password
11346952Sbostic * file (used to lock everything), and one for a temporary file.
11446952Sbostic * 2: Display() gets an fp for the temporary file, and copies the
11546952Sbostic * user's information into it. It then gives the temporary file
11646952Sbostic * to the user and closes the fp, closing the underlying fd.
11746392Sbostic * 3: The user edits the temporary file some number of times.
11846952Sbostic * 4: Verify() gets an fp for the temporary file, and verifies the
11946952Sbostic * contents. It can't use an fp derived from the step #2 fd,
12046952Sbostic * because the user's editor may have created a new instance of
12146952Sbostic * the file. Once the file is verified, its contents are stored
12246952Sbostic * in a password structure. The verify routine closes the fp,
12346952Sbostic * closing the underlying fd.
12446952Sbostic * 5: Delete the temporary file.
12546952Sbostic * 6: Get a new temporary file/fd. Pw_copy() gets an fp for it
12646952Sbostic * file and copies the master password file into it, replacing
12746952Sbostic * the user record with a new one. We can't use the first
12846952Sbostic * temporary file for this because it was owned by the user.
12946952Sbostic * Pw_copy() closes its fp, flushing the data and closing the
13046952Sbostic * underlying file descriptor. We can't close the master
13146952Sbostic * password fp, or we'd lose the lock.
13246952Sbostic * 7: Call pw_mkdb() (which renames the temporary file) and exit.
13346952Sbostic * The exit closes the master passwd fp/fd.
13436863Sbostic */
13546392Sbostic pw_init();
13646392Sbostic pfd = pw_lock();
13746392Sbostic tfd = pw_tmp();
13836863Sbostic
13946952Sbostic if (op == EDITENTRY) {
14046952Sbostic display(tfd, pw);
14146952Sbostic edit(pw);
14246952Sbostic (void)unlink(tempname);
14346952Sbostic tfd = pw_tmp();
14446952Sbostic }
14546952Sbostic
14646952Sbostic pw_copy(pfd, tfd, pw);
14736863Sbostic
14846392Sbostic if (!pw_mkdb())
14946392Sbostic pw_error((char *)NULL, 0, 1);
15046392Sbostic exit(0);
15137195Sbostic }
15236863Sbostic
15366621Spendry void
baduser()15438212Sbostic baduser()
15538212Sbostic {
15666621Spendry
15766621Spendry errx(1, "%s", strerror(EACCES));
15838212Sbostic }
15938212Sbostic
16066621Spendry void
usage()16137136Sbostic usage()
16237136Sbostic {
16366621Spendry
16438212Sbostic (void)fprintf(stderr, "usage: chpass [-a list] [-s shell] [user]\n");
16537136Sbostic exit(1);
16637136Sbostic }
167