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 35fa146c53SArchie Cobbs static const 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 41fa146c53SArchie Cobbs static const char sccsid[] = "From: @(#)chpass.c 8.4 (Berkeley) 4/2/94"; 42fa146c53SArchie Cobbs static const char rcsid[] = 43c3aac50fSPeter Wemm "$FreeBSD$"; 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; 868c44e779SCrist J. Clark struct passwd *pw = NULL, lpw, old_pw; 8772383443SGuido van Rooij char *username = NULL; 889b50d902SRodney W. Grimes int ch, pfd, tfd; 89fa146c53SArchie Cobbs char *arg = NULL; 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 971c8af878SWarner Losh while ((ch = getopt(argc, argv, "a:p:s:e:d:h:oly")) != -1) 9892194236SBill Paul #else 991c8af878SWarner Losh while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1) 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 1638c44e779SCrist J. Clark 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))) 176f458f48bSMike Barcroft errx(1, "unknown user: uid %lu", 177f458f48bSMike Barcroft (unsigned long)uid); 1789b50d902SRodney W. Grimes break; 1799b50d902SRodney W. Grimes case 1: 1809b50d902SRodney W. Grimes if (!(pw = getpwnam(*argv))) 1819b50d902SRodney W. Grimes errx(1, "unknown user: %s", *argv); 182c2dfe9feSBill Paul #endif 1839b50d902SRodney W. Grimes if (uid && uid != pw->pw_uid) 1849b50d902SRodney W. Grimes baduser(); 1859b50d902SRodney W. Grimes break; 1869b50d902SRodney W. Grimes default: 1879b50d902SRodney W. Grimes usage(); 1889b50d902SRodney W. Grimes } 1898c44e779SCrist J. Clark 1908c44e779SCrist J. Clark /* Make a copy for later verification */ 1918c44e779SCrist J. Clark old_pw = *pw; 1928c44e779SCrist J. Clark old_pw.pw_gecos = strdup(old_pw.pw_gecos); 1938c44e779SCrist J. Clark } 1948c44e779SCrist J. Clark 195049ceb63SJoerg Wunsch if (op == NEWSH) { 196049ceb63SJoerg Wunsch /* protect p_shell -- it thinks NULL is /bin/sh */ 197049ceb63SJoerg Wunsch if (!arg[0]) 198049ceb63SJoerg Wunsch usage(); 199049ceb63SJoerg Wunsch if (p_shell(arg, pw, (ENTRY *)NULL)) 200049ceb63SJoerg Wunsch pw_error((char *)NULL, 0, 1); 201049ceb63SJoerg Wunsch } 202049ceb63SJoerg Wunsch 203366982a5SPeter Wemm if (op == NEWEXP) { 204366982a5SPeter Wemm if (uid) /* only root can change expire */ 205366982a5SPeter Wemm baduser(); 206366982a5SPeter Wemm if (p_expire(arg, pw, (ENTRY *)NULL)) 207366982a5SPeter Wemm pw_error((char *)NULL, 0, 1); 208366982a5SPeter Wemm } 209366982a5SPeter Wemm 210049ceb63SJoerg Wunsch if (op == LOADENTRY) { 211049ceb63SJoerg Wunsch if (uid) 212049ceb63SJoerg Wunsch baduser(); 213049ceb63SJoerg Wunsch pw = &lpw; 214248aee62SJacques Vidrine if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) 215049ceb63SJoerg Wunsch exit(1); 216049ceb63SJoerg Wunsch } 21772383443SGuido van Rooij username = pw->pw_name; 218049ceb63SJoerg Wunsch 219049ceb63SJoerg Wunsch if (op == NEWPW) { 220049ceb63SJoerg Wunsch if (uid) 221049ceb63SJoerg Wunsch baduser(); 222049ceb63SJoerg Wunsch 223049ceb63SJoerg Wunsch if(strchr(arg, ':')) { 224049ceb63SJoerg Wunsch errx(1, "invalid format for password"); 225049ceb63SJoerg Wunsch } 226049ceb63SJoerg Wunsch pw->pw_passwd = arg; 227049ceb63SJoerg Wunsch } 228049ceb63SJoerg Wunsch 2299b50d902SRodney W. Grimes /* 2309b50d902SRodney W. Grimes * The temporary file/file descriptor usage is a little tricky here. 2318c44e779SCrist J. Clark * 1: Create a temporary file called tempname, get descriptor tfd. 2329b50d902SRodney W. Grimes * 2: Display() gets an fp for the temporary file, and copies the 2339b50d902SRodney W. Grimes * user's information into it. It then gives the temporary file 2349b50d902SRodney W. Grimes * to the user and closes the fp, closing the underlying fd. 2359b50d902SRodney W. Grimes * 3: The user edits the temporary file some number of times. 2368c44e779SCrist J. Clark * The results are stored in pw by edit(). 2378c44e779SCrist J. Clark * 4: Delete the temporary file. 2388c44e779SCrist J. Clark * 5: Make a new temporary file, descriptor tfd. 2398c44e779SCrist J. Clark * 6: Get a descriptor for the master.passwd file, pfd, and 2408c44e779SCrist J. Clark * lock master.passwd. 2418c44e779SCrist J. Clark * 7: Pw_copy() gets descriptors for master.passwd and the 2428c44e779SCrist J. Clark * temporary file and copies the master password file into it, 2438c44e779SCrist J. Clark * replacing the modified user's record with a new one. We can't 2448c44e779SCrist J. Clark * use the first temporary file for this because it was owned 2458c44e779SCrist J. Clark * by the user. Pass the new and old user info. Check the 2468c44e779SCrist J. Clark * entry for our user has not been changed by someone else by 2478c44e779SCrist J. Clark * while the user was editing by comparing the old info to 2488c44e779SCrist J. Clark * the entry freshly read from master.passwd. Pw_copy() closes 2498c44e779SCrist J. Clark * its fp, flushing the data and closing the underlying file 2508c44e779SCrist J. Clark * descriptor. We can't close the master password fp, or we'd 2518c44e779SCrist J. Clark * lose the lock. 2528c44e779SCrist J. Clark * 8: Call pw_mkdb() (which renames the temporary file) and exit. 2539b50d902SRodney W. Grimes * The exit closes the master passwd fp/fd. 2549b50d902SRodney W. Grimes */ 2559b50d902SRodney W. Grimes pw_init(); 2569b50d902SRodney W. Grimes tfd = pw_tmp(); 2579b50d902SRodney W. Grimes 2589b50d902SRodney W. Grimes if (op == EDITENTRY) { 2599b50d902SRodney W. Grimes display(tfd, pw); 2609b50d902SRodney W. Grimes edit(pw); 2619b50d902SRodney W. Grimes (void)unlink(tempname); 2629b50d902SRodney W. Grimes tfd = pw_tmp(); 2639b50d902SRodney W. Grimes } 2649b50d902SRodney W. Grimes 26536715722SBill Paul #ifdef YP 26636715722SBill Paul if (_use_yp) { 26736715722SBill Paul yp_submit(pw); 26836715722SBill Paul (void)unlink(tempname); 26936715722SBill Paul } else { 27036715722SBill Paul #endif /* YP */ 2718c44e779SCrist J. Clark pfd = pw_lock(); 2728c44e779SCrist J. Clark pw_copy(pfd, tfd, pw, (op == LOADENTRY) ? NULL : &old_pw); 2739b50d902SRodney W. Grimes 27479a1b8d9SGuido van Rooij if (!pw_mkdb(username)) 2759b50d902SRodney W. Grimes pw_error((char *)NULL, 0, 1); 27636715722SBill Paul #ifdef YP 27736715722SBill Paul } 27836715722SBill Paul #endif /* YP */ 2799b50d902SRodney W. Grimes exit(0); 2809b50d902SRodney W. Grimes } 2819b50d902SRodney W. Grimes 2829b50d902SRodney W. Grimes void 2839b50d902SRodney W. Grimes baduser() 2849b50d902SRodney W. Grimes { 2859b50d902SRodney W. Grimes errx(1, "%s", strerror(EACCES)); 2869b50d902SRodney W. Grimes } 2879b50d902SRodney W. Grimes 2889b50d902SRodney W. Grimes void 2899b50d902SRodney W. Grimes usage() 2909b50d902SRodney W. Grimes { 2919b50d902SRodney W. Grimes 2920e10ef2eSGarrett Wollman (void)fprintf(stderr, 29392194236SBill Paul #ifdef YP 294366982a5SPeter Wemm "usage: chpass [-l] [-y] [-d domain [-h host]] [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n"); 29592194236SBill Paul #else 296366982a5SPeter Wemm "usage: chpass [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n"); 29792194236SBill Paul #endif 2989b50d902SRodney W. Grimes exit(1); 2999b50d902SRodney W. Grimes } 300