1 /*- 2 * Copyright (c) 1988 The Regents of the University of California. 3 * 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 char copyright[] = 36 "@(#) Copyright (c) 1988 The Regents of the University of California.\n\ 37 All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 /*static char sccsid[] = "from: @(#)chpass.c 5.17 (Berkeley) 3/3/91";*/ 42 static char rcsid[] = "$Id: chpass.c,v 1.3 1993/08/01 18:17:59 mycroft Exp $"; 43 #endif /* not lint */ 44 45 #include <sys/param.h> 46 #include <sys/stat.h> 47 #include <sys/signal.h> 48 #include <sys/time.h> 49 #include <sys/resource.h> 50 #include <fcntl.h> 51 #include <pwd.h> 52 #include <errno.h> 53 #include <stdio.h> 54 #include <ctype.h> 55 #include <string.h> 56 #include "chpass.h" 57 #include "pathnames.h" 58 59 char *progname = "chpass"; 60 char *tempname; 61 uid_t uid; 62 63 #ifdef YP 64 int use_yp; 65 int force_yp = 0; 66 extern struct passwd *ypgetpwnam(), *ypgetpwuid(); 67 #endif 68 69 main(argc, argv) 70 int argc; 71 char **argv; 72 { 73 extern int optind; 74 extern char *optarg; 75 register enum { NEWSH, LOADENTRY, EDITENTRY } op; 76 register struct passwd *pw; 77 struct passwd lpw; 78 int ch, pfd, tfd; 79 char *arg; 80 81 #ifdef YP 82 use_yp = _yp_check(NULL); 83 #endif 84 85 op = EDITENTRY; 86 while ((ch = getopt(argc, argv, "a:s:ly")) != EOF) 87 switch(ch) { 88 case 'a': 89 op = LOADENTRY; 90 arg = optarg; 91 break; 92 case 's': 93 op = NEWSH; 94 arg = optarg; 95 break; 96 #ifdef YP 97 case 'l': 98 use_yp = 0; 99 break; 100 case 'y': 101 if (!use_yp) { 102 fprintf(stderr, "chpass: YP not in use.\n"); 103 usage(); 104 exit(1); 105 } 106 force_yp = 1; 107 break; 108 #endif 109 case '?': 110 default: 111 usage(); 112 } 113 argc -= optind; 114 argv += optind; 115 116 #ifdef YP 117 if (op == LOADENTRY && use_yp) { 118 (void)fprintf(stderr, "chpass: cannot load entry using NIS.\n\tUse the -l flag to load local.\n"); 119 exit(1); 120 } 121 #endif 122 uid = getuid(); 123 124 if (op == EDITENTRY || op == NEWSH) 125 switch(argc) { 126 case 0: 127 pw = getpwuid(uid); 128 #ifdef YP 129 if (pw && !force_yp) 130 use_yp = 0; 131 else if (use_yp) 132 pw = ypgetpwuid(uid); 133 #endif /* YP */ 134 if (!pw) { 135 (void)fprintf(stderr, 136 "chpass: unknown user: uid %u\n", uid); 137 exit(1); 138 } 139 break; 140 case 1: 141 pw = getpwnam(*argv); 142 #ifdef YP 143 if (pw && !force_yp) 144 use_yp = 0; 145 else if (use_yp) 146 pw = ypgetpwnam(*argv); 147 #endif /* YP */ 148 if (!pw) { 149 (void)fprintf(stderr, 150 "chpass: unknown user %s.\n", *argv); 151 exit(1); 152 } 153 if (uid && uid != pw->pw_uid) 154 baduser(); 155 break; 156 default: 157 usage(); 158 } 159 160 if (op == NEWSH) { 161 /* protect p_shell -- it thinks NULL is /bin/sh */ 162 if (!arg[0]) 163 usage(); 164 if (p_shell(arg, pw, (ENTRY *)NULL)) 165 pw_error((char *)NULL, 0, 1); 166 } 167 168 if (op == LOADENTRY) { 169 if (uid) 170 baduser(); 171 pw = &lpw; 172 if (!pw_scan(arg, pw)) 173 exit(1); 174 } 175 176 /* 177 * The temporary file/file descriptor usage is a little tricky here. 178 * 1: We start off with two fd's, one for the master password 179 * file (used to lock everything), and one for a temporary file. 180 * 2: Display() gets an fp for the temporary file, and copies the 181 * user's information into it. It then gives the temporary file 182 * to the user and closes the fp, closing the underlying fd. 183 * 3: The user edits the temporary file some number of times. 184 * 4: Verify() gets an fp for the temporary file, and verifies the 185 * contents. It can't use an fp derived from the step #2 fd, 186 * because the user's editor may have created a new instance of 187 * the file. Once the file is verified, its contents are stored 188 * in a password structure. The verify routine closes the fp, 189 * closing the underlying fd. 190 * 5: Delete the temporary file. 191 * 6: Get a new temporary file/fd. Pw_copy() gets an fp for it 192 * file and copies the master password file into it, replacing 193 * the user record with a new one. We can't use the first 194 * temporary file for this because it was owned by the user. 195 * Pw_copy() closes its fp, flushing the data and closing the 196 * underlying file descriptor. We can't close the master 197 * password fp, or we'd lose the lock. 198 * 7: Call pw_mkdb() (which renames the temporary file) and exit. 199 * The exit closes the master passwd fp/fd. 200 */ 201 pw_init(); 202 pfd = pw_lock(); 203 tfd = pw_tmp(); 204 205 if (op == EDITENTRY) { 206 display(tfd, pw); 207 edit(pw); 208 (void)unlink(tempname); 209 tfd = pw_tmp(); 210 } 211 212 #ifdef YP 213 if (use_yp) { 214 (void)unlink(tempname); 215 if (pw_yp(pw, uid)) 216 pw_error((char *)NULL, 0, 1); 217 else 218 exit(0); 219 } 220 else 221 #endif /* YP */ 222 pw_copy(pfd, tfd, pw); 223 224 if (!pw_mkdb()) 225 pw_error((char *)NULL, 0, 1); 226 227 exit(0); 228 } 229 230 baduser() 231 { 232 (void)fprintf(stderr, "chpass: %s\n", strerror(EACCES)); 233 exit(1); 234 } 235 236 usage() 237 { 238 #ifdef YP 239 (void)fprintf(stderr, "usage: chpass [-a list] [-s shell] [-l]%s [user]\n", use_yp?" [-y]":""); 240 #else 241 (void)fprintf(stderr, "usage: chpass [-a list] [-s shell] [user]\n"); 242 #endif 243 exit(1); 244 } 245