1 /*- 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1988, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)chpass.c 8.1 (Berkeley) 06/06/93"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/stat.h> 20 #include <sys/signal.h> 21 #include <sys/time.h> 22 #include <sys/resource.h> 23 #include <fcntl.h> 24 #include <pwd.h> 25 #include <errno.h> 26 #include <stdio.h> 27 #include <ctype.h> 28 #include <string.h> 29 #include "chpass.h" 30 #include "pathnames.h" 31 32 char *progname = "chpass"; 33 char *tempname; 34 uid_t uid; 35 36 main(argc, argv) 37 int argc; 38 char **argv; 39 { 40 extern int optind; 41 extern char *optarg; 42 register enum { NEWSH, LOADENTRY, EDITENTRY } op; 43 register struct passwd *pw; 44 struct passwd lpw; 45 int ch, pfd, tfd; 46 char *arg; 47 48 op = EDITENTRY; 49 while ((ch = getopt(argc, argv, "a:s:")) != EOF) 50 switch(ch) { 51 case 'a': 52 op = LOADENTRY; 53 arg = optarg; 54 break; 55 case 's': 56 op = NEWSH; 57 arg = optarg; 58 break; 59 case '?': 60 default: 61 usage(); 62 } 63 argc -= optind; 64 argv += optind; 65 66 uid = getuid(); 67 68 if (op == EDITENTRY || op == NEWSH) 69 switch(argc) { 70 case 0: 71 if (!(pw = getpwuid(uid))) { 72 (void)fprintf(stderr, 73 "chpass: unknown user: uid %u\n", uid); 74 exit(1); 75 } 76 break; 77 case 1: 78 if (!(pw = getpwnam(*argv))) { 79 (void)fprintf(stderr, 80 "chpass: unknown user %s.\n", *argv); 81 exit(1); 82 } 83 if (uid && uid != pw->pw_uid) 84 baduser(); 85 break; 86 default: 87 usage(); 88 } 89 90 if (op == NEWSH) { 91 /* protect p_shell -- it thinks NULL is /bin/sh */ 92 if (!arg[0]) 93 usage(); 94 if (p_shell(arg, pw, (ENTRY *)NULL)) 95 pw_error((char *)NULL, 0, 1); 96 } 97 98 if (op == LOADENTRY) { 99 if (uid) 100 baduser(); 101 pw = &lpw; 102 if (!pw_scan(arg, pw)) 103 exit(1); 104 } 105 106 /* 107 * The temporary file/file descriptor usage is a little tricky here. 108 * 1: We start off with two fd's, one for the master password 109 * file (used to lock everything), and one for a temporary file. 110 * 2: Display() gets an fp for the temporary file, and copies the 111 * user's information into it. It then gives the temporary file 112 * to the user and closes the fp, closing the underlying fd. 113 * 3: The user edits the temporary file some number of times. 114 * 4: Verify() gets an fp for the temporary file, and verifies the 115 * contents. It can't use an fp derived from the step #2 fd, 116 * because the user's editor may have created a new instance of 117 * the file. Once the file is verified, its contents are stored 118 * in a password structure. The verify routine closes the fp, 119 * closing the underlying fd. 120 * 5: Delete the temporary file. 121 * 6: Get a new temporary file/fd. Pw_copy() gets an fp for it 122 * file and copies the master password file into it, replacing 123 * the user record with a new one. We can't use the first 124 * temporary file for this because it was owned by the user. 125 * Pw_copy() closes its fp, flushing the data and closing the 126 * underlying file descriptor. We can't close the master 127 * password fp, or we'd lose the lock. 128 * 7: Call pw_mkdb() (which renames the temporary file) and exit. 129 * The exit closes the master passwd fp/fd. 130 */ 131 pw_init(); 132 pfd = pw_lock(); 133 tfd = pw_tmp(); 134 135 if (op == EDITENTRY) { 136 display(tfd, pw); 137 edit(pw); 138 (void)unlink(tempname); 139 tfd = pw_tmp(); 140 } 141 142 pw_copy(pfd, tfd, pw); 143 144 if (!pw_mkdb()) 145 pw_error((char *)NULL, 0, 1); 146 exit(0); 147 } 148 149 baduser() 150 { 151 (void)fprintf(stderr, "chpass: %s\n", strerror(EACCES)); 152 exit(1); 153 } 154 155 usage() 156 { 157 (void)fprintf(stderr, "usage: chpass [-a list] [-s shell] [user]\n"); 158 exit(1); 159 } 160