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
main(argc,argv)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
baduser()154 baduser()
155 {
156
157 errx(1, "%s", strerror(EACCES));
158 }
159
160 void
usage()161 usage()
162 {
163
164 (void)fprintf(stderr, "usage: chpass [-a list] [-s shell] [user]\n");
165 exit(1);
166 }
167