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"; 429b50d902SRodney W. Grimes #endif /* not lint */ 439b50d902SRodney W. Grimes 445ea73378SMark Murray #include <sys/cdefs.h> 455ea73378SMark Murray __FBSDID("$FreeBSD$"); 465ea73378SMark Murray 479b50d902SRodney W. Grimes #include <sys/param.h> 489b50d902SRodney W. Grimes #include <sys/stat.h> 499b50d902SRodney W. Grimes #include <sys/signal.h> 509b50d902SRodney W. Grimes #include <sys/time.h> 519b50d902SRodney W. Grimes #include <sys/resource.h> 529b50d902SRodney W. Grimes 539b50d902SRodney W. Grimes #include <ctype.h> 549b50d902SRodney W. Grimes #include <err.h> 559b50d902SRodney W. Grimes #include <errno.h> 569b50d902SRodney W. Grimes #include <fcntl.h> 579b50d902SRodney W. Grimes #include <pwd.h> 589b50d902SRodney W. Grimes #include <stdio.h> 599b50d902SRodney W. Grimes #include <stdlib.h> 609b50d902SRodney W. Grimes #include <string.h> 619b50d902SRodney W. Grimes #include <unistd.h> 629b50d902SRodney W. Grimes 639b50d902SRodney W. Grimes #include <pw_scan.h> 649b50d902SRodney W. Grimes #include <pw_util.h> 659b50d902SRodney W. Grimes #include "pw_copy.h" 6636715722SBill Paul #ifdef YP 67c2dfe9feSBill Paul #include <rpcsvc/yp.h> 68c2dfe9feSBill Paul int yp_errno = YP_TRUE; 6936715722SBill Paul #include "pw_yp.h" 7036715722SBill Paul #endif 719b50d902SRodney W. Grimes 729b50d902SRodney W. Grimes #include "chpass.h" 739b50d902SRodney W. Grimes #include "pathnames.h" 749b50d902SRodney W. Grimes 759b50d902SRodney W. Grimes char *tempname; 769b50d902SRodney W. Grimes uid_t uid; 779b50d902SRodney W. Grimes 78f1bb2cd2SWarner Losh void baduser(void); 79f1bb2cd2SWarner Losh void usage(void); 809b50d902SRodney W. Grimes 815ea73378SMark Murray char localhost[] = "localhost"; 825ea73378SMark Murray 839b50d902SRodney W. Grimes int 845ea73378SMark Murray main(int argc, char *argv[]) 859b50d902SRodney W. Grimes { 86366982a5SPeter Wemm enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW, NEWEXP } op; 878c44e779SCrist J. Clark struct passwd *pw = NULL, lpw, old_pw; 8872383443SGuido van Rooij char *username = NULL; 899b50d902SRodney W. Grimes int ch, pfd, tfd; 90fa146c53SArchie Cobbs char *arg = NULL; 9192194236SBill Paul #ifdef YP 9292194236SBill Paul int force_local = 0; 9392194236SBill Paul int force_yp = 0; 9492194236SBill Paul #endif 959b50d902SRodney W. Grimes 969b50d902SRodney W. Grimes op = EDITENTRY; 9792194236SBill Paul #ifdef YP 981c8af878SWarner Losh while ((ch = getopt(argc, argv, "a:p:s:e:d:h:oly")) != -1) 9992194236SBill Paul #else 1001c8af878SWarner Losh while ((ch = getopt(argc, argv, "a:p:s:e:")) != -1) 10192194236SBill Paul #endif 1029b50d902SRodney W. Grimes switch(ch) { 1039b50d902SRodney W. Grimes case 'a': 1049b50d902SRodney W. Grimes op = LOADENTRY; 1059b50d902SRodney W. Grimes arg = optarg; 1069b50d902SRodney W. Grimes break; 1079b50d902SRodney W. Grimes case 's': 1089b50d902SRodney W. Grimes op = NEWSH; 1099b50d902SRodney W. Grimes arg = optarg; 1109b50d902SRodney W. Grimes break; 1110e10ef2eSGarrett Wollman case 'p': 1120e10ef2eSGarrett Wollman op = NEWPW; 1130e10ef2eSGarrett Wollman arg = optarg; 1140e10ef2eSGarrett Wollman break; 115366982a5SPeter Wemm case 'e': 116366982a5SPeter Wemm op = NEWEXP; 117366982a5SPeter Wemm arg = optarg; 118366982a5SPeter Wemm break; 11992194236SBill Paul #ifdef YP 120c2dfe9feSBill Paul case 'h': 121a7aa11b1SBill Paul #ifdef PARANOID 122c2dfe9feSBill Paul if (getuid()) { 123a7aa11b1SBill Paul warnx("Only the superuser can use the -h flag"); 124c2dfe9feSBill Paul } else { 125c2dfe9feSBill Paul #endif 126c2dfe9feSBill Paul yp_server = optarg; 127c2dfe9feSBill Paul #ifdef PARANOID 128c2dfe9feSBill Paul } 129c2dfe9feSBill Paul #endif 130c2dfe9feSBill Paul break; 131c2dfe9feSBill Paul case 'd': 132c2dfe9feSBill Paul #ifdef PARANOID 133c2dfe9feSBill Paul if (getuid()) { 134c2dfe9feSBill Paul warnx("Only the superuser can use the -d flag"); 135c2dfe9feSBill Paul } else { 136c2dfe9feSBill Paul #endif 137c2dfe9feSBill Paul yp_domain = optarg; 138c2dfe9feSBill Paul if (yp_server == NULL) 1395ea73378SMark Murray yp_server = localhost; 140c2dfe9feSBill Paul #ifdef PARANOID 141c2dfe9feSBill Paul } 142c2dfe9feSBill Paul #endif 143c2dfe9feSBill Paul break; 14492194236SBill Paul case 'l': 145a7aa11b1SBill Paul _use_yp = 0; 14692194236SBill Paul force_local = 1; 14792194236SBill Paul break; 14892194236SBill Paul case 'y': 149c2dfe9feSBill Paul _use_yp = force_yp = 1; 150c2dfe9feSBill Paul break; 151c2dfe9feSBill Paul case 'o': 152c2dfe9feSBill Paul force_old++; 15392194236SBill Paul break; 15492194236SBill Paul #endif 1559b50d902SRodney W. Grimes case '?': 1569b50d902SRodney W. Grimes default: 1579b50d902SRodney W. Grimes usage(); 1589b50d902SRodney W. Grimes } 1599b50d902SRodney W. Grimes argc -= optind; 1609b50d902SRodney W. Grimes argv += optind; 1619b50d902SRodney W. Grimes 1629b50d902SRodney W. Grimes uid = getuid(); 1639b50d902SRodney W. Grimes 1648c44e779SCrist J. Clark if (op == EDITENTRY || op == NEWSH || op == NEWPW || op == NEWEXP) { 1659b50d902SRodney W. Grimes switch(argc) { 166c2dfe9feSBill Paul #ifdef YP 167c2dfe9feSBill Paul case 0: 168c2dfe9feSBill Paul GETPWUID(uid) 169c2dfe9feSBill Paul get_yp_master(1); /* XXX just to set the suser flag */ 170c2dfe9feSBill Paul break; 171c2dfe9feSBill Paul case 1: 172c2dfe9feSBill Paul GETPWNAM(*argv) 173c2dfe9feSBill Paul get_yp_master(1); /* XXX just to set the suser flag */ 174c2dfe9feSBill Paul #else 1759b50d902SRodney W. Grimes case 0: 1769b50d902SRodney W. Grimes if (!(pw = getpwuid(uid))) 177f458f48bSMike Barcroft errx(1, "unknown user: uid %lu", 178f458f48bSMike Barcroft (unsigned long)uid); 1799b50d902SRodney W. Grimes break; 1809b50d902SRodney W. Grimes case 1: 1819b50d902SRodney W. Grimes if (!(pw = getpwnam(*argv))) 1829b50d902SRodney W. Grimes errx(1, "unknown user: %s", *argv); 183c2dfe9feSBill Paul #endif 1849b50d902SRodney W. Grimes if (uid && uid != pw->pw_uid) 1859b50d902SRodney W. Grimes baduser(); 1869b50d902SRodney W. Grimes break; 1879b50d902SRodney W. Grimes default: 1889b50d902SRodney W. Grimes usage(); 1899b50d902SRodney W. Grimes } 1908c44e779SCrist J. Clark 1918c44e779SCrist J. Clark /* Make a copy for later verification */ 1928c44e779SCrist J. Clark old_pw = *pw; 1938c44e779SCrist J. Clark old_pw.pw_gecos = strdup(old_pw.pw_gecos); 1948c44e779SCrist J. Clark } 1958c44e779SCrist J. Clark 196049ceb63SJoerg Wunsch if (op == NEWSH) { 197049ceb63SJoerg Wunsch /* protect p_shell -- it thinks NULL is /bin/sh */ 198049ceb63SJoerg Wunsch if (!arg[0]) 199049ceb63SJoerg Wunsch usage(); 200049ceb63SJoerg Wunsch if (p_shell(arg, pw, (ENTRY *)NULL)) 201049ceb63SJoerg Wunsch pw_error((char *)NULL, 0, 1); 202049ceb63SJoerg Wunsch } 203049ceb63SJoerg Wunsch 204366982a5SPeter Wemm if (op == NEWEXP) { 205366982a5SPeter Wemm if (uid) /* only root can change expire */ 206366982a5SPeter Wemm baduser(); 207366982a5SPeter Wemm if (p_expire(arg, pw, (ENTRY *)NULL)) 208366982a5SPeter Wemm pw_error((char *)NULL, 0, 1); 209366982a5SPeter Wemm } 210366982a5SPeter Wemm 211049ceb63SJoerg Wunsch if (op == LOADENTRY) { 212049ceb63SJoerg Wunsch if (uid) 213049ceb63SJoerg Wunsch baduser(); 214049ceb63SJoerg Wunsch pw = &lpw; 215248aee62SJacques Vidrine if (!__pw_scan(arg, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) 216049ceb63SJoerg Wunsch exit(1); 217049ceb63SJoerg Wunsch } 21872383443SGuido van Rooij username = pw->pw_name; 219049ceb63SJoerg Wunsch 220049ceb63SJoerg Wunsch if (op == NEWPW) { 221049ceb63SJoerg Wunsch if (uid) 222049ceb63SJoerg Wunsch baduser(); 223049ceb63SJoerg Wunsch 224049ceb63SJoerg Wunsch if(strchr(arg, ':')) { 225049ceb63SJoerg Wunsch errx(1, "invalid format for password"); 226049ceb63SJoerg Wunsch } 227049ceb63SJoerg Wunsch pw->pw_passwd = arg; 228049ceb63SJoerg Wunsch } 229049ceb63SJoerg Wunsch 2309b50d902SRodney W. Grimes /* 2319b50d902SRodney W. Grimes * The temporary file/file descriptor usage is a little tricky here. 2328c44e779SCrist J. Clark * 1: Create a temporary file called tempname, get descriptor tfd. 2339b50d902SRodney W. Grimes * 2: Display() gets an fp for the temporary file, and copies the 2349b50d902SRodney W. Grimes * user's information into it. It then gives the temporary file 2359b50d902SRodney W. Grimes * to the user and closes the fp, closing the underlying fd. 2369b50d902SRodney W. Grimes * 3: The user edits the temporary file some number of times. 2378c44e779SCrist J. Clark * The results are stored in pw by edit(). 2388c44e779SCrist J. Clark * 4: Delete the temporary file. 2398c44e779SCrist J. Clark * 5: Make a new temporary file, descriptor tfd. 2408c44e779SCrist J. Clark * 6: Get a descriptor for the master.passwd file, pfd, and 2418c44e779SCrist J. Clark * lock master.passwd. 2428c44e779SCrist J. Clark * 7: Pw_copy() gets descriptors for master.passwd and the 2438c44e779SCrist J. Clark * temporary file and copies the master password file into it, 2448c44e779SCrist J. Clark * replacing the modified user's record with a new one. We can't 2458c44e779SCrist J. Clark * use the first temporary file for this because it was owned 2468c44e779SCrist J. Clark * by the user. Pass the new and old user info. Check the 2478c44e779SCrist J. Clark * entry for our user has not been changed by someone else by 2488c44e779SCrist J. Clark * while the user was editing by comparing the old info to 2498c44e779SCrist J. Clark * the entry freshly read from master.passwd. Pw_copy() closes 2508c44e779SCrist J. Clark * its fp, flushing the data and closing the underlying file 2518c44e779SCrist J. Clark * descriptor. We can't close the master password fp, or we'd 2528c44e779SCrist J. Clark * lose the lock. 2538c44e779SCrist J. Clark * 8: Call pw_mkdb() (which renames the temporary file) and exit. 2549b50d902SRodney W. Grimes * The exit closes the master passwd fp/fd. 2559b50d902SRodney W. Grimes */ 2569b50d902SRodney W. Grimes pw_init(); 2579b50d902SRodney W. Grimes tfd = pw_tmp(); 2589b50d902SRodney W. Grimes 2599b50d902SRodney W. Grimes if (op == EDITENTRY) { 2609b50d902SRodney W. Grimes display(tfd, pw); 2619b50d902SRodney W. Grimes edit(pw); 2629b50d902SRodney W. Grimes (void)unlink(tempname); 2639b50d902SRodney W. Grimes tfd = pw_tmp(); 2649b50d902SRodney W. Grimes } 2659b50d902SRodney W. Grimes 26636715722SBill Paul #ifdef YP 26736715722SBill Paul if (_use_yp) { 26836715722SBill Paul yp_submit(pw); 26936715722SBill Paul (void)unlink(tempname); 27036715722SBill Paul } else { 27136715722SBill Paul #endif /* YP */ 2728c44e779SCrist J. Clark pfd = pw_lock(); 2738c44e779SCrist J. Clark pw_copy(pfd, tfd, pw, (op == LOADENTRY) ? NULL : &old_pw); 2749b50d902SRodney W. Grimes 27579a1b8d9SGuido van Rooij if (!pw_mkdb(username)) 2769b50d902SRodney W. Grimes pw_error((char *)NULL, 0, 1); 27736715722SBill Paul #ifdef YP 27836715722SBill Paul } 27936715722SBill Paul #endif /* YP */ 2809b50d902SRodney W. Grimes exit(0); 2819b50d902SRodney W. Grimes } 2829b50d902SRodney W. Grimes 2839b50d902SRodney W. Grimes void 2845ea73378SMark Murray baduser(void) 2859b50d902SRodney W. Grimes { 2869b50d902SRodney W. Grimes errx(1, "%s", strerror(EACCES)); 2879b50d902SRodney W. Grimes } 2889b50d902SRodney W. Grimes 2899b50d902SRodney W. Grimes void 2905ea73378SMark Murray usage(void) 2919b50d902SRodney W. Grimes { 2929b50d902SRodney W. Grimes 2930e10ef2eSGarrett Wollman (void)fprintf(stderr, 29492194236SBill Paul #ifdef YP 295366982a5SPeter Wemm "usage: chpass [-l] [-y] [-d domain [-h host]] [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n"); 29692194236SBill Paul #else 297366982a5SPeter Wemm "usage: chpass [-a list] [-p encpass] [-s shell] [-e mmm dd yy] [user]\n"); 29892194236SBill Paul #endif 2999b50d902SRodney W. Grimes exit(1); 3009b50d902SRodney W. Grimes } 301