1 /* $NetBSD: chpass.c,v 1.32 2007/02/21 20:32:10 hubertf Exp $ */
4 * Copyright (c) 1988, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\
35 The Regents of the University of California. All rights reserved.");
40 static char sccsid
[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94";
42 __RCSID("$NetBSD: chpass.c,v 1.32 2007/02/21 20:32:10 hubertf Exp $");
46 #include <sys/param.h>
49 #include <sys/resource.h>
64 #include "pathnames.h"
66 static char tempname
[] = "/tmp/pw.XXXXXX";
70 void (*Pw_error
)(const char *, int, int);
73 extern int _yp_check(char **); /* buried deep inside libc */
81 main(int argc
, char **argv
)
83 enum { NEWSH
, LOADENTRY
, EDITENTRY
} op
;
84 struct passwd
*pw
, lpw
, old_pw
;
85 int ch
, dfd
, pfd
, tfd
;
89 char *arg
, *username
= NULL
;
92 pw
= NULL
; /* XXX gcc -Wuninitialized */
96 use_yp
= _yp_check(NULL
);
100 while ((ch
= getopt(argc
, argv
, "a:s:ly")) != -1)
116 errx(1, "YP not in use.");
119 errx(1, "YP support not compiled in.");
144 * We need to determine if we _really_ want to use YP.
145 * If we defaulted to YP (i.e. were not given the -y flag),
146 * and the master is not running rpc.yppasswdd, we check
147 * to see if the user exists in the local passwd database.
148 * If so, we use it, otherwise we error out.
150 if (use_yp
&& yflag
== 0) {
151 if (check_yppasswdd()) {
153 * We weren't able to contact rpc.yppasswdd.
154 * Check to see if we're in the local
155 * password database. If we are, use it.
157 if (username
!= NULL
)
158 pw
= getpwnam(username
);
164 warnx("master YP server not running yppasswd"
166 errx(1, "Can't change password.");
174 Pw_error
= yppw_error
;
180 if (op
== LOADENTRY
&& use_yp
)
181 errx(1, "cannot load entry using YP.\n"
182 "\tUse the -l flag to load local.");
185 if (op
== EDITENTRY
|| op
== NEWSH
) {
186 if (username
!= NULL
) {
187 pw
= getpwnam(username
);
189 errx(1, "unknown user: %s", username
);
190 if (uid
&& uid
!= pw
->pw_uid
)
195 errx(1, "unknown user: uid %u", uid
);
198 /* Make a copy for later verification */
200 old_pw
.pw_gecos
= strdup(old_pw
.pw_gecos
);
201 if (!old_pw
.pw_gecos
) {
208 /* protect p_shell -- it thinks NULL is /bin/sh */
211 if (p_shell(arg
, pw
, NULL
))
212 (*Pw_error
)(NULL
, 0, 1);
215 if (op
== LOADENTRY
) {
219 if (!pw_scan(arg
, pw
, NULL
))
223 /* Edit the user passwd information if requested. */
224 if (op
== EDITENTRY
) {
227 dfd
= mkstemp(tempname
);
228 if (dfd
< 0 || fcntl(dfd
, F_SETFD
, 1) < 0)
229 (*Pw_error
)(tempname
, 1, 1);
230 if (atexit(cleanup
)) {
232 errx(1, "couldn't register cleanup");
234 if (stat(dirname(tempname
), &sb
) == -1)
235 err(1, "couldn't stat `%s'", dirname(tempname
));
236 if (!(sb
.st_mode
& S_ISTXT
))
237 errx(1, "temporary directory `%s' is not sticky",
240 display(tempname
, dfd
, pw
);
247 yppw_error((char *)NULL
, 0, 1);
250 /* Will not exit from this if. */
256 * Get the passwd lock file and open the passwd file for
263 err(1, "%s", _PATH_MASTERPASSWD_LOCK
);
264 warnx("The passwd file is busy, waiting...");
268 err(1, "%s", _PATH_MASTERPASSWD_LOCK
);
269 errx(1, "The passwd file is still busy, "
273 if (fcntl(tfd
, F_SETFD
, 1) < 0)
274 pw_error(_PATH_MASTERPASSWD_LOCK
, 1, 1);
276 pfd
= open(_PATH_MASTERPASSWD
, O_RDONLY
, 0);
277 if (pfd
< 0 || fcntl(pfd
, F_SETFD
, 1) < 0)
278 pw_error(_PATH_MASTERPASSWD
, 1, 1);
280 /* Copy the passwd file to the lock file, updating pw. */
281 pw_copy(pfd
, tfd
, pw
, (op
== LOADENTRY
) ? NULL
: &old_pw
);
286 /* Now finish the passwd file update. */
287 if (pw_mkdb(username
, 0) < 0)
288 pw_error(NULL
, 0, 1);
297 errx(1, "%s", strerror(EACCES
));
304 (void)fprintf(stderr
,
305 "usage: %s [-a list] [-s shell] [-l] [user]\n"
306 " %s [-a list] [-s shell] [-y] [user]\n",
307 getprogname(), getprogname());
315 (void)unlink(tempname
);