19b50d902SRodney W. Grimes /*- 29b50d902SRodney W. Grimes * Copyright (c) 1988, 1993, 1994 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 4f1d05925SDag-Erling Smørgrav * Copyright (c) 2002 Networks Associates Technology, Inc. 5f1d05925SDag-Erling Smørgrav * All rights reserved. 6f1d05925SDag-Erling Smørgrav * 7f1d05925SDag-Erling Smørgrav * Portions of this software were developed for the FreeBSD Project by 8f1d05925SDag-Erling Smørgrav * ThinkSec AS and NAI Labs, the Security Research Division of Network 9f1d05925SDag-Erling Smørgrav * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 10f1d05925SDag-Erling Smørgrav * ("CBOSS"), as part of the DARPA CHATS research program. 119b50d902SRodney W. Grimes * 129b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 139b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 149b50d902SRodney W. Grimes * are met: 159b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 169b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 179b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 189b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 199b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 209b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 219b50d902SRodney W. Grimes * must display the following acknowledgement: 229b50d902SRodney W. Grimes * This product includes software developed by the University of 239b50d902SRodney W. Grimes * California, Berkeley and its contributors. 249b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 259b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 269b50d902SRodney W. Grimes * without specific prior written permission. 279b50d902SRodney W. Grimes * 289b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 299b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 309b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 319b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 329b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 339b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 349b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 359b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 369b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 379b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 389b50d902SRodney W. Grimes * SUCH DAMAGE. 399b50d902SRodney W. Grimes */ 409b50d902SRodney W. Grimes 41ebe901b4SDavid E. O'Brien #if 0 429b50d902SRodney W. Grimes #ifndef lint 43fa146c53SArchie Cobbs static const char copyright[] = 449b50d902SRodney W. Grimes "@(#) Copyright (c) 1988, 1993, 1994\n\ 459b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 469b50d902SRodney W. Grimes #endif /* not lint */ 479b50d902SRodney W. Grimes 489b50d902SRodney W. Grimes #ifndef lint 494d09bd65SDavid Malone static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94"; 509b50d902SRodney W. Grimes #endif /* not lint */ 514d09bd65SDavid Malone #endif 525ea73378SMark Murray #include <sys/cdefs.h> 535ea73378SMark Murray __FBSDID("$FreeBSD$"); 545ea73378SMark Murray 559b50d902SRodney W. Grimes #include <sys/param.h> 569b50d902SRodney W. Grimes 579b50d902SRodney W. Grimes #include <err.h> 589b50d902SRodney W. Grimes #include <errno.h> 599b50d902SRodney W. Grimes #include <pwd.h> 609b50d902SRodney W. Grimes #include <stdio.h> 619b50d902SRodney W. Grimes #include <stdlib.h> 629b50d902SRodney W. Grimes #include <string.h> 639b50d902SRodney W. Grimes #include <unistd.h> 6436715722SBill Paul #ifdef YP 65f1d05925SDag-Erling Smørgrav #include <ypclnt.h> 6636715722SBill Paul #endif 679b50d902SRodney W. Grimes 68f1d05925SDag-Erling Smørgrav #include <pw_scan.h> 69f1d05925SDag-Erling Smørgrav #include <libutil.h> 70f1d05925SDag-Erling Smørgrav 719b50d902SRodney W. Grimes #include "chpass.h" 729b50d902SRodney W. Grimes 73f1d05925SDag-Erling Smørgrav int master_mode; 749b50d902SRodney W. Grimes 75f1d05925SDag-Erling Smørgrav static void baduser(void); 76f1d05925SDag-Erling Smørgrav static void usage(void); 779b50d902SRodney W. Grimes 789b50d902SRodney W. Grimes int 795ea73378SMark Murray main(int argc, char *argv[]) 809b50d902SRodney W. Grimes { 81366982a5SPeter Wemm enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op; 8224c05aeeSDavid E. O'Brien struct passwd lpw, *old_pw, *pw; 839b50d902SRodney W. Grimes int ch, pfd, tfd; 84f1d05925SDag-Erling Smørgrav const char *password; 85fa146c53SArchie Cobbs char *arg = NULL; 86f1d05925SDag-Erling Smørgrav uid_t uid; 8792194236SBill Paul #ifdef YP 88f1d05925SDag-Erling Smørgrav struct ypclnt *ypclnt; 89f1d05925SDag-Erling Smørgrav const char *yp_domain = NULL, *yp_host = NULL; 9092194236SBill Paul #endif 919b50d902SRodney W. Grimes 9224c05aeeSDavid E. O'Brien pw = old_pw = NULL; 939b50d902SRodney W. Grimes op = EDITENTRY; 9492194236SBill Paul #ifdef YP 95f1d05925SDag-Erling Smørgrav while ((ch = getopt(argc, argv, "a:p:s:e:d:h:loy")) != -1) 9692194236SBill Paul #else 971c8af878SWarner Losh while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1) 9892194236SBill Paul #endif 999b50d902SRodney W. Grimes switch (ch) { 1009b50d902SRodney W. Grimes case 'a': 1019b50d902SRodney W. Grimes op = LOADENTRY; 1029b50d902SRodney W. Grimes arg = optarg; 1039b50d902SRodney W. Grimes break; 1049b50d902SRodney W. Grimes case 's': 1059b50d902SRodney W. Grimes op = NEWSH; 1069b50d902SRodney W. Grimes arg = optarg; 1079b50d902SRodney W. Grimes break; 1080e10ef2eSGarrett Wollman case 'p': 1090e10ef2eSGarrett Wollman op = NEWPW; 1100e10ef2eSGarrett Wollman arg = optarg; 1110e10ef2eSGarrett Wollman break; 112366982a5SPeter Wemm case 'e': 113366982a5SPeter Wemm op = NEWEXP; 114366982a5SPeter Wemm arg = optarg; 115366982a5SPeter Wemm break; 11692194236SBill Paul #ifdef YP 117c2dfe9feSBill Paul case 'd': 118c2dfe9feSBill Paul yp_domain = optarg; 119f1d05925SDag-Erling Smørgrav break; 120f1d05925SDag-Erling Smørgrav case 'h': 121f1d05925SDag-Erling Smørgrav yp_host = optarg; 122c2dfe9feSBill Paul break; 12392194236SBill Paul case 'l': 124c2dfe9feSBill Paul case 'o': 125f1d05925SDag-Erling Smørgrav case 'y': 126f1d05925SDag-Erling Smørgrav /* compatibility */ 12792194236SBill Paul break; 12892194236SBill Paul #endif 1299b50d902SRodney W. Grimes case '?': 1309b50d902SRodney W. Grimes default: 1319b50d902SRodney W. Grimes usage(); 1329b50d902SRodney W. Grimes } 133f1d05925SDag-Erling Smørgrav 1349b50d902SRodney W. Grimes argc -= optind; 1359b50d902SRodney W. Grimes argv += optind; 1369b50d902SRodney W. Grimes 137f1d05925SDag-Erling Smørgrav if (argc > 1) 138f1d05925SDag-Erling Smørgrav usage(); 139f1d05925SDag-Erling Smørgrav 1409b50d902SRodney W. Grimes uid = getuid(); 1419b50d902SRodney W. Grimes 1428c44e779SCrist J. Clark if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) { 143f1d05925SDag-Erling Smørgrav if (argc == 0) { 144f1d05925SDag-Erling Smørgrav if ((pw = getpwuid(uid)) == NULL) 145f458f48bSMike Barcroft errx(1, "unknown user: uid %lu", 146f458f48bSMike Barcroft (unsigned long)uid); 147f1d05925SDag-Erling Smørgrav } else { 148f1d05925SDag-Erling Smørgrav if ((pw = getpwnam(*argv)) == NULL) 1499b50d902SRodney W. Grimes errx(1, "unknown user: %s", *argv); 150f1d05925SDag-Erling Smørgrav if (uid != 0 && uid != pw->pw_uid) 1519b50d902SRodney W. Grimes baduser(); 1529b50d902SRodney W. Grimes } 1538c44e779SCrist J. Clark 1548c44e779SCrist J. Clark /* Make a copy for later verification */ 155f1d05925SDag-Erling Smørgrav if ((pw = pw_dup(pw)) == NULL || 156f1d05925SDag-Erling Smørgrav (old_pw = pw_dup(pw)) == NULL) 157f1d05925SDag-Erling Smørgrav err(1, "pw_dup"); 1588c44e779SCrist J. Clark } 1598c44e779SCrist J. Clark 160f1d05925SDag-Erling Smørgrav #ifdef YP 1616aa4e03fSJoerg Wunsch if (pw != NULL && (pw->pw_fields & _PWF_SOURCE) == _PWF_NIS) { 162f1d05925SDag-Erling Smørgrav ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host); 163f1d05925SDag-Erling Smørgrav master_mode = (ypclnt != NULL && 164f1d05925SDag-Erling Smørgrav ypclnt_connect(ypclnt) != -1 && 165f1d05925SDag-Erling Smørgrav ypclnt_havepasswdd(ypclnt) == 1); 166f1d05925SDag-Erling Smørgrav ypclnt_free(ypclnt); 167f1d05925SDag-Erling Smørgrav } else 168f1d05925SDag-Erling Smørgrav #endif 169f1d05925SDag-Erling Smørgrav master_mode = (uid == 0); 170f1d05925SDag-Erling Smørgrav 171049ceb63SJoerg Wunsch if (op == NEWSH) { 172049ceb63SJoerg Wunsch /* protect p_shell -- it thinks NULL is /bin/sh */ 173049ceb63SJoerg Wunsch if (!arg[0]) 174049ceb63SJoerg Wunsch usage(); 175f1d05925SDag-Erling Smørgrav if (p_shell(arg, pw, (ENTRY *)NULL) == -1) 176f1d05925SDag-Erling Smørgrav exit(1); 177049ceb63SJoerg Wunsch } 178049ceb63SJoerg Wunsch 179366982a5SPeter Wemm if (op == NEWEXP) { 180366982a5SPeter Wemm if (uid) /* only root can change expire */ 181366982a5SPeter Wemm baduser(); 182f1d05925SDag-Erling Smørgrav if (p_expire(arg, pw, (ENTRY *)NULL) == -1) 183f1d05925SDag-Erling Smørgrav exit(1); 184366982a5SPeter Wemm } 185366982a5SPeter Wemm 186049ceb63SJoerg Wunsch if (op == LOADENTRY) { 187049ceb63SJoerg Wunsch if (uid) 188049ceb63SJoerg Wunsch baduser(); 189049ceb63SJoerg Wunsch pw = &lpw; 190f1d05925SDag-Erling Smørgrav old_pw = NULL; 191248aee62SJacques Vidrine if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) 192049ceb63SJoerg Wunsch exit(1); 193049ceb63SJoerg Wunsch } 194049ceb63SJoerg Wunsch 195049ceb63SJoerg Wunsch if (op == NEWPW) { 196049ceb63SJoerg Wunsch if (uid) 197049ceb63SJoerg Wunsch baduser(); 198049ceb63SJoerg Wunsch 199f1d05925SDag-Erling Smørgrav if (strchr(arg, ':')) 200049ceb63SJoerg Wunsch errx(1, "invalid format for password"); 201049ceb63SJoerg Wunsch pw->pw_passwd = arg; 202049ceb63SJoerg Wunsch } 203049ceb63SJoerg Wunsch 2049b50d902SRodney W. Grimes if (op == EDITENTRY) { 205f1d05925SDag-Erling Smørgrav /* 206f1d05925SDag-Erling Smørgrav * We don't really need pw_*() here, but pw_edit() (used 207f1d05925SDag-Erling Smørgrav * by edit()) is just too useful... 208f1d05925SDag-Erling Smørgrav */ 209f1d05925SDag-Erling Smørgrav if (pw_init(NULL, NULL)) 210f1d05925SDag-Erling Smørgrav err(1, "pw_init()"); 211f1d05925SDag-Erling Smørgrav if ((tfd = pw_tmp(-1)) == -1) { 212f1d05925SDag-Erling Smørgrav pw_fini(); 213f1d05925SDag-Erling Smørgrav err(1, "pw_tmp()"); 214f1d05925SDag-Erling Smørgrav } 215f1d05925SDag-Erling Smørgrav free(pw); 216f1d05925SDag-Erling Smørgrav pw = edit(pw_tempname(), old_pw); 217f1d05925SDag-Erling Smørgrav pw_fini(); 218f1d05925SDag-Erling Smørgrav if (pw == NULL) 219f1d05925SDag-Erling Smørgrav err(1, "edit()"); 22050789a2fSDmitry Morozovsky /* 22150789a2fSDmitry Morozovsky * pw_equal does not check for crypted passwords, so we 22250789a2fSDmitry Morozovsky * should do it explicitly 22350789a2fSDmitry Morozovsky */ 22450789a2fSDmitry Morozovsky if (pw_equal(old_pw, pw) && 22550789a2fSDmitry Morozovsky strcmp(old_pw->pw_passwd, pw->pw_passwd) == 0) 226f1d05925SDag-Erling Smørgrav errx(0, "user information unchanged"); 2279b50d902SRodney W. Grimes } 2289b50d902SRodney W. Grimes 229f1d05925SDag-Erling Smørgrav if (old_pw && !master_mode) { 230f1d05925SDag-Erling Smørgrav password = getpass("Password: "); 231f1d05925SDag-Erling Smørgrav if (strcmp(crypt(password, old_pw->pw_passwd), 232f1d05925SDag-Erling Smørgrav old_pw->pw_passwd) != 0) 233f1d05925SDag-Erling Smørgrav baduser(); 23436715722SBill Paul } else { 235f1d05925SDag-Erling Smørgrav password = ""; 236f1d05925SDag-Erling Smørgrav } 2379b50d902SRodney W. Grimes 238f1d05925SDag-Erling Smørgrav if (old_pw != NULL) 239f1d05925SDag-Erling Smørgrav pw->pw_fields |= (old_pw->pw_fields & _PWF_SOURCE); 240f1d05925SDag-Erling Smørgrav switch (pw->pw_fields & _PWF_SOURCE) { 24136715722SBill Paul #ifdef YP 242f1d05925SDag-Erling Smørgrav case _PWF_NIS: 243f1d05925SDag-Erling Smørgrav ypclnt = ypclnt_new(yp_domain, "passwd.byname", yp_host); 244f1d05925SDag-Erling Smørgrav if (ypclnt == NULL || 245f1d05925SDag-Erling Smørgrav ypclnt_connect(ypclnt) == -1 || 246f1d05925SDag-Erling Smørgrav ypclnt_passwd(ypclnt, pw, password) == -1) { 247f1d05925SDag-Erling Smørgrav warnx("%s", ypclnt->error); 248f1d05925SDag-Erling Smørgrav ypclnt_free(ypclnt); 249f1d05925SDag-Erling Smørgrav exit(1); 25036715722SBill Paul } 251f1d05925SDag-Erling Smørgrav ypclnt_free(ypclnt); 252f1d05925SDag-Erling Smørgrav errx(0, "NIS user information updated"); 25336715722SBill Paul #endif /* YP */ 254f1d05925SDag-Erling Smørgrav case 0: 255f1d05925SDag-Erling Smørgrav case _PWF_FILES: 256f1d05925SDag-Erling Smørgrav if (pw_init(NULL, NULL)) 257f1d05925SDag-Erling Smørgrav err(1, "pw_init()"); 258f1d05925SDag-Erling Smørgrav if ((pfd = pw_lock()) == -1) { 259f1d05925SDag-Erling Smørgrav pw_fini(); 260f1d05925SDag-Erling Smørgrav err(1, "pw_lock()"); 261f1d05925SDag-Erling Smørgrav } 262f1d05925SDag-Erling Smørgrav if ((tfd = pw_tmp(-1)) == -1) { 263f1d05925SDag-Erling Smørgrav pw_fini(); 264f1d05925SDag-Erling Smørgrav err(1, "pw_tmp()"); 265f1d05925SDag-Erling Smørgrav } 266f1d05925SDag-Erling Smørgrav if (pw_copy(pfd, tfd, pw, old_pw) == -1) { 267f1d05925SDag-Erling Smørgrav pw_fini(); 268f1d05925SDag-Erling Smørgrav err(1, "pw_copy"); 269f1d05925SDag-Erling Smørgrav } 270f1d05925SDag-Erling Smørgrav if (pw_mkdb(pw->pw_name) == -1) { 271f1d05925SDag-Erling Smørgrav pw_fini(); 272f1d05925SDag-Erling Smørgrav err(1, "pw_mkdb()"); 273f1d05925SDag-Erling Smørgrav } 274f1d05925SDag-Erling Smørgrav pw_fini(); 275f1d05925SDag-Erling Smørgrav errx(0, "user information updated"); 276f1d05925SDag-Erling Smørgrav break; 277f1d05925SDag-Erling Smørgrav default: 278f1d05925SDag-Erling Smørgrav errx(1, "unsupported passwd source"); 279f1d05925SDag-Erling Smørgrav } 2809b50d902SRodney W. Grimes } 2819b50d902SRodney W. Grimes 282f1d05925SDag-Erling Smørgrav static void 2835ea73378SMark Murray baduser(void) 2849b50d902SRodney W. Grimes { 285f1d05925SDag-Erling Smørgrav 2869b50d902SRodney W. Grimes errx(1, "%s", strerror(EACCES)); 2879b50d902SRodney W. Grimes } 2889b50d902SRodney W. Grimes 289f1d05925SDag-Erling Smørgrav static void 2905ea73378SMark Murray usage(void) 2919b50d902SRodney W. Grimes { 2929b50d902SRodney W. Grimes 2930e10ef2eSGarrett Wollman (void)fprintf(stderr, 294612956f6SPhilippe Charnier "usage: chpass%s %s [user]\n", 29592194236SBill Paul #ifdef YP 296f1d05925SDag-Erling Smørgrav " [-d domain] [-h host]", 29792194236SBill Paul #else 298f1d05925SDag-Erling Smørgrav "", 29992194236SBill Paul #endif 300f1d05925SDag-Erling Smørgrav "[-a list] [-p encpass] [-s shell] [-e mmm dd yy]"); 3019b50d902SRodney W. Grimes exit(1); 3029b50d902SRodney W. Grimes } 303