1 /* $NetBSD: local_passwd.c,v 1.36 2012/03/25 05:55:07 dholland Exp $ */
4 * Copyright (c) 1990, 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>
35 static char sccsid
[] = "from: @(#)local_passwd.c 8.3 (Berkeley) 4/2/94";
37 __RCSID("$NetBSD: local_passwd.c,v 1.36 2012/03/25 05:55:07 dholland Exp $");
41 #include <sys/types.h>
55 #include <login_cap.h>
63 getnewpasswd(struct passwd
*pw
, int min_pw_len
)
67 char buf
[_PASSWORD_LEN
+1], salt
[_PASSWORD_LEN
+1];
68 char option
[LINE_MAX
], *key
, *opt
;
70 (void)printf("Changing local password for %s.\n", pw
->pw_name
);
72 if (uid
&& pw
->pw_passwd
[0] &&
73 strcmp(crypt(getpass("Old password:"), pw
->pw_passwd
),
76 syslog(LOG_AUTH
| LOG_NOTICE
,
77 "user %s (UID %lu) failed to change the "
78 "local password of user %s: %m",
79 pw
->pw_name
, (unsigned long)uid
, pw
->pw_name
);
83 for (buf
[0] = '\0', tries
= 0;;) {
84 p
= getpass("New password:");
86 (void)printf("Password unchanged.\n");
89 if (min_pw_len
> 0 && (int)strlen(p
) < min_pw_len
) {
90 (void) printf("Password is too short.\n");
93 if (strlen(p
) <= 5 && ++tries
< 2) {
94 (void)printf("Please enter a longer password.\n");
97 for (t
= p
; *t
&& islower((unsigned char)*t
); ++t
);
98 if (!*t
&& ++tries
< 2) {
99 (void)printf("Please don't use an all-lower case "
100 "password.\nUnusual capitalization, "
101 "control characters or digits are "
105 (void)strlcpy(buf
, p
, sizeof(buf
));
106 if (!strcmp(buf
, getpass("Retype new password:")))
108 (void)printf("Mismatch; try again, EOF to quit.\n");
111 pw_getpwconf(option
, sizeof(option
), pw
, "localcipher");
113 key
= strsep(&opt
, ",");
114 if(pw_gensalt(salt
, _PASSWORD_LEN
, key
, opt
) == -1) {
115 warn("Couldn't generate salt");
116 pw_error(NULL
, 0, 0);
118 return(crypt(buf
, salt
));
124 pwlocal_usage(const char *prefix
)
127 (void) fprintf(stderr
, "%s %s [-d files | -l] [user]\n",
128 prefix
, getprogname());
132 pwlocal_process(const char *username
, int argc
, char **argv
)
135 struct passwd old_pw
;
145 while ((ch
= getopt(argc
, argv
, "l")) != -1) {
149 * Aborb the -l that may have gotten us here.
164 /* username already provided */
174 if (!(pw
= getpwnam(username
)))
175 errx(1, "unknown user %s", username
);
178 if (uid
&& uid
!= pw
->pw_uid
)
179 errx(1, "%s", strerror(EACCES
));
181 /* Save the old pw information for comparing on pw_copy(). */
185 * Get class restrictions for this user, then get the new password.
188 if((lc
= login_getclass(pw
->pw_class
)) != NULL
) {
189 min_pw_len
= (int) login_getcapnum(lc
, "minpasswordlen", 0, 0);
190 pw_expiry
= (int) login_getcaptime(lc
, "passwordtime", 0, 0);
195 pw
->pw_passwd
= getnewpasswd(pw
, min_pw_len
);
196 old_change
= pw
->pw_change
;
197 pw
->pw_change
= pw_expiry
? pw_expiry
+ time(NULL
) : 0;
200 * Now that the user has given us a new password, let us
201 * change the database.
206 warnx ("The passwd file is busy, waiting...");
209 errx(1, "The passwd file is still busy, "
213 pfd
= open(_PATH_MASTERPASSWD
, O_RDONLY
, 0);
215 pw_error(_PATH_MASTERPASSWD
, 1, 1);
217 pw_copy(pfd
, tfd
, pw
, &old_pw
);
219 if (pw_mkdb(username
, old_change
== pw
->pw_change
) < 0)
220 pw_error(NULL
, 0, 1);
222 syslog(LOG_AUTH
| LOG_INFO
,
223 "user %s (UID %lu) successfully changed "
224 "the local password of user %s",
225 uid
? username
: "root", (unsigned long)uid
, username
);
228 #else /* ! USE_PAM */
230 static int force_local
;
233 local_init(const char *progname
)
240 local_arg(char ch
, const char *arg
)
256 return(PW_USE_FORCE
);
267 local_chpw(const char *uname
)
270 struct passwd old_pw
;
279 if (!(pw
= getpwnam(uname
))) {
280 warnx("unknown user %s", uname
);
285 if (uid
&& uid
!= pw
->pw_uid
) {
286 warnx("%s", strerror(EACCES
));
290 /* Save the old pw information for comparing on pw_copy(). */
294 * Get class restrictions for this user, then get the new password.
297 if((lc
= login_getclass(pw
->pw_class
))) {
298 min_pw_len
= (int) login_getcapnum(lc
, "minpasswordlen", 0, 0);
299 pw_expiry
= (int) login_getcaptime(lc
, "passwordtime", 0, 0);
304 pw
->pw_passwd
= getnewpasswd(pw
, min_pw_len
);
305 old_change
= pw
->pw_change
;
306 pw
->pw_change
= pw_expiry
? pw_expiry
+ time(NULL
) : 0;
309 * Now that the user has given us a new password, let us
310 * change the database.
315 warnx ("The passwd file is busy, waiting...");
318 errx(1, "The passwd file is still busy, "
322 pfd
= open(_PATH_MASTERPASSWD
, O_RDONLY
, 0);
324 pw_error(_PATH_MASTERPASSWD
, 1, 1);
326 pw_copy(pfd
, tfd
, pw
, &old_pw
);
328 if (pw_mkdb(uname
, old_change
== pw
->pw_change
) < 0)
329 pw_error(NULL
, 0, 1);
331 syslog(LOG_AUTH
| LOG_INFO
,
332 "user %s (UID %lu) successfully changed "
333 "the local password of user %s",
334 uid
? uname
: "root", (unsigned long)uid
, uname
);