xref: /csrg-svn/usr.bin/chpass/chpass.c (revision 66651)
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