local_passwd.c revision 330897
1/*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1990, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#ifndef lint 37static const char sccsid[] = "@(#)local_passwd.c 8.3 (Berkeley) 4/2/94"; 38#endif /* not lint */ 39 40#include <sys/cdefs.h> 41__FBSDID("$FreeBSD: stable/11/release/picobsd/tinyware/passwd/local_passwd.c 330897 2018-03-14 03:19:51Z eadler $"); 42 43#include <sys/types.h> 44#include <sys/time.h> 45 46#include <ctype.h> 47#include <err.h> 48#include <errno.h> 49#include <pwd.h> 50#include <stdio.h> 51#include <stdlib.h> 52#include <string.h> 53#include <time.h> 54#include <unistd.h> 55 56#include <pw_util.h> 57#ifdef YP 58#include <pw_yp.h> 59#endif 60 61#ifdef LOGGING 62#include <syslog.h> 63#endif 64 65#ifdef LOGIN_CAP 66#ifdef AUTH_NONE /* multiple defs :-( */ 67#undef AUTH_NONE 68#endif 69#include <login_cap.h> 70#endif 71 72#include "extern.h" 73 74static uid_t uid; 75int randinit; 76 77extern void 78pw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw); 79 80char *tempname; 81 82static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 83 "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 84 85void 86to64(s, v, n) 87 char *s; 88 long v; 89 int n; 90{ 91 while (--n >= 0) { 92 *s++ = itoa64[v&0x3f]; 93 v >>= 6; 94 } 95} 96 97char * 98getnewpasswd(pw, nis) 99 struct passwd *pw; 100 int nis; 101{ 102 int tries, min_length = 6; 103 int force_mix_case = 1; 104 char *p, *t; 105#ifdef LOGIN_CAP 106 login_cap_t * lc; 107#endif 108 char buf[_PASSWORD_LEN+1], salt[32]; 109 struct timeval tv; 110 111 if (!nis) 112 (void)printf("Changing local password for %s.\n", pw->pw_name); 113 114 if (uid && pw->pw_passwd[0] && 115 strcmp(crypt(getpass("Old password:"), pw->pw_passwd), 116 pw->pw_passwd)) { 117 errno = EACCES; 118 pw_error(NULL, 1, 1); 119 } 120 121#ifdef LOGIN_CAP 122 /* 123 * Determine minimum password length, next password change date, 124 * and whether or not to force mixed case passwords. 125 * Note that even for NIS passwords, login_cap is still used. 126 */ 127 if ((lc = login_getpwclass(pw)) != NULL) { 128 time_t period; 129 130 /* minpasswordlen capablity */ 131 min_length = (int)login_getcapnum(lc, "minpasswordlen", 132 min_length, min_length); 133 /* passwordtime capability */ 134 period = login_getcaptime(lc, "passwordtime", 0, 0); 135 if (period > (time_t)0) { 136 pw->pw_change = time(NULL) + period; 137 } 138 /* mixpasswordcase capability */ 139 force_mix_case = login_getcapbool(lc, "mixpasswordcase", 1); 140 } 141#endif 142 143 for (buf[0] = '\0', tries = 0;;) { 144 p = getpass("New password:"); 145 if (!*p) { 146 (void)printf("Password unchanged.\n"); 147 pw_error(NULL, 0, 0); 148 } 149 if (strlen(p) < min_length && (uid != 0 || ++tries < 2)) { 150 (void)printf("Please enter a password at least %d characters in length.\n", min_length); 151 continue; 152 } 153 154 if (force_mix_case) { 155 for (t = p; *t && islower(*t); ++t); 156 if (!*t && (uid != 0 || ++tries < 2)) { 157 (void)printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n"); 158 continue; 159 } 160 } 161 (void)strcpy(buf, p); 162 if (!strcmp(buf, getpass("Retype new password:"))) 163 break; 164 (void)printf("Mismatch; try again, EOF to quit.\n"); 165 } 166 /* grab a random printable character that isn't a colon */ 167 if (!randinit) { 168 randinit = 1; 169 srandomdev(); 170 } 171#ifdef NEWSALT 172 salt[0] = _PASSWORD_EFMT1; 173 to64(&salt[1], (long)(29 * 25), 4); 174 to64(&salt[5], random(), 4); 175 salt[9] = '\0'; 176#else 177 /* Make a good size salt for algorithms that can use it. */ 178 gettimeofday(&tv,0); 179#ifdef LOGIN_CAP 180 if (login_setcryptfmt(lc, "md5", NULL) == NULL) 181 pw_error("cannot set password cipher", 1, 1); 182 login_close(lc); 183#else 184 (void)crypt_set_format("md5"); 185#endif 186 /* Salt suitable for anything */ 187 to64(&salt[0], random(), 3); 188 to64(&salt[3], tv.tv_usec, 3); 189 to64(&salt[6], tv.tv_sec, 2); 190 to64(&salt[8], random(), 5); 191 to64(&salt[13], random(), 5); 192 to64(&salt[17], random(), 5); 193 to64(&salt[22], random(), 5); 194 salt[27] = '\0'; 195#endif 196 return (crypt(buf, salt)); 197} 198 199int 200local_passwd(uname) 201 char *uname; 202{ 203 struct passwd *pw; 204 int pfd, tfd; 205 206 if (!(pw = getpwnam(uname))) 207 errx(1, "unknown user %s", uname); 208 209#ifdef YP 210 /* Use the right password information. */ 211 pw = (struct passwd *)&local_password; 212#endif 213 uid = getuid(); 214 if (uid && uid != pw->pw_uid) 215 errx(1, "%s", strerror(EACCES)); 216 217 pw_init(); 218 219 /* 220 * Get the new password. Reset passwd change time to zero by 221 * default. If the user has a valid login class (or the default 222 * fallback exists), then the next password change date is set 223 * by getnewpasswd() according to the "passwordtime" capability 224 * if one has been specified. 225 */ 226 pw->pw_change = 0; 227 pw->pw_passwd = getnewpasswd(pw, 0); 228 229 pfd = pw_lock(); 230 tfd = pw_tmp(); 231 pw_copy(pfd, tfd, pw, NULL); 232 233 if (!pw_mkdb(uname)) 234 pw_error((char *)NULL, 0, 1); 235#ifdef LOGGING 236 syslog(LOG_DEBUG, "user %s changed their local password\n", uname); 237#endif 238 return (0); 239} 240