2 * Copyright (c) 1990, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
33 * $FreeBSD: src/usr.bin/passwd/local_passwd.c,v 1.24.2.3 2002/03/24 09:00:11 cjc Exp $
34 * $DragonFly: src/usr.bin/passwd/local_passwd.c,v 1.3 2003/10/04 20:36:50 hmp Exp $
36 * @(#)local_passwd.c 8.3 (Berkeley) 4/2/94
39 #include <sys/types.h>
63 #ifdef AUTH_NONE /* multiple defs :-( */
66 #include <login_cap.h>
76 static unsigned char itoa64
[] = /* 0 ... 63 => ascii - 64 */
77 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
80 to64(char *s
, long v
, long n
)
83 *s
++ = itoa64
[v
&0x3f];
89 getnewpasswd(struct passwd
*pw
, int nis
)
91 int tries
, min_length
= 6;
92 int force_mix_case
= 1;
97 char buf
[_PASSWORD_LEN
+1], salt
[32];
101 (void)printf("Changing local password for %s.\n", pw
->pw_name
);
103 if (uid
&& pw
->pw_passwd
[0] &&
104 strcmp(crypt(getpass("Old password:"), pw
->pw_passwd
),
107 pw_error(NULL
, 1, 1);
112 * Determine minimum password length, next password change date,
113 * and whether or not to force mixed case passwords.
114 * Note that even for NIS passwords, login_cap is still used.
116 if ((lc
= login_getpwclass(pw
)) != NULL
) {
119 /* minpasswordlen capablity */
120 min_length
= (int)login_getcapnum(lc
, "minpasswordlen",
121 min_length
, min_length
);
122 /* passwordtime capability */
123 period
= login_getcaptime(lc
, "passwordtime", 0, 0);
124 if (period
> (time_t)0) {
125 pw
->pw_change
= time(NULL
) + period
;
127 /* mixpasswordcase capability */
128 force_mix_case
= login_getcapbool(lc
, "mixpasswordcase", 1);
132 for (buf
[0] = '\0', tries
= 0;;) {
133 p
= getpass("New password:");
135 (void)printf("Password unchanged.\n");
136 pw_error(NULL
, 0, 0);
138 if (strlen(p
) < min_length
&& (uid
!= 0 || ++tries
< 2)) {
139 (void)printf("Please enter a password at least %d characters in length.\n", min_length
);
143 if (force_mix_case
) {
144 for (t
= p
; *t
&& islower(*t
); ++t
);
145 if (!*t
&& (uid
!= 0 || ++tries
< 2)) {
146 (void)printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n");
150 (void)strcpy(buf
, p
);
151 if (!strcmp(buf
, getpass("Retype new password:")))
153 (void)printf("Mismatch; try again, EOF to quit.\n");
155 /* grab a random printable character that isn't a colon */
161 salt
[0] = _PASSWORD_EFMT1
;
162 to64(&salt
[1], (long)(29 * 25), 4);
163 to64(&salt
[5], random(), 4);
166 /* Make a good size salt for algoritms that can use it. */
169 if (login_setcryptfmt(lc
, "md5", NULL
) == NULL
)
170 pw_error("cannot set password cipher", 1, 1);
173 (void)crypt_set_format("md5");
175 /* Salt suitable for anything */
176 to64(&salt
[0], random(), 3);
177 to64(&salt
[3], tv
.tv_usec
, 3);
178 to64(&salt
[6], tv
.tv_sec
, 2);
179 to64(&salt
[8], random(), 5);
180 to64(&salt
[13], random(), 5);
181 to64(&salt
[17], random(), 5);
182 to64(&salt
[22], random(), 5);
185 return (crypt(buf
, salt
));
189 local_passwd(char *uname
)
194 if (!(pw
= getpwnam(uname
)))
195 errx(1, "unknown user %s", uname
);
198 /* Use the right password information. */
199 pw
= (struct passwd
*)&local_password
;
202 if (uid
&& uid
!= pw
->pw_uid
)
203 errx(1, "%s", strerror(EACCES
));
208 * Get the new password. Reset passwd change time to zero by
209 * default. If the user has a valid login class (or the default
210 * fallback exists), then the next password change date is set
211 * by getnewpasswd() according to the "passwordtime" capability
212 * if one has been specified.
215 pw
->pw_passwd
= getnewpasswd(pw
, 0);
219 pw_copy(pfd
, tfd
, pw
, NULL
);
222 pw_error((char *)NULL
, 0, 1);
224 syslog(LOG_DEBUG
, "user %s changed their local password\n", uname
);