MFC:
[dragonfly.git] / usr.bin / passwd / local_passwd.c
blobb1f241a37414d4eca2e96d96cac40e7e2255a80e
1 /*-
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
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.
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.
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>
40 #include <sys/time.h>
42 #include <ctype.h>
43 #include <err.h>
44 #include <errno.h>
45 #include <pwd.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <time.h>
50 #include <unistd.h>
52 #include <pw_copy.h>
53 #include <pw_util.h>
54 #ifdef YP
55 #include <pw_yp.h>
56 #endif
58 #ifdef LOGGING
59 #include <syslog.h>
60 #endif
62 #ifdef LOGIN_CAP
63 #ifdef AUTH_NONE /* multiple defs :-( */
64 #undef AUTH_NONE
65 #endif
66 #include <login_cap.h>
67 #endif
69 #include "extern.h"
71 static uid_t uid;
72 int randinit;
74 char *tempname;
76 static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
77 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
79 void
80 to64(char *s, long v, long n)
82 while (--n >= 0) {
83 *s++ = itoa64[v&0x3f];
84 v >>= 6;
88 char *
89 getnewpasswd(struct passwd *pw, int nis)
91 int tries, min_length = 6;
92 int force_mix_case = 1;
93 char *p, *t;
94 #ifdef LOGIN_CAP
95 login_cap_t * lc;
96 #endif
97 char buf[_PASSWORD_LEN+1], salt[32];
98 struct timeval tv;
100 if (!nis)
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),
105 pw->pw_passwd)) {
106 errno = EACCES;
107 pw_error(NULL, 1, 1);
110 #ifdef LOGIN_CAP
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) {
117 time_t period;
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);
130 #endif
132 for (buf[0] = '\0', tries = 0;;) {
133 p = getpass("New password:");
134 if (!*p) {
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);
140 continue;
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");
147 continue;
150 (void)strcpy(buf, p);
151 if (!strcmp(buf, getpass("Retype new password:")))
152 break;
153 (void)printf("Mismatch; try again, EOF to quit.\n");
155 /* grab a random printable character that isn't a colon */
156 if (!randinit) {
157 randinit = 1;
158 srandomdev();
160 #ifdef NEWSALT
161 salt[0] = _PASSWORD_EFMT1;
162 to64(&salt[1], (long)(29 * 25), 4);
163 to64(&salt[5], random(), 4);
164 salt[9] = '\0';
165 #else
166 /* Make a good size salt for algoritms that can use it. */
167 gettimeofday(&tv,0);
168 #ifdef LOGIN_CAP
169 if (login_setcryptfmt(lc, "md5", NULL) == NULL)
170 pw_error("cannot set password cipher", 1, 1);
171 login_close(lc);
172 #else
173 (void)crypt_set_format("md5");
174 #endif
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);
183 salt[27] = '\0';
184 #endif
185 return (crypt(buf, salt));
189 local_passwd(char *uname)
191 struct passwd *pw;
192 int pfd, tfd;
194 if (!(pw = getpwnam(uname)))
195 errx(1, "unknown user %s", uname);
197 #ifdef YP
198 /* Use the right password information. */
199 pw = (struct passwd *)&local_password;
200 #endif
201 uid = getuid();
202 if (uid && uid != pw->pw_uid)
203 errx(1, "%s", strerror(EACCES));
205 pw_init();
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.
214 pw->pw_change = 0;
215 pw->pw_passwd = getnewpasswd(pw, 0);
217 pfd = pw_lock();
218 tfd = pw_tmp();
219 pw_copy(pfd, tfd, pw, NULL);
221 if (!pw_mkdb(uname))
222 pw_error((char *)NULL, 0, 1);
223 #ifdef LOGGING
224 syslog(LOG_DEBUG, "user %s changed their local password\n", uname);
225 #endif
226 return (0);