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[] = 430e10ef2eSGarrett Wollman "$Id$"; 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" 659b50d902SRodney W. Grimes 669b50d902SRodney W. Grimes #include "chpass.h" 679b50d902SRodney W. Grimes #include "pathnames.h" 689b50d902SRodney W. Grimes 699b50d902SRodney W. Grimes char *progname = "chpass"; 709b50d902SRodney W. Grimes char *tempname; 719b50d902SRodney W. Grimes uid_t uid; 729b50d902SRodney W. Grimes 739b50d902SRodney W. Grimes void baduser __P((void)); 749b50d902SRodney W. Grimes void usage __P((void)); 759b50d902SRodney W. Grimes 769b50d902SRodney W. Grimes int 779b50d902SRodney W. Grimes main(argc, argv) 789b50d902SRodney W. Grimes int argc; 799b50d902SRodney W. Grimes char **argv; 809b50d902SRodney W. Grimes { 810e10ef2eSGarrett Wollman enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW } op; 829b50d902SRodney W. Grimes struct passwd *pw, lpw; 839b50d902SRodney W. Grimes int ch, pfd, tfd; 849b50d902SRodney W. Grimes char *arg; 859b50d902SRodney W. Grimes 869b50d902SRodney W. Grimes op = EDITENTRY; 870e10ef2eSGarrett Wollman while ((ch = getopt(argc, argv, "a:p:s:")) != EOF) 889b50d902SRodney W. Grimes switch(ch) { 899b50d902SRodney W. Grimes case 'a': 909b50d902SRodney W. Grimes op = LOADENTRY; 919b50d902SRodney W. Grimes arg = optarg; 929b50d902SRodney W. Grimes break; 939b50d902SRodney W. Grimes case 's': 949b50d902SRodney W. Grimes op = NEWSH; 959b50d902SRodney W. Grimes arg = optarg; 969b50d902SRodney W. Grimes break; 970e10ef2eSGarrett Wollman case 'p': 980e10ef2eSGarrett Wollman op = NEWPW; 990e10ef2eSGarrett Wollman arg = optarg; 1000e10ef2eSGarrett Wollman break; 1019b50d902SRodney W. Grimes case '?': 1029b50d902SRodney W. Grimes default: 1039b50d902SRodney W. Grimes usage(); 1049b50d902SRodney W. Grimes } 1059b50d902SRodney W. Grimes argc -= optind; 1069b50d902SRodney W. Grimes argv += optind; 1079b50d902SRodney W. Grimes 1089b50d902SRodney W. Grimes uid = getuid(); 1099b50d902SRodney W. Grimes 1100e10ef2eSGarrett Wollman if (op == EDITENTRY || op == NEWSH || op == NEWPW) 1119b50d902SRodney W. Grimes switch(argc) { 1129b50d902SRodney W. Grimes case 0: 1139b50d902SRodney W. Grimes if (!(pw = getpwuid(uid))) 1149b50d902SRodney W. Grimes errx(1, "unknown user: uid %u", uid); 1159b50d902SRodney W. Grimes break; 1169b50d902SRodney W. Grimes case 1: 1179b50d902SRodney W. Grimes if (!(pw = getpwnam(*argv))) 1189b50d902SRodney W. Grimes errx(1, "unknown user: %s", *argv); 1199b50d902SRodney W. Grimes if (uid && uid != pw->pw_uid) 1209b50d902SRodney W. Grimes baduser(); 1219b50d902SRodney W. Grimes break; 1229b50d902SRodney W. Grimes default: 1239b50d902SRodney W. Grimes usage(); 1249b50d902SRodney W. Grimes } 1259b50d902SRodney W. Grimes 1269b50d902SRodney W. Grimes if (op == NEWSH) { 1279b50d902SRodney W. Grimes /* protect p_shell -- it thinks NULL is /bin/sh */ 1289b50d902SRodney W. Grimes if (!arg[0]) 1299b50d902SRodney W. Grimes usage(); 1309b50d902SRodney W. Grimes if (p_shell(arg, pw, (ENTRY *)NULL)) 1319b50d902SRodney W. Grimes pw_error((char *)NULL, 0, 1); 1329b50d902SRodney W. Grimes } 1339b50d902SRodney W. Grimes 1349b50d902SRodney W. Grimes if (op == LOADENTRY) { 1359b50d902SRodney W. Grimes if (uid) 1369b50d902SRodney W. Grimes baduser(); 1379b50d902SRodney W. Grimes pw = &lpw; 1389b50d902SRodney W. Grimes if (!pw_scan(arg, pw)) 1399b50d902SRodney W. Grimes exit(1); 1409b50d902SRodney W. Grimes } 1419b50d902SRodney W. Grimes 1420e10ef2eSGarrett Wollman if (op == NEWPW) { 1430e10ef2eSGarrett Wollman if (uid) 1440e10ef2eSGarrett Wollman baduser(); 1450e10ef2eSGarrett Wollman 1460e10ef2eSGarrett Wollman if(strchr(arg, ':')) { 1470e10ef2eSGarrett Wollman errx(1, "invalid format for password"); 1480e10ef2eSGarrett Wollman } 1490e10ef2eSGarrett Wollman pw->pw_passwd = arg; 1500e10ef2eSGarrett Wollman } 1510e10ef2eSGarrett Wollman 1529b50d902SRodney W. Grimes /* 1539b50d902SRodney W. Grimes * The temporary file/file descriptor usage is a little tricky here. 1549b50d902SRodney W. Grimes * 1: We start off with two fd's, one for the master password 1559b50d902SRodney W. Grimes * file (used to lock everything), and one for a temporary file. 1569b50d902SRodney W. Grimes * 2: Display() gets an fp for the temporary file, and copies the 1579b50d902SRodney W. Grimes * user's information into it. It then gives the temporary file 1589b50d902SRodney W. Grimes * to the user and closes the fp, closing the underlying fd. 1599b50d902SRodney W. Grimes * 3: The user edits the temporary file some number of times. 1609b50d902SRodney W. Grimes * 4: Verify() gets an fp for the temporary file, and verifies the 1619b50d902SRodney W. Grimes * contents. It can't use an fp derived from the step #2 fd, 1629b50d902SRodney W. Grimes * because the user's editor may have created a new instance of 1639b50d902SRodney W. Grimes * the file. Once the file is verified, its contents are stored 1649b50d902SRodney W. Grimes * in a password structure. The verify routine closes the fp, 1659b50d902SRodney W. Grimes * closing the underlying fd. 1669b50d902SRodney W. Grimes * 5: Delete the temporary file. 1679b50d902SRodney W. Grimes * 6: Get a new temporary file/fd. Pw_copy() gets an fp for it 1689b50d902SRodney W. Grimes * file and copies the master password file into it, replacing 1699b50d902SRodney W. Grimes * the user record with a new one. We can't use the first 1709b50d902SRodney W. Grimes * temporary file for this because it was owned by the user. 1719b50d902SRodney W. Grimes * Pw_copy() closes its fp, flushing the data and closing the 1729b50d902SRodney W. Grimes * underlying file descriptor. We can't close the master 1739b50d902SRodney W. Grimes * password fp, or we'd lose the lock. 1749b50d902SRodney W. Grimes * 7: Call pw_mkdb() (which renames the temporary file) and exit. 1759b50d902SRodney W. Grimes * The exit closes the master passwd fp/fd. 1769b50d902SRodney W. Grimes */ 1779b50d902SRodney W. Grimes pw_init(); 1789b50d902SRodney W. Grimes pfd = pw_lock(); 1799b50d902SRodney W. Grimes tfd = pw_tmp(); 1809b50d902SRodney W. Grimes 1819b50d902SRodney W. Grimes if (op == EDITENTRY) { 1829b50d902SRodney W. Grimes display(tfd, pw); 1839b50d902SRodney W. Grimes edit(pw); 1849b50d902SRodney W. Grimes (void)unlink(tempname); 1859b50d902SRodney W. Grimes tfd = pw_tmp(); 1869b50d902SRodney W. Grimes } 1879b50d902SRodney W. Grimes 1889b50d902SRodney W. Grimes pw_copy(pfd, tfd, pw); 1899b50d902SRodney W. Grimes 1909b50d902SRodney W. Grimes if (!pw_mkdb()) 1919b50d902SRodney W. Grimes pw_error((char *)NULL, 0, 1); 1929b50d902SRodney W. Grimes exit(0); 1939b50d902SRodney W. Grimes } 1949b50d902SRodney W. Grimes 1959b50d902SRodney W. Grimes void 1969b50d902SRodney W. Grimes baduser() 1979b50d902SRodney W. Grimes { 1989b50d902SRodney W. Grimes errx(1, "%s", strerror(EACCES)); 1999b50d902SRodney W. Grimes } 2009b50d902SRodney W. Grimes 2019b50d902SRodney W. Grimes void 2029b50d902SRodney W. Grimes usage() 2039b50d902SRodney W. Grimes { 2049b50d902SRodney W. Grimes 2050e10ef2eSGarrett Wollman (void)fprintf(stderr, 2060e10ef2eSGarrett Wollman "usage: chpass [-a list] [-p encpass] [-s shell] [user]\n"); 2079b50d902SRodney W. Grimes exit(1); 2089b50d902SRodney W. Grimes } 209