1 /* $NetBSD: chpass.c,v 1.11 1997/01/05 10:06:40 cjs Exp $ */ 2 3 /*- 4 * Copyright (c) 1988, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #ifndef lint 37 static char copyright[] = 38 "@(#) Copyright (c) 1988, 1993, 1994\n\ 39 The Regents of the University of California. All rights reserved.\n"; 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)chpass.c 8.4 (Berkeley) 4/2/94"; 45 #else 46 static char rcsid[] = "$NetBSD: chpass.c,v 1.11 1997/01/05 10:06:40 cjs Exp $"; 47 #endif 48 #endif /* not lint */ 49 50 #include <sys/param.h> 51 #include <sys/stat.h> 52 #include <sys/time.h> 53 #include <sys/resource.h> 54 55 #include <ctype.h> 56 #include <err.h> 57 #include <errno.h> 58 #include <fcntl.h> 59 #include <pwd.h> 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <string.h> 63 #include <unistd.h> 64 #include <util.h> 65 66 #include "chpass.h" 67 #include "pathnames.h" 68 69 extern char *__progname; /* from crt0.o */ 70 71 char *tempname; 72 uid_t uid; 73 int use_yp; 74 int yflag; 75 76 void (*Pw_error) __P((const char *, int, int)); 77 78 #ifdef YP 79 extern struct passwd *ypgetpwnam(), *ypgetpwuid(); 80 extern int _yp_check __P((char **)); /* buried deep inside libc */ 81 #endif 82 83 void baduser __P((void)); 84 void usage __P((void)); 85 86 int 87 main(argc, argv) 88 int argc; 89 char **argv; 90 { 91 enum { NEWSH, LOADENTRY, EDITENTRY } op; 92 struct passwd *pw, lpw; 93 int ch, pfd, tfd, dfd; 94 char *arg, *username = NULL, tempname[] = "/etc/pw.XXXXXX"; 95 96 #ifdef YP 97 use_yp = _yp_check(NULL); 98 #endif 99 100 op = EDITENTRY; 101 while ((ch = getopt(argc, argv, "a:s:ly")) != EOF) 102 switch(ch) { 103 case 'a': 104 op = LOADENTRY; 105 arg = optarg; 106 break; 107 case 's': 108 op = NEWSH; 109 arg = optarg; 110 break; 111 case 'l': 112 use_yp = 0; 113 break; 114 case 'y': 115 #ifdef YP 116 if (!use_yp) 117 errx(1, "YP not in use."); 118 yflag = 1; 119 #else 120 errx(1, "YP support not compiled in."); 121 #endif 122 break; 123 default: 124 usage(); 125 } 126 argc -= optind; 127 argv += optind; 128 129 uid = getuid(); 130 switch (argc) { 131 case 0: 132 /* nothing */ 133 break; 134 135 case 1: 136 username = argv[0]; 137 break; 138 139 default: 140 usage(); 141 } 142 143 #ifdef YP 144 /* 145 * We need to determine if we _really_ want to use YP. 146 * If we defaulted to YP (i.e. were not given the -y flag), 147 * and the master is not running rpc.yppasswdd, we check 148 * to see if the user exists in the local passwd database. 149 * If so, we use it, otherwise we error out. 150 */ 151 if (use_yp && yflag == 0) { 152 if (check_yppasswdd()) { 153 /* 154 * We weren't able to contact rpc.yppasswdd. 155 * Check to see if we're in the local 156 * password database. If we are, use it. 157 */ 158 if (username != NULL) 159 pw = getpwnam(username); 160 else 161 pw = getpwuid(uid); 162 if (pw != NULL) 163 use_yp = 0; 164 else { 165 errx(1, "master YP server not running yppasswd daemon.\n\t%s\n", 166 "Can't change password."); 167 } 168 } 169 } 170 #endif 171 172 #ifdef YP 173 if (use_yp) 174 Pw_error = yppw_error; 175 else 176 #endif 177 Pw_error = pw_error; 178 179 #ifdef YP 180 if (op == LOADENTRY && use_yp) 181 errx(1, "cannot load entry using YP.\n\tUse the -l flag to load local."); 182 #endif 183 184 if (op == EDITENTRY || op == NEWSH) { 185 if (username != NULL) { 186 #ifdef YP 187 if (use_yp) 188 pw = ypgetpwnam(username); 189 else 190 #endif /* YP */ 191 pw = getpwnam(username); 192 if (pw == NULL) 193 errx(1, "unknown user: %s", username); 194 if (uid && uid != pw->pw_uid) 195 baduser(); 196 } else { 197 #ifdef YP 198 if (use_yp) 199 pw = ypgetpwuid(uid); 200 else 201 #endif /* YP */ 202 pw = getpwuid(uid); 203 if (pw == NULL) 204 errx(1, "unknown user: uid %u\n", uid); 205 } 206 } 207 208 if (op == NEWSH) { 209 /* protect p_shell -- it thinks NULL is /bin/sh */ 210 if (!arg[0]) 211 usage(); 212 if (p_shell(arg, pw, (ENTRY *)NULL)) 213 (*Pw_error)((char *)NULL, 0, 1); 214 } 215 216 if (op == LOADENTRY) { 217 if (uid) 218 baduser(); 219 pw = &lpw; 220 if (!pw_scan(arg, pw, (int *)NULL)) 221 exit(1); 222 } 223 224 if (!use_yp) { 225 /* 226 * Get the passwd lock file and open the passwd file for 227 * reading. 228 */ 229 pw_init(); 230 tfd = pw_lock(0); 231 if (tfd < 0) 232 errx(1, "the passwd file is busy."); 233 pfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); 234 if (pfd < 0) 235 pw_error(_PATH_MASTERPASSWD, 1, 1); 236 } 237 238 /* Edit the user passwd information if requested. */ 239 if (op == EDITENTRY) { 240 dfd = mkstemp(tempname); 241 if (dfd < 0) { 242 (*Pw_error)(tempname, 1, 1); 243 } 244 display(tempname, dfd, pw); 245 edit(tempname, pw); 246 (void)unlink(tempname); 247 } 248 249 #ifdef YP 250 if (use_yp) { 251 if (pw_yp(pw, uid)) 252 yppw_error((char *)NULL, 0, 1); 253 else 254 exit(0); 255 } 256 else 257 #endif /* YP */ 258 259 /* Copy the passwd file to the lock file, updating pw. */ 260 pw_copy(pfd, tfd, pw); 261 262 /* Now finish the passwd file update. */ 263 if (pw_mkdb() < 0) 264 pw_error((char *)NULL, 0, 1); 265 266 exit(0); 267 } 268 269 void 270 baduser() 271 { 272 273 errx(1, "%s", strerror(EACCES)); 274 } 275 276 void 277 usage() 278 { 279 280 #ifdef YP 281 (void)fprintf(stderr, "usage: chpass [-a list] [-s shell] [-l]%s [user]\n", use_yp?" [-y]":""); 282 #else 283 (void)fprintf(stderr, "usage: chpass [-a list] [-s shell] [user]\n"); 284 #endif 285 exit(1); 286 } 287