1 /*- 2 * Copyright (c) 1988, 1993, 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char copyright[] = 36 "@(#) Copyright (c) 1988, 1993, 1994\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 static char sccsid[] = "From: @(#)chpass.c 8.4 (Berkeley) 4/2/94"; 42 static char rcsid[] = 43 "$Id: chpass.c,v 1.4 1995/08/13 16:12:24 wpaul Exp $"; 44 #endif /* not lint */ 45 46 #include <sys/param.h> 47 #include <sys/stat.h> 48 #include <sys/signal.h> 49 #include <sys/time.h> 50 #include <sys/resource.h> 51 52 #include <ctype.h> 53 #include <err.h> 54 #include <errno.h> 55 #include <fcntl.h> 56 #include <pwd.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <string.h> 60 #include <unistd.h> 61 62 #include <pw_scan.h> 63 #include <pw_util.h> 64 #include "pw_copy.h" 65 #ifdef YP 66 #include "pw_yp.h" 67 #endif 68 69 #include "chpass.h" 70 #include "pathnames.h" 71 72 char *progname = "chpass"; 73 char *tempname; 74 uid_t uid; 75 76 void baduser __P((void)); 77 void usage __P((void)); 78 79 int 80 main(argc, argv) 81 int argc; 82 char **argv; 83 { 84 enum { NEWSH, LOADENTRY, EDITENTRY, NEWPW } op; 85 struct passwd *pw, lpw; 86 int ch, pfd, tfd; 87 char *arg; 88 #ifdef YP 89 int force_local = 0; 90 int force_yp = 0; 91 #endif 92 93 op = EDITENTRY; 94 #ifdef YP 95 while ((ch = getopt(argc, argv, "a:p:s:ly")) != EOF) 96 #else 97 while ((ch = getopt(argc, argv, "a:p:s:")) != EOF) 98 #endif 99 switch(ch) { 100 case 'a': 101 op = LOADENTRY; 102 arg = optarg; 103 break; 104 case 's': 105 op = NEWSH; 106 arg = optarg; 107 break; 108 case 'p': 109 op = NEWPW; 110 arg = optarg; 111 break; 112 #ifdef YP 113 case 'l': 114 force_local = 1; 115 break; 116 case 'y': 117 force_yp = 1; 118 break; 119 #endif 120 case '?': 121 default: 122 usage(); 123 } 124 argc -= optind; 125 argv += optind; 126 127 uid = getuid(); 128 129 if (op == EDITENTRY || op == NEWSH || op == NEWPW) 130 switch(argc) { 131 case 0: 132 if (!(pw = getpwuid(uid))) 133 errx(1, "unknown user: uid %u", uid); 134 break; 135 case 1: 136 if (!(pw = getpwnam(*argv))) 137 errx(1, "unknown user: %s", *argv); 138 if (uid && uid != pw->pw_uid) 139 baduser(); 140 break; 141 default: 142 usage(); 143 } 144 if (op == NEWSH) { 145 /* protect p_shell -- it thinks NULL is /bin/sh */ 146 if (!arg[0]) 147 usage(); 148 if (p_shell(arg, pw, (ENTRY *)NULL)) 149 pw_error((char *)NULL, 0, 1); 150 } 151 152 if (op == LOADENTRY) { 153 if (uid) 154 baduser(); 155 pw = &lpw; 156 if (!pw_scan(arg, pw)) 157 exit(1); 158 } 159 160 if (op == NEWPW) { 161 if (uid) 162 baduser(); 163 164 if(strchr(arg, ':')) { 165 errx(1, "invalid format for password"); 166 } 167 pw->pw_passwd = arg; 168 } 169 170 #ifdef YP 171 pw->pw_name = strdup(pw->pw_name); 172 _use_yp = use_yp(pw->pw_name); 173 if (_use_yp == USER_YP_ONLY) { 174 if (!force_local) { 175 _use_yp = 1; 176 pw = (struct passwd *)&yp_password; 177 } else 178 errx(1, "unknown local user: %s.", pw->pw_name); 179 } else if (_use_yp == USER_LOCAL_ONLY) { 180 if (!force_yp) { 181 _use_yp = 0; 182 pw = (struct passwd *)&local_password; 183 } else 184 errx(1, "unknown NIS user: %s.", pw->pw_name); 185 } else if (_use_yp == USER_YP_AND_LOCAL) { 186 if (!force_local) { 187 _use_yp = 1; 188 pw = (struct passwd *)&yp_password; 189 } else { 190 _use_yp = 0; 191 pw = (struct passwd *)&local_password; 192 } 193 } 194 #endif /* YP */ 195 196 /* 197 * The temporary file/file descriptor usage is a little tricky here. 198 * 1: We start off with two fd's, one for the master password 199 * file (used to lock everything), and one for a temporary file. 200 * 2: Display() gets an fp for the temporary file, and copies the 201 * user's information into it. It then gives the temporary file 202 * to the user and closes the fp, closing the underlying fd. 203 * 3: The user edits the temporary file some number of times. 204 * 4: Verify() gets an fp for the temporary file, and verifies the 205 * contents. It can't use an fp derived from the step #2 fd, 206 * because the user's editor may have created a new instance of 207 * the file. Once the file is verified, its contents are stored 208 * in a password structure. The verify routine closes the fp, 209 * closing the underlying fd. 210 * 5: Delete the temporary file. 211 * 6: Get a new temporary file/fd. Pw_copy() gets an fp for it 212 * file and copies the master password file into it, replacing 213 * the user record with a new one. We can't use the first 214 * temporary file for this because it was owned by the user. 215 * Pw_copy() closes its fp, flushing the data and closing the 216 * underlying file descriptor. We can't close the master 217 * password fp, or we'd lose the lock. 218 * 7: Call pw_mkdb() (which renames the temporary file) and exit. 219 * The exit closes the master passwd fp/fd. 220 */ 221 pw_init(); 222 pfd = pw_lock(); 223 tfd = pw_tmp(); 224 225 if (op == EDITENTRY) { 226 display(tfd, pw); 227 edit(pw); 228 (void)unlink(tempname); 229 tfd = pw_tmp(); 230 } 231 232 #ifdef YP 233 if (_use_yp) { 234 yp_submit(pw); 235 (void)unlink(tempname); 236 } else { 237 #endif /* YP */ 238 pw_copy(pfd, tfd, pw); 239 240 if (!pw_mkdb()) 241 pw_error((char *)NULL, 0, 1); 242 #ifdef YP 243 } 244 #endif /* YP */ 245 exit(0); 246 } 247 248 void 249 baduser() 250 { 251 errx(1, "%s", strerror(EACCES)); 252 } 253 254 void 255 usage() 256 { 257 258 (void)fprintf(stderr, 259 #ifdef YP 260 "usage: chpass [-l] [-y] [-a list] [-p encpass] [-s shell] [user]\n"); 261 #else 262 "usage: chpass [-a list] [-p encpass] [-s shell] [user]\n"); 263 #endif 264 exit(1); 265 } 266