19b50d902SRodney W. Grimes /*- 29b50d902SRodney W. Grimes * Copyright (c) 1988, 1993, 1994 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 69b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 79b50d902SRodney W. Grimes * are met: 89b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 99b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 109b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 129b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 139b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 149b50d902SRodney W. Grimes * must display the following acknowledgement: 159b50d902SRodney W. Grimes * This product includes software developed by the University of 169b50d902SRodney W. Grimes * California, Berkeley and its contributors. 179b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 189b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 199b50d902SRodney W. Grimes * without specific prior written permission. 209b50d902SRodney W. Grimes * 219b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 229b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 239b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 249b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 259b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 269b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 279b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 289b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 299b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 309b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 319b50d902SRodney W. Grimes * SUCH DAMAGE. 329b50d902SRodney W. Grimes */ 339b50d902SRodney W. Grimes 349b50d902SRodney W. Grimes #ifndef lint 359b50d902SRodney W. Grimes static char copyright[] = 369b50d902SRodney W. Grimes "@(#) Copyright (c) 1988, 1993, 1994\n\ 379b50d902SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 389b50d902SRodney W. Grimes #endif /* not lint */ 399b50d902SRodney W. Grimes 409b50d902SRodney W. Grimes #ifndef lint 410e10ef2eSGarrett Wollman static char sccsid[] = "From: @(#)chpass.c 8.4 (Berkeley) 4/2/94"; 420e10ef2eSGarrett Wollman static char rcsid[] = 43366982a5SPeter Wemm "$Id: chpass.c,v 1.10 1996/07/14 16:42:33 guido Exp $"; 449b50d902SRodney W. Grimes #endif /* not lint */ 459b50d902SRodney W. Grimes 469b50d902SRodney W. Grimes #include <sys/param.h> 479b50d902SRodney W. Grimes #include <sys/stat.h> 489b50d902SRodney W. Grimes #include <sys/signal.h> 499b50d902SRodney W. Grimes #include <sys/time.h> 509b50d902SRodney W. Grimes #include <sys/resource.h> 519b50d902SRodney W. Grimes 529b50d902SRodney W. Grimes #include <ctype.h> 539b50d902SRodney W. Grimes #include <err.h> 549b50d902SRodney W. Grimes #include <errno.h> 559b50d902SRodney W. Grimes #include <fcntl.h> 569b50d902SRodney W. Grimes #include <pwd.h> 579b50d902SRodney W. Grimes #include <stdio.h> 589b50d902SRodney W. Grimes #include <stdlib.h> 599b50d902SRodney W. Grimes #include <string.h> 609b50d902SRodney W. Grimes #include <unistd.h> 619b50d902SRodney W. Grimes 629b50d902SRodney W. Grimes #include <pw_scan.h> 639b50d902SRodney W. Grimes #include <pw_util.h> 649b50d902SRodney W. Grimes #include "pw_copy.h" 6536715722SBill Paul #ifdef YP 66c2dfe9feSBill Paul #include <rpcsvc/yp.h> 67c2dfe9feSBill Paul int yp_errno = YP_TRUE; 6836715722SBill Paul #include "pw_yp.h" 6936715722SBill Paul #endif 709b50d902SRodney W. Grimes 719b50d902SRodney W. Grimes #include "chpass.h" 729b50d902SRodney W. Grimes #include "pathnames.h" 739b50d902SRodney W. Grimes 749b50d902SRodney W. Grimes char *tempname; 759b50d902SRodney W. Grimes uid_t uid; 769b50d902SRodney W. Grimes 779b50d902SRodney W. Grimes void baduser __P((void)); 789b50d902SRodney W. Grimes void usage __P((void)); 799b50d902SRodney W. Grimes 809b50d902SRodney W. Grimes int 819b50d902SRodney W. Grimes main(argc, argv) 829b50d902SRodney W. Grimes int argc; 839b50d902SRodney W. Grimes char **argv; 849b50d902SRodney W. Grimes { 85366982a5SPeter Wemm enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op; 869b50d902SRodney W. Grimes struct passwd *pw, lpw; 8772383443SGuido van Rooij char *username = NULL; 889b50d902SRodney W. Grimes int ch, pfd, tfd; 899b50d902SRodney W. Grimes char *arg; 9092194236SBill Paul #ifdef YP 9192194236SBill Paul int force_local = 0; 9292194236SBill Paul int force_yp = 0; 9392194236SBill Paul #endif 949b50d902SRodney W. Grimes 959b50d902SRodney W. Grimes op = EDITENTRY; 9692194236SBill Paul #ifdef YP 97366982a5SPeter Wemm while ((ch = getopt(argc, argv, "a:p:s:e:d:h:oly")) != EOF) 9892194236SBill Paul #else 99366982a5SPeter Wemm while ((ch = getopt(argc, argv, "a:p:s:e:")) != EOF) 10092194236SBill Paul #endif 1019b50d902SRodney W. Grimes switch(ch) { 1029b50d902SRodney W. Grimes case 'a': 1039b50d902SRodney W. Grimes op = LOADENTRY; 1049b50d902SRodney W. Grimes arg = optarg; 1059b50d902SRodney W. Grimes break; 1069b50d902SRodney W. Grimes case 's': 1079b50d902SRodney W. Grimes op = NEWSH; 1089b50d902SRodney W. Grimes arg = optarg; 1099b50d902SRodney W. Grimes break; 1100e10ef2eSGarrett Wollman case 'p': 1110e10ef2eSGarrett Wollman op = NEWPW; 1120e10ef2eSGarrett Wollman arg = optarg; 1130e10ef2eSGarrett Wollman break; 114366982a5SPeter Wemm case 'e': 115366982a5SPeter Wemm op = NEWEXP; 116366982a5SPeter Wemm arg = optarg; 117366982a5SPeter Wemm break; 11892194236SBill Paul #ifdef YP 119c2dfe9feSBill Paul case 'h': 120a7aa11b1SBill Paul #ifdef PARANOID 121c2dfe9feSBill Paul if (getuid()) { 122a7aa11b1SBill Paul warnx("Only the superuser can use the -h flag"); 123c2dfe9feSBill Paul } else { 124c2dfe9feSBill Paul #endif 125c2dfe9feSBill Paul yp_server = optarg; 126c2dfe9feSBill Paul #ifdef PARANOID 127c2dfe9feSBill Paul } 128c2dfe9feSBill Paul #endif 129c2dfe9feSBill Paul break; 130c2dfe9feSBill Paul case 'd': 131c2dfe9feSBill Paul #ifdef PARANOID 132c2dfe9feSBill Paul if (getuid()) { 133c2dfe9feSBill Paul warnx("Only the superuser can use the -d flag"); 134c2dfe9feSBill Paul } else { 135c2dfe9feSBill Paul #endif 136c2dfe9feSBill Paul yp_domain = optarg; 137c2dfe9feSBill Paul if (yp_server == NULL) 138c2dfe9feSBill Paul yp_server = "localhost"; 139c2dfe9feSBill Paul #ifdef PARANOID 140c2dfe9feSBill Paul } 141c2dfe9feSBill Paul #endif 142c2dfe9feSBill Paul break; 14392194236SBill Paul case 'l': 144a7aa11b1SBill Paul _use_yp = 0; 14592194236SBill Paul force_local = 1; 14692194236SBill Paul break; 14792194236SBill Paul case 'y': 148c2dfe9feSBill Paul _use_yp = force_yp = 1; 149c2dfe9feSBill Paul break; 150c2dfe9feSBill Paul case 'o': 151c2dfe9feSBill Paul force_old++; 15292194236SBill Paul break; 15392194236SBill Paul #endif 1549b50d902SRodney W. Grimes case '?': 1559b50d902SRodney W. Grimes default: 1569b50d902SRodney W. Grimes usage(); 1579b50d902SRodney W. Grimes } 1589b50d902SRodney W. Grimes argc -= optind; 1599b50d902SRodney W. Grimes argv += optind; 1609b50d902SRodney W. Grimes 1619b50d902SRodney W. Grimes uid = getuid(); 1629b50d902SRodney W. Grimes 163366982a5SPeter Wemm if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) 1649b50d902SRodney W. Grimes switch(argc) { 165c2dfe9feSBill Paul #ifdef YP 166c2dfe9feSBill Paul case 0: 167c2dfe9feSBill Paul GETPWUID(uid) 168c2dfe9feSBill Paul get_yp_master(1); /* XXX just to set the suser flag */ 169c2dfe9feSBill Paul break; 170c2dfe9feSBill Paul case 1: 171c2dfe9feSBill Paul GETPWNAM(*argv) 172c2dfe9feSBill Paul get_yp_master(1); /* XXX just to set the suser flag */ 173c2dfe9feSBill Paul #else 1749b50d902SRodney W. Grimes case 0: 1759b50d902SRodney W. Grimes if (!(pw = getpwuid(uid))) 1769b50d902SRodney W. Grimes errx(1, "unknown user: uid %u", uid); 1779b50d902SRodney W. Grimes break; 1789b50d902SRodney W. Grimes case 1: 1799b50d902SRodney W. Grimes if (!(pw = getpwnam(*argv))) 1809b50d902SRodney W. Grimes errx(1, "unknown user: %s", *argv); 181c2dfe9feSBill Paul #endif 1829b50d902SRodney W. Grimes if (uid && uid != pw->pw_uid) 1839b50d902SRodney W. Grimes baduser(); 1849b50d902SRodney W. Grimes break; 1859b50d902SRodney W. Grimes default: 1869b50d902SRodney W. Grimes usage(); 1879b50d902SRodney W. Grimes } 188049ceb63SJoerg Wunsch if (op == NEWSH) { 189049ceb63SJoerg Wunsch /* protect p_shell -- it thinks NULL is /bin/sh */ 190049ceb63SJoerg Wunsch if (!arg[0]) 191049ceb63SJoerg Wunsch usage(); 192049ceb63SJoerg Wunsch if (p_shell(arg, pw, (ENTRY *)NULL)) 193049ceb63SJoerg Wunsch pw_error((char *)NULL, 0, 1); 194049ceb63SJoerg Wunsch } 195049ceb63SJoerg Wunsch 196366982a5SPeter Wemm if (op == NEWEXP) { 197366982a5SPeter Wemm if (uid) /* only root can change expire */ 198366982a5SPeter Wemm baduser(); 199366982a5SPeter Wemm if (p_expire(arg, pw, (ENTRY *)NULL)) 200366982a5SPeter Wemm pw_error((char *)NULL, 0, 1); 201366982a5SPeter Wemm } 202366982a5SPeter Wemm 203049ceb63SJoerg Wunsch if (op == LOADENTRY) { 204049ceb63SJoerg Wunsch if (uid) 205049ceb63SJoerg Wunsch baduser(); 206049ceb63SJoerg Wunsch pw = &lpw; 207049ceb63SJoerg Wunsch if (!pw_scan(arg, pw)) 208049ceb63SJoerg Wunsch exit(1); 209049ceb63SJoerg Wunsch } 21072383443SGuido van Rooij username = pw->pw_name; 211049ceb63SJoerg Wunsch 212049ceb63SJoerg Wunsch if (op == NEWPW) { 213049ceb63SJoerg Wunsch if (uid) 214049ceb63SJoerg Wunsch baduser(); 215049ceb63SJoerg Wunsch 216049ceb63SJoerg Wunsch if(strchr(arg, ':')) { 217049ceb63SJoerg Wunsch errx(1, "invalid format for password"); 218049ceb63SJoerg Wunsch } 219049ceb63SJoerg Wunsch pw->pw_passwd = arg; 220049ceb63SJoerg Wunsch } 221049ceb63SJoerg Wunsch 2229b50d902SRodney W. Grimes /* 2239b50d902SRodney W. Grimes * The temporary file/file descriptor usage is a little tricky here. 2249b50d902SRodney W. Grimes * 1: We start off with two fd's, one for the master password 2259b50d902SRodney W. Grimes * file (used to lock everything), and one for a temporary file. 2269b50d902SRodney W. Grimes * 2: Display() gets an fp for the temporary file, and copies the 2279b50d902SRodney W. Grimes * user's information into it. It then gives the temporary file 2289b50d902SRodney W. Grimes * to the user and closes the fp, closing the underlying fd. 2299b50d902SRodney W. Grimes * 3: The user edits the temporary file some number of times. 2309b50d902SRodney W. Grimes * 4: Verify() gets an fp for the temporary file, and verifies the 2319b50d902SRodney W. Grimes * contents. It can't use an fp derived from the step #2 fd, 2329b50d902SRodney W. Grimes * because the user's editor may have created a new instance of 2339b50d902SRodney W. Grimes * the file. Once the file is verified, its contents are stored 2349b50d902SRodney W. Grimes * in a password structure. The verify routine closes the fp, 2359b50d902SRodney W. Grimes * closing the underlying fd. 2369b50d902SRodney W. Grimes * 5: Delete the temporary file. 2379b50d902SRodney W. Grimes * 6: Get a new temporary file/fd. Pw_copy() gets an fp for it 2389b50d902SRodney W. Grimes * file and copies the master password file into it, replacing 2399b50d902SRodney W. Grimes * the user record with a new one. We can't use the first 2409b50d902SRodney W. Grimes * temporary file for this because it was owned by the user. 2419b50d902SRodney W. Grimes * Pw_copy() closes its fp, flushing the data and closing the 2429b50d902SRodney W. Grimes * underlying file descriptor. We can't close the master 2439b50d902SRodney W. Grimes * password fp, or we'd lose the lock. 2449b50d902SRodney W. Grimes * 7: Call pw_mkdb() (which renames the temporary file) and exit. 2459b50d902SRodney W. Grimes * The exit closes the master passwd fp/fd. 2469b50d902SRodney W. Grimes */ 2479b50d902SRodney W. Grimes pw_init(); 2489b50d902SRodney W. Grimes pfd = pw_lock(); 2499b50d902SRodney W. Grimes tfd = pw_tmp(); 2509b50d902SRodney W. Grimes 2519b50d902SRodney W. Grimes if (op == EDITENTRY) { 2529b50d902SRodney W. Grimes display(tfd, pw); 2539b50d902SRodney W. Grimes edit(pw); 2549b50d902SRodney W. Grimes (void)unlink(tempname); 2559b50d902SRodney W. Grimes tfd = pw_tmp(); 2569b50d902SRodney W. Grimes } 2579b50d902SRodney W. Grimes 25836715722SBill Paul #ifdef YP 25936715722SBill Paul if (_use_yp) { 26036715722SBill Paul yp_submit(pw); 26136715722SBill Paul (void)unlink(tempname); 26236715722SBill Paul } else { 26336715722SBill Paul #endif /* YP */ 2649b50d902SRodney W. Grimes pw_copy(pfd, tfd, pw); 2659b50d902SRodney W. Grimes 26679a1b8d9SGuido van Rooij if (!pw_mkdb(username)) 2679b50d902SRodney W. Grimes pw_error((char *)NULL, 0, 1); 26836715722SBill Paul #ifdef YP 26936715722SBill Paul } 27036715722SBill Paul #endif /* YP */ 2719b50d902SRodney W. Grimes exit(0); 2729b50d902SRodney W. Grimes } 2739b50d902SRodney W. Grimes 2749b50d902SRodney W. Grimes void 2759b50d902SRodney W. Grimes baduser() 2769b50d902SRodney W. Grimes { 2779b50d902SRodney W. Grimes errx(1, "%s", strerror(EACCES)); 2789b50d902SRodney W. Grimes } 2799b50d902SRodney W. Grimes 2809b50d902SRodney W. Grimes void 2819b50d902SRodney W. Grimes usage() 2829b50d902SRodney W. Grimes { 2839b50d902SRodney W. Grimes 2840e10ef2eSGarrett Wollman (void)fprintf(stderr, 28592194236SBill Paul #ifdef YP 286366982a5SPeter Wemm "usage: chpass [-l] [-y] [-d domain [-h host]] [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n"); 28792194236SBill Paul #else 288366982a5SPeter Wemm "usage: chpass [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n"); 28992194236SBill Paul #endif 2909b50d902SRodney W. Grimes exit(1); 2919b50d902SRodney W. Grimes } 292