]> git.cameronkatri.com Git - pw-darwin.git/blob - chpass/chpass.c
2fe205f9d07ead280c7dba5f97b388be5e994ecf
[pw-darwin.git] / chpass / chpass.c
1 /*-
2 * Copyright (c) 1988, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1988, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38 #endif /* not lint */
39
40 #if 0
41 #ifndef lint
42 static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94";
43 #endif /* not lint */
44 #endif
45
46 #include <sys/cdefs.h>
47 __FBSDID("$FreeBSD$");
48
49 #include <sys/param.h>
50 #include <sys/stat.h>
51 #include <sys/signal.h>
52 #include <sys/time.h>
53 #include <sys/resource.h>
54
55 #include <ctype.h>
56 #include <err.h>
57 #include <errno.h>
58 #include <fcntl.h>
59 #include <pwd.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64
65 #include <pw_scan.h>
66 #include <pw_util.h>
67 #include "pw_copy.h"
68 #ifdef YP
69 #include <rpcsvc/yp.h>
70 int yp_errno = YP_TRUE;
71 #include "pw_yp.h"
72 #endif
73
74 #include "chpass.h"
75 #include "pathnames.h"
76
77 char *tempname;
78 uid_t uid;
79
80 void baduser(void);
81 void usage(void);
82
83 char localhost[] = "localhost";
84
85 int
86 main(int argc, char *argv[])
87 {
88 enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op;
89 struct passwd *pw = NULL, lpw, old_pw;
90 char *username = NULL;
91 int ch, pfd, tfd;
92 char *arg = NULL;
93 #ifdef YP
94 int force_local = 0;
95 int force_yp = 0;
96 #endif
97
98 op = EDITENTRY;
99 #ifdef YP
100 while ((ch = getopt(argc, argv, "a:p:s:e:d:h:oly")) != -1)
101 #else
102 while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1)
103 #endif
104 switch(ch) {
105 case 'a':
106 op = LOADENTRY;
107 arg = optarg;
108 break;
109 case 's':
110 op = NEWSH;
111 arg = optarg;
112 break;
113 case 'p':
114 op = NEWPW;
115 arg = optarg;
116 break;
117 case 'e':
118 op = NEWEXP;
119 arg = optarg;
120 break;
121 #ifdef YP
122 case 'h':
123 #ifdef PARANOID
124 if (getuid()) {
125 warnx("Only the superuser can use the -h flag");
126 } else {
127 #endif
128 yp_server = optarg;
129 #ifdef PARANOID
130 }
131 #endif
132 break;
133 case 'd':
134 #ifdef PARANOID
135 if (getuid()) {
136 warnx("Only the superuser can use the -d flag");
137 } else {
138 #endif
139 yp_domain = optarg;
140 if (yp_server == NULL)
141 yp_server = localhost;
142 #ifdef PARANOID
143 }
144 #endif
145 break;
146 case 'l':
147 _use_yp = 0;
148 force_local = 1;
149 break;
150 case 'y':
151 _use_yp = force_yp = 1;
152 break;
153 case 'o':
154 force_old++;
155 break;
156 #endif
157 case '?':
158 default:
159 usage();
160 }
161 argc -= optind;
162 argv += optind;
163
164 uid = getuid();
165
166 if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) {
167 switch(argc) {
168 #ifdef YP
169 case 0:
170 GETPWUID(uid)
171 get_yp_master(1); /* XXX just to set the suser flag */
172 break;
173 case 1:
174 GETPWNAM(*argv)
175 get_yp_master(1); /* XXX just to set the suser flag */
176 #else
177 case 0:
178 if (!(pw = getpwuid(uid)))
179 errx(1, "unknown user: uid %lu",
180 (unsigned long)uid);
181 break;
182 case 1:
183 if (!(pw = getpwnam(*argv)))
184 errx(1, "unknown user: %s", *argv);
185 #endif
186 if (uid && uid != pw->pw_uid)
187 baduser();
188 break;
189 default:
190 usage();
191 }
192
193 /* Make a copy for later verification */
194 old_pw = *pw;
195 old_pw.pw_gecos = strdup(old_pw.pw_gecos);
196 }
197
198 if (op == NEWSH) {
199 /* protect p_shell -- it thinks NULL is /bin/sh */
200 if (!arg[0])
201 usage();
202 if (p_shell(arg, pw, (ENTRY *)NULL))
203 pw_error((char *)NULL, 0, 1);
204 }
205
206 if (op == NEWEXP) {
207 if (uid) /* only root can change expire */
208 baduser();
209 if (p_expire(arg, pw, (ENTRY *)NULL))
210 pw_error((char *)NULL, 0, 1);
211 }
212
213 if (op == LOADENTRY) {
214 if (uid)
215 baduser();
216 pw = &lpw;
217 if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER))
218 exit(1);
219 }
220 username = pw->pw_name;
221
222 if (op == NEWPW) {
223 if (uid)
224 baduser();
225
226 if(strchr(arg, ':')) {
227 errx(1, "invalid format for password");
228 }
229 pw->pw_passwd = arg;
230 }
231
232 /*
233 * The temporary file/file descriptor usage is a little tricky here.
234 * 1: Create a temporary file called tempname, get descriptor tfd.
235 * 2: Display() gets an fp for the temporary file, and copies the
236 * user's information into it. It then gives the temporary file
237 * to the user and closes the fp, closing the underlying fd.
238 * 3: The user edits the temporary file some number of times.
239 * The results are stored in pw by edit().
240 * 4: Delete the temporary file.
241 * 5: Make a new temporary file, descriptor tfd.
242 * 6: Get a descriptor for the master.passwd file, pfd, and
243 * lock master.passwd.
244 * 7: Pw_copy() gets descriptors for master.passwd and the
245 * temporary file and copies the master password file into it,
246 * replacing the modified user's record with a new one. We can't
247 * use the first temporary file for this because it was owned
248 * by the user. Pass the new and old user info. Check the
249 * entry for our user has not been changed by someone else by
250 * while the user was editing by comparing the old info to
251 * the entry freshly read from master.passwd. Pw_copy() closes
252 * its fp, flushing the data and closing the underlying file
253 * descriptor. We can't close the master password fp, or we'd
254 * lose the lock.
255 * 8: Call pw_mkdb() (which renames the temporary file) and exit.
256 * The exit closes the master passwd fp/fd.
257 */
258 pw_init();
259 tfd = pw_tmp();
260
261 if (op == EDITENTRY) {
262 display(tfd, pw);
263 edit(pw);
264 (void)unlink(tempname);
265 tfd = pw_tmp();
266 }
267
268 #ifdef YP
269 if (_use_yp) {
270 yp_submit(pw);
271 (void)unlink(tempname);
272 } else {
273 #endif /* YP */
274 pfd = pw_lock();
275 pw_copy(pfd, tfd, pw, (op == LOADENTRY) ? NULL : &old_pw);
276
277 if (!pw_mkdb(username))
278 pw_error((char *)NULL, 0, 1);
279 #ifdef YP
280 }
281 #endif /* YP */
282 exit(0);
283 }
284
285 void
286 baduser(void)
287 {
288 errx(1, "%s", strerror(EACCES));
289 }
290
291 void
292 usage(void)
293 {
294
295 (void)fprintf(stderr,
296 #ifdef YP
297 "usage: chpass [-o] [-l] [-y] [-d domain] [-h host] [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n");
298 #else
299 "usage: chpass [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n");
300 #endif
301 exit(1);
302 }