128021Sjoerg/*- 228021Sjoerg * Copyright (c) 1990, 1993, 1994 328021Sjoerg * The Regents of the University of California. All rights reserved. 428021Sjoerg * 528021Sjoerg * Redistribution and use in source and binary forms, with or without 628021Sjoerg * modification, are permitted provided that the following conditions 728021Sjoerg * are met: 828021Sjoerg * 1. Redistributions of source code must retain the above copyright 928021Sjoerg * notice, this list of conditions and the following disclaimer. 1028021Sjoerg * 2. Redistributions in binary form must reproduce the above copyright 1128021Sjoerg * notice, this list of conditions and the following disclaimer in the 1228021Sjoerg * documentation and/or other materials provided with the distribution. 1328021Sjoerg * 3. All advertising materials mentioning features or use of this software 1428021Sjoerg * must display the following acknowledgement: 1528021Sjoerg * This product includes software developed by the University of 1628021Sjoerg * California, Berkeley and its contributors. 1728021Sjoerg * 4. Neither the name of the University nor the names of its contributors 1828021Sjoerg * may be used to endorse or promote products derived from this software 1928021Sjoerg * without specific prior written permission. 2028021Sjoerg * 2128021Sjoerg * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2228021Sjoerg * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2328021Sjoerg * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2428021Sjoerg * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2528021Sjoerg * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2650476Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2728021Sjoerg * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2828021Sjoerg * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2928021Sjoerg * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3028021Sjoerg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3128021Sjoerg * SUCH DAMAGE. 3228021Sjoerg */ 3328021Sjoerg 3428021Sjoerg#ifndef lint 3528021Sjoergstatic const char sccsid[] = "@(#)local_passwd.c 8.3 (Berkeley) 4/2/94"; 3628021Sjoerg#endif /* not lint */ 3728021Sjoerg 3828021Sjoerg#include <sys/cdefs.h> 3928021Sjoerg__FBSDID("$FreeBSD$"); 4028021Sjoerg 4128021Sjoerg#include <sys/types.h> 4228021Sjoerg#include <sys/time.h> 4328021Sjoerg 4428021Sjoerg#include <ctype.h> 4528021Sjoerg#include <err.h> 4628021Sjoerg#include <errno.h> 4728021Sjoerg#include <pwd.h> 4828021Sjoerg#include <stdio.h> 4928021Sjoerg#include <stdlib.h> 5028021Sjoerg#include <string.h> 5128021Sjoerg#include <time.h> 5228021Sjoerg#include <unistd.h> 5328021Sjoerg 5428021Sjoerg#include <pw_util.h> 5528021Sjoerg#ifdef YP 5628021Sjoerg#include <pw_yp.h> 5728021Sjoerg#endif 5828021Sjoerg 5928021Sjoerg#ifdef LOGGING 6028021Sjoerg#include <syslog.h> 6128021Sjoerg#endif 6228021Sjoerg 6328021Sjoerg#ifdef LOGIN_CAP 6428021Sjoerg#ifdef AUTH_NONE /* multiple defs :-( */ 6528021Sjoerg#undef AUTH_NONE 6628021Sjoerg#endif 6728021Sjoerg#include <login_cap.h> 6828021Sjoerg#endif 6928021Sjoerg 7028021Sjoerg#include "extern.h" 7128021Sjoerg 7228021Sjoergstatic uid_t uid; 7328021Sjoergint randinit; 7428021Sjoerg 7528021Sjoergextern void 7628021Sjoergpw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw); 7728021Sjoerg 7828021Sjoergchar *tempname; 7928021Sjoerg 8028021Sjoergstatic unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 8128021Sjoerg "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 8228021Sjoerg 8328021Sjoergvoid 8428021Sjoergto64(s, v, n) 8528021Sjoerg char *s; 8628021Sjoerg long v; 8728021Sjoerg int n; 8828021Sjoerg{ 8928021Sjoerg while (--n >= 0) { 9028021Sjoerg *s++ = itoa64[v&0x3f]; 9128021Sjoerg v >>= 6; 9228021Sjoerg } 9328021Sjoerg} 9428021Sjoerg 9528021Sjoergchar * 9628021Sjoerggetnewpasswd(pw, nis) 9728021Sjoerg struct passwd *pw; 9828021Sjoerg int nis; 9928021Sjoerg{ 10028021Sjoerg int tries, min_length = 6; 10128021Sjoerg int force_mix_case = 1; 10228021Sjoerg char *p, *t; 10328021Sjoerg#ifdef LOGIN_CAP 10428021Sjoerg login_cap_t * lc; 10528021Sjoerg#endif 10628021Sjoerg char buf[_PASSWORD_LEN+1], salt[32]; 10728021Sjoerg struct timeval tv; 10828021Sjoerg 10928021Sjoerg if (!nis) 11028021Sjoerg (void)printf("Changing local password for %s.\n", pw->pw_name); 11128021Sjoerg 11228021Sjoerg if (uid && pw->pw_passwd[0] && 11328021Sjoerg strcmp(crypt(getpass("Old password:"), pw->pw_passwd), 11428021Sjoerg pw->pw_passwd)) { 11528021Sjoerg errno = EACCES; 11628021Sjoerg pw_error(NULL, 1, 1); 11728021Sjoerg } 11828021Sjoerg 11928021Sjoerg#ifdef LOGIN_CAP 12028021Sjoerg /* 12128021Sjoerg * Determine minimum password length, next password change date, 12228021Sjoerg * and whether or not to force mixed case passwords. 12328021Sjoerg * Note that even for NIS passwords, login_cap is still used. 12428021Sjoerg */ 12528021Sjoerg if ((lc = login_getpwclass(pw)) != NULL) { 12628021Sjoerg time_t period; 12728021Sjoerg 12828021Sjoerg /* minpasswordlen capablity */ 12928021Sjoerg min_length = (int)login_getcapnum(lc, "minpasswordlen", 13028021Sjoerg min_length, min_length); 13128021Sjoerg /* passwordtime capability */ 13228021Sjoerg period = login_getcaptime(lc, "passwordtime", 0, 0); 13328021Sjoerg if (period > (time_t)0) { 13428021Sjoerg pw->pw_change = time(NULL) + period; 13528021Sjoerg } 13628021Sjoerg /* mixpasswordcase capability */ 13728021Sjoerg force_mix_case = login_getcapbool(lc, "mixpasswordcase", 1); 13828021Sjoerg } 13928021Sjoerg#endif 14028021Sjoerg 14128021Sjoerg for (buf[0] = '\0', tries = 0;;) { 14228021Sjoerg p = getpass("New password:"); 14328021Sjoerg if (!*p) { 14428021Sjoerg (void)printf("Password unchanged.\n"); 14528021Sjoerg pw_error(NULL, 0, 0); 14628021Sjoerg } 14728021Sjoerg if (strlen(p) < min_length && (uid != 0 || ++tries < 2)) { 14828021Sjoerg (void)printf("Please enter a password at least %d characters in length.\n", min_length); 14939327Simp continue; 15028021Sjoerg } 15128021Sjoerg 15228021Sjoerg if (force_mix_case) { 15328021Sjoerg for (t = p; *t && islower(*t); ++t); 15428021Sjoerg if (!*t && (uid != 0 || ++tries < 2)) { 15528021Sjoerg (void)printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n"); 15628021Sjoerg continue; 15728021Sjoerg } 15828021Sjoerg } 15928021Sjoerg (void)strcpy(buf, p); 16028021Sjoerg if (!strcmp(buf, getpass("Retype new password:"))) 16128021Sjoerg break; 16228021Sjoerg (void)printf("Mismatch; try again, EOF to quit.\n"); 16328021Sjoerg } 16428021Sjoerg /* grab a random printable character that isn't a colon */ 16528021Sjoerg if (!randinit) { 16628021Sjoerg randinit = 1; 16728021Sjoerg srandomdev(); 16828021Sjoerg } 16928021Sjoerg#ifdef NEWSALT 17028021Sjoerg salt[0] = _PASSWORD_EFMT1; 17128021Sjoerg to64(&salt[1], (long)(29 * 25), 4); 17228021Sjoerg to64(&salt[5], random(), 4); 17328021Sjoerg salt[9] = '\0'; 17428021Sjoerg#else 17528021Sjoerg /* Make a good size salt for algorithms that can use it. */ 17628021Sjoerg gettimeofday(&tv,0); 17728021Sjoerg#ifdef LOGIN_CAP 17828021Sjoerg if (login_setcryptfmt(lc, "md5", NULL) == NULL) 17928021Sjoerg pw_error("cannot set password cipher", 1, 1); 18028021Sjoerg login_close(lc); 18128021Sjoerg#else 18228021Sjoerg (void)crypt_set_format("md5"); 18328021Sjoerg#endif 18428021Sjoerg /* Salt suitable for anything */ 18528021Sjoerg to64(&salt[0], random(), 3); 18628021Sjoerg to64(&salt[3], tv.tv_usec, 3); 18728021Sjoerg to64(&salt[6], tv.tv_sec, 2); 18828021Sjoerg to64(&salt[8], random(), 5); 18928021Sjoerg to64(&salt[13], random(), 5); 19028021Sjoerg to64(&salt[17], random(), 5); 19128021Sjoerg to64(&salt[22], random(), 5); 19228021Sjoerg salt[27] = '\0'; 19328021Sjoerg#endif 19428021Sjoerg return (crypt(buf, salt)); 19528021Sjoerg} 19628021Sjoerg 19728021Sjoergint 198local_passwd(uname) 199 char *uname; 200{ 201 struct passwd *pw; 202 int pfd, tfd; 203 204 if (!(pw = getpwnam(uname))) 205 errx(1, "unknown user %s", uname); 206 207#ifdef YP 208 /* Use the right password information. */ 209 pw = (struct passwd *)&local_password; 210#endif 211 uid = getuid(); 212 if (uid && uid != pw->pw_uid) 213 errx(1, "%s", strerror(EACCES)); 214 215 pw_init(); 216 217 /* 218 * Get the new password. Reset passwd change time to zero by 219 * default. If the user has a valid login class (or the default 220 * fallback exists), then the next password change date is set 221 * by getnewpasswd() according to the "passwordtime" capability 222 * if one has been specified. 223 */ 224 pw->pw_change = 0; 225 pw->pw_passwd = getnewpasswd(pw, 0); 226 227 pfd = pw_lock(); 228 tfd = pw_tmp(); 229 pw_copy(pfd, tfd, pw, NULL); 230 231 if (!pw_mkdb(uname)) 232 pw_error((char *)NULL, 0, 1); 233#ifdef LOGGING 234 syslog(LOG_DEBUG, "user %s changed their local password\n", uname); 235#endif 236 return (0); 237} 238