198514Sluigi/*- 298514Sluigi * Copyright (c) 1990, 1993, 1994 398514Sluigi * The Regents of the University of California. All rights reserved. 498514Sluigi * 598514Sluigi * Redistribution and use in source and binary forms, with or without 698514Sluigi * modification, are permitted provided that the following conditions 798514Sluigi * are met: 898514Sluigi * 1. Redistributions of source code must retain the above copyright 998514Sluigi * notice, this list of conditions and the following disclaimer. 1098514Sluigi * 2. Redistributions in binary form must reproduce the above copyright 1198514Sluigi * notice, this list of conditions and the following disclaimer in the 1298514Sluigi * documentation and/or other materials provided with the distribution. 1398514Sluigi * 3. All advertising materials mentioning features or use of this software 1498514Sluigi * must display the following acknowledgement: 1598514Sluigi * This product includes software developed by the University of 1698514Sluigi * California, Berkeley and its contributors. 1798514Sluigi * 4. Neither the name of the University nor the names of its contributors 1898514Sluigi * may be used to endorse or promote products derived from this software 1998514Sluigi * without specific prior written permission. 2098514Sluigi * 2198514Sluigi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2298514Sluigi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2398514Sluigi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2498514Sluigi * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2598514Sluigi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2698514Sluigi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2798514Sluigi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2898514Sluigi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2998514Sluigi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3098514Sluigi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3198514Sluigi * SUCH DAMAGE. 3298514Sluigi */ 3398514Sluigi 3498514Sluigi#ifndef lint 3598514Sluigistatic const char sccsid[] = "@(#)local_passwd.c 8.3 (Berkeley) 4/2/94"; 3698514Sluigi#endif /* not lint */ 3798514Sluigi 3898514Sluigi#include <sys/cdefs.h> 3998514Sluigi__FBSDID("$FreeBSD$"); 4098514Sluigi 4198514Sluigi#include <sys/types.h> 4298514Sluigi#include <sys/time.h> 4398514Sluigi 4498514Sluigi#include <ctype.h> 4598514Sluigi#include <err.h> 4698514Sluigi#include <errno.h> 4798514Sluigi#include <pwd.h> 4898514Sluigi#include <stdio.h> 4998514Sluigi#include <stdlib.h> 5098514Sluigi#include <string.h> 5198514Sluigi#include <time.h> 5298514Sluigi#include <unistd.h> 5398514Sluigi 5498514Sluigi#include <pw_util.h> 5598514Sluigi#ifdef YP 5698514Sluigi#include <pw_yp.h> 5798514Sluigi#endif 5898514Sluigi 5998514Sluigi#ifdef LOGGING 6098514Sluigi#include <syslog.h> 6198514Sluigi#endif 6298514Sluigi 6398514Sluigi#ifdef LOGIN_CAP 6498514Sluigi#ifdef AUTH_NONE /* multiple defs :-( */ 6598514Sluigi#undef AUTH_NONE 6698514Sluigi#endif 6798514Sluigi#include <login_cap.h> 6898514Sluigi#endif 6998514Sluigi 7098514Sluigi#include "extern.h" 7198514Sluigi 7298514Sluigistatic uid_t uid; 7398514Sluigiint randinit; 7498514Sluigi 7598514Sluigiextern void 7698514Sluigipw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw); 7798514Sluigi 7898514Sluigichar *tempname; 7998514Sluigi 8098514Sluigistatic unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ 8198514Sluigi "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 8298514Sluigi 8398514Sluigivoid 8498514Sluigito64(s, v, n) 8598514Sluigi char *s; 8698514Sluigi long v; 8798514Sluigi int n; 8898514Sluigi{ 8998514Sluigi while (--n >= 0) { 9098514Sluigi *s++ = itoa64[v&0x3f]; 9198514Sluigi v >>= 6; 9298514Sluigi } 9398514Sluigi} 9498514Sluigi 9598514Sluigichar * 9698514Sluigigetnewpasswd(pw, nis) 9798514Sluigi struct passwd *pw; 9898514Sluigi int nis; 9998514Sluigi{ 10098514Sluigi int tries, min_length = 6; 10198514Sluigi int force_mix_case = 1; 10298514Sluigi char *p, *t; 10398514Sluigi#ifdef LOGIN_CAP 10498514Sluigi login_cap_t * lc; 10598514Sluigi#endif 10698514Sluigi char buf[_PASSWORD_LEN+1], salt[32]; 10798514Sluigi struct timeval tv; 10898514Sluigi 10998514Sluigi if (!nis) 11098514Sluigi (void)printf("Changing local password for %s.\n", pw->pw_name); 11198514Sluigi 11298514Sluigi if (uid && pw->pw_passwd[0] && 11398514Sluigi strcmp(crypt(getpass("Old password:"), pw->pw_passwd), 11498514Sluigi pw->pw_passwd)) { 11598514Sluigi errno = EACCES; 11698514Sluigi pw_error(NULL, 1, 1); 11798514Sluigi } 11898514Sluigi 11998514Sluigi#ifdef LOGIN_CAP 12098514Sluigi /* 12198514Sluigi * Determine minimum password length, next password change date, 12298514Sluigi * and whether or not to force mixed case passwords. 12398514Sluigi * Note that even for NIS passwords, login_cap is still used. 12498514Sluigi */ 12598514Sluigi if ((lc = login_getpwclass(pw)) != NULL) { 12698514Sluigi time_t period; 12798514Sluigi 12898514Sluigi /* minpasswordlen capablity */ 12998514Sluigi min_length = (int)login_getcapnum(lc, "minpasswordlen", 13098514Sluigi min_length, min_length); 13198514Sluigi /* passwordtime capability */ 13298514Sluigi period = login_getcaptime(lc, "passwordtime", 0, 0); 13398514Sluigi if (period > (time_t)0) { 13498514Sluigi pw->pw_change = time(NULL) + period; 13598514Sluigi } 13698514Sluigi /* mixpasswordcase capability */ 13798514Sluigi force_mix_case = login_getcapbool(lc, "mixpasswordcase", 1); 13898514Sluigi } 13998514Sluigi#endif 14098514Sluigi 14198514Sluigi for (buf[0] = '\0', tries = 0;;) { 14298514Sluigi p = getpass("New password:"); 14398514Sluigi if (!*p) { 14498514Sluigi (void)printf("Password unchanged.\n"); 14598514Sluigi pw_error(NULL, 0, 0); 14698514Sluigi } 14798514Sluigi if (strlen(p) < min_length && (uid != 0 || ++tries < 2)) { 14898514Sluigi (void)printf("Please enter a password at least %d characters in length.\n", min_length); 14998514Sluigi continue; 15098514Sluigi } 15198514Sluigi 15298514Sluigi if (force_mix_case) { 15398514Sluigi for (t = p; *t && islower(*t); ++t); 15498514Sluigi if (!*t && (uid != 0 || ++tries < 2)) { 15598514Sluigi (void)printf("Please don't use an all-lower case password.\nUnusual capitalization, control characters or digits are suggested.\n"); 15698514Sluigi continue; 15798514Sluigi } 15898514Sluigi } 15998514Sluigi (void)strcpy(buf, p); 16098514Sluigi if (!strcmp(buf, getpass("Retype new password:"))) 16198514Sluigi break; 16298514Sluigi (void)printf("Mismatch; try again, EOF to quit.\n"); 16398514Sluigi } 16498514Sluigi /* grab a random printable character that isn't a colon */ 16598514Sluigi if (!randinit) { 16698514Sluigi randinit = 1; 16798514Sluigi srandomdev(); 16898514Sluigi } 16998514Sluigi#ifdef NEWSALT 17098514Sluigi salt[0] = _PASSWORD_EFMT1; 17198514Sluigi to64(&salt[1], (long)(29 * 25), 4); 17298514Sluigi to64(&salt[5], random(), 4); 17398514Sluigi salt[9] = '\0'; 17498514Sluigi#else 175229779Suqs /* Make a good size salt for algorithms that can use it. */ 17698514Sluigi gettimeofday(&tv,0); 17798514Sluigi#ifdef LOGIN_CAP 17898514Sluigi if (login_setcryptfmt(lc, "md5", NULL) == NULL) 17998514Sluigi pw_error("cannot set password cipher", 1, 1); 18098514Sluigi login_close(lc); 18198514Sluigi#else 18298514Sluigi (void)crypt_set_format("md5"); 18398514Sluigi#endif 18498514Sluigi /* Salt suitable for anything */ 18598514Sluigi to64(&salt[0], random(), 3); 18698514Sluigi to64(&salt[3], tv.tv_usec, 3); 18798514Sluigi to64(&salt[6], tv.tv_sec, 2); 18898514Sluigi to64(&salt[8], random(), 5); 18998514Sluigi to64(&salt[13], random(), 5); 19098514Sluigi to64(&salt[17], random(), 5); 19198514Sluigi to64(&salt[22], random(), 5); 19298514Sluigi salt[27] = '\0'; 19398514Sluigi#endif 19498514Sluigi return (crypt(buf, salt)); 19598514Sluigi} 19698514Sluigi 19798514Sluigiint 19898514Sluigilocal_passwd(uname) 19998514Sluigi char *uname; 20098514Sluigi{ 20198514Sluigi struct passwd *pw; 20298514Sluigi int pfd, tfd; 20398514Sluigi 20498514Sluigi if (!(pw = getpwnam(uname))) 20598514Sluigi errx(1, "unknown user %s", uname); 20698514Sluigi 20798514Sluigi#ifdef YP 20898514Sluigi /* Use the right password information. */ 20998514Sluigi pw = (struct passwd *)&local_password; 21098514Sluigi#endif 21198514Sluigi uid = getuid(); 21298514Sluigi if (uid && uid != pw->pw_uid) 21398514Sluigi errx(1, "%s", strerror(EACCES)); 21498514Sluigi 21598514Sluigi pw_init(); 21698514Sluigi 21798514Sluigi /* 21898514Sluigi * Get the new password. Reset passwd change time to zero by 21998514Sluigi * default. If the user has a valid login class (or the default 22098514Sluigi * fallback exists), then the next password change date is set 22198514Sluigi * by getnewpasswd() according to the "passwordtime" capability 22298514Sluigi * if one has been specified. 22398514Sluigi */ 22498514Sluigi pw->pw_change = 0; 22598514Sluigi pw->pw_passwd = getnewpasswd(pw, 0); 22698514Sluigi 22798514Sluigi pfd = pw_lock(); 22898514Sluigi tfd = pw_tmp(); 22998514Sluigi pw_copy(pfd, tfd, pw, NULL); 23098514Sluigi 23198514Sluigi if (!pw_mkdb(uname)) 23298514Sluigi pw_error((char *)NULL, 0, 1); 23398514Sluigi#ifdef LOGGING 23498514Sluigi syslog(LOG_DEBUG, "user %s changed their local password\n", uname); 23598514Sluigi#endif 23698514Sluigi return (0); 23798514Sluigi} 238