xref: /original-bsd/usr.bin/chpass/chpass.c (revision e58c8952)
1 /*-
2  * Copyright (c) 1988, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1988, 1993, 1994\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)chpass.c	8.4 (Berkeley) 04/02/94";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 #include <sys/signal.h>
21 #include <sys/time.h>
22 #include <sys/resource.h>
23 
24 #include <ctype.h>
25 #include <err.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <pwd.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 
34 #include <pw_scan.h>
35 #include <pw_util.h>
36 #include "pw_copy.h"
37 
38 #include "chpass.h"
39 #include "pathnames.h"
40 
41 char *progname = "chpass";
42 char *tempname;
43 uid_t uid;
44 
45 void	baduser __P((void));
46 void	usage __P((void));
47 
48 int
49 main(argc, argv)
50 	int argc;
51 	char **argv;
52 {
53 	enum { NEWSH, LOADENTRY, EDITENTRY } op;
54 	struct passwd *pw, lpw;
55 	int ch, pfd, tfd;
56 	char *arg;
57 
58 	op = EDITENTRY;
59 	while ((ch = getopt(argc, argv, "a:s:")) != EOF)
60 		switch(ch) {
61 		case 'a':
62 			op = LOADENTRY;
63 			arg = optarg;
64 			break;
65 		case 's':
66 			op = NEWSH;
67 			arg = optarg;
68 			break;
69 		case '?':
70 		default:
71 			usage();
72 		}
73 	argc -= optind;
74 	argv += optind;
75 
76 	uid = getuid();
77 
78 	if (op == EDITENTRY || op == NEWSH)
79 		switch(argc) {
80 		case 0:
81 			if (!(pw = getpwuid(uid)))
82 				errx(1, "unknown user: uid %u", uid);
83 			break;
84 		case 1:
85 			if (!(pw = getpwnam(*argv)))
86 				errx(1, "unknown user: %s", *argv);
87 			if (uid && uid != pw->pw_uid)
88 				baduser();
89 			break;
90 		default:
91 			usage();
92 		}
93 
94 	if (op == NEWSH) {
95 		/* protect p_shell -- it thinks NULL is /bin/sh */
96 		if (!arg[0])
97 			usage();
98 		if (p_shell(arg, pw, (ENTRY *)NULL))
99 			pw_error((char *)NULL, 0, 1);
100 	}
101 
102 	if (op == LOADENTRY) {
103 		if (uid)
104 			baduser();
105 		pw = &lpw;
106 		if (!pw_scan(arg, pw))
107 			exit(1);
108 	}
109 
110 	/*
111 	 * The temporary file/file descriptor usage is a little tricky here.
112 	 * 1:	We start off with two fd's, one for the master password
113 	 *	file (used to lock everything), and one for a temporary file.
114 	 * 2:	Display() gets an fp for the temporary file, and copies the
115 	 *	user's information into it.  It then gives the temporary file
116 	 *	to the user and closes the fp, closing the underlying fd.
117 	 * 3:	The user edits the temporary file some number of times.
118 	 * 4:	Verify() gets an fp for the temporary file, and verifies the
119 	 *	contents.  It can't use an fp derived from the step #2 fd,
120 	 *	because the user's editor may have created a new instance of
121 	 *	the file.  Once the file is verified, its contents are stored
122 	 *	in a password structure.  The verify routine closes the fp,
123 	 *	closing the underlying fd.
124 	 * 5:	Delete the temporary file.
125 	 * 6:	Get a new temporary file/fd.  Pw_copy() gets an fp for it
126 	 *	file and copies the master password file into it, replacing
127 	 *	the user record with a new one.  We can't use the first
128 	 *	temporary file for this because it was owned by the user.
129 	 *	Pw_copy() closes its fp, flushing the data and closing the
130 	 *	underlying file descriptor.  We can't close the master
131 	 *	password fp, or we'd lose the lock.
132 	 * 7:	Call pw_mkdb() (which renames the temporary file) and exit.
133 	 *	The exit closes the master passwd fp/fd.
134 	 */
135 	pw_init();
136 	pfd = pw_lock();
137 	tfd = pw_tmp();
138 
139 	if (op == EDITENTRY) {
140 		display(tfd, pw);
141 		edit(pw);
142 		(void)unlink(tempname);
143 		tfd = pw_tmp();
144 	}
145 
146 	pw_copy(pfd, tfd, pw);
147 
148 	if (!pw_mkdb())
149 		pw_error((char *)NULL, 0, 1);
150 	exit(0);
151 }
152 
153 void
154 baduser()
155 {
156 
157 	errx(1, "%s", strerror(EACCES));
158 }
159 
160 void
161 usage()
162 {
163 
164 	(void)fprintf(stderr, "usage: chpass [-a list] [-s shell] [user]\n");
165 	exit(1);
166 }
167