1 /*- 2 * Copyright (c) 1991 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)pwd_mkdb.c 5.4 (Berkeley) 03/08/91"; 16 #endif /* not lint */ 17 18 #include <sys/param.h> 19 #include <sys/stat.h> 20 #include <signal.h> 21 #include <fcntl.h> 22 #include <db.h> 23 #include <pwd.h> 24 #include <errno.h> 25 #include <limits.h> 26 #include <stdio.h> 27 #include <string.h> 28 29 #define INSECURE 1 30 #define SECURE 2 31 #define PERM_INSECURE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) 32 #define PERM_SECURE (S_IRUSR|S_IWUSR) 33 34 char *progname = "pwd_mkdb"; 35 36 static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean; 37 static struct passwd pwd; /* password structure */ 38 static char *pname; /* password file name */ 39 40 main(argc, argv) 41 int argc; 42 char **argv; 43 { 44 extern int optind; 45 register int len, makeold; 46 register char *p, *t; 47 FILE *fp, *oldfp; 48 DB *dp, *edp; 49 sigset_t set; 50 DBT data, key; 51 int ch, cnt, tfd; 52 char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024]; 53 54 makeold = 0; 55 while ((ch = getopt(argc, argv, "pv")) != EOF) 56 switch(ch) { 57 case 'p': /* create V7 "file.orig" */ 58 makeold = 1; 59 break; 60 case 'v': /* backward compatible */ 61 break; 62 case '?': 63 default: 64 usage(); 65 } 66 argc -= optind; 67 argv += optind; 68 69 if (argc != 1) 70 usage(); 71 72 /* 73 * This could be done to allow the user to interrupt. Probably 74 * not worth the effort. 75 */ 76 sigemptyset(&set); 77 sigaddset(&set, SIGTSTP); 78 sigaddset(&set, SIGHUP); 79 sigaddset(&set, SIGINT); 80 sigaddset(&set, SIGQUIT); 81 sigaddset(&set, SIGTERM); 82 (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL); 83 84 pname = *argv; 85 /* Open the original password file */ 86 if (!(fp = fopen(pname, "r"))) 87 error(pname); 88 89 /* Open the temporary insecure password database. */ 90 (void)sprintf(buf, "%s.tmp", _PATH_MP_DB); 91 dp = hash_open(buf, O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE, NULL); 92 if (!dp) 93 error(buf); 94 clean = FILE_INSECURE; 95 96 /* Open the temporary encrypted password database. */ 97 (void)sprintf(buf, "%s.tmp", _PATH_SMP_DB); 98 edp = hash_open(buf, O_WRONLY|O_CREAT|O_EXCL, PERM_SECURE, NULL); 99 if (!edp) 100 error(buf); 101 clean = FILE_SECURE; 102 103 /* 104 * Open file for old password file. Minor trickiness -- don't want to 105 * chance the file already existing, since someone (stupidly) might 106 * still be using this for permission checking. So, open it first and 107 * fdopen the resulting fd. Don't really care who reads it. 108 */ 109 if (makeold) { 110 (void)sprintf(buf, "%s.orig", pname); 111 if ((tfd = open(buf, 112 O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0) 113 error(buf); 114 if (!(oldfp = fdopen(tfd, "w"))) 115 error(buf); 116 clean = FILE_ORIG; 117 } 118 119 data.data = (u_char *)buf; 120 key.data = (u_char *)tbuf; 121 for (cnt = 1; scan(fp, &pwd); ++cnt) { 122 #define COMPACT(e) t = e; while (*p++ = *t++); 123 /* Create insecure data. */ 124 p = buf; 125 COMPACT(pwd.pw_name); 126 COMPACT("*"); 127 bcopy((char *)&pwd.pw_uid, p, sizeof(int)); 128 p += sizeof(int); 129 bcopy((char *)&pwd.pw_gid, p, sizeof(int)); 130 p += sizeof(int); 131 bcopy((char *)&pwd.pw_change, p, sizeof(time_t)); 132 p += sizeof(time_t); 133 COMPACT(pwd.pw_class); 134 COMPACT(pwd.pw_gecos); 135 COMPACT(pwd.pw_dir); 136 COMPACT(pwd.pw_shell); 137 bcopy((char *)&pwd.pw_expire, p, sizeof(time_t)); 138 p += sizeof(time_t); 139 data.size = p - buf; 140 141 /* Store insecure by name. */ 142 tbuf[0] = _PW_KEYBYNAME; 143 len = strlen(pwd.pw_name); 144 bcopy(pwd.pw_name, tbuf + 1, len); 145 key.size = len + 1; 146 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 147 error("put"); 148 149 /* Store insecure by number. */ 150 tbuf[0] = _PW_KEYBYNUM; 151 bcopy((char *)&cnt, tbuf + 1, sizeof(cnt)); 152 key.size = sizeof(cnt) + 1; 153 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 154 error("put"); 155 156 /* Store insecure by uid. */ 157 tbuf[0] = _PW_KEYBYUID; 158 bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid)); 159 key.size = sizeof(pwd.pw_uid) + 1; 160 if ((dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1) 161 error("put"); 162 163 /* Create secure data. */ 164 p = buf; 165 COMPACT(pwd.pw_name); 166 COMPACT(pwd.pw_passwd); 167 bcopy((char *)&pwd.pw_uid, p, sizeof(int)); 168 p += sizeof(int); 169 bcopy((char *)&pwd.pw_gid, p, sizeof(int)); 170 p += sizeof(int); 171 bcopy((char *)&pwd.pw_change, p, sizeof(time_t)); 172 p += sizeof(time_t); 173 COMPACT(pwd.pw_class); 174 COMPACT(pwd.pw_gecos); 175 COMPACT(pwd.pw_dir); 176 COMPACT(pwd.pw_shell); 177 bcopy((char *)&pwd.pw_expire, p, sizeof(time_t)); 178 p += sizeof(time_t); 179 data.size = p - buf; 180 181 /* Store secure by name. */ 182 tbuf[0] = _PW_KEYBYNAME; 183 len = strlen(pwd.pw_name); 184 bcopy(pwd.pw_name, tbuf + 1, len); 185 key.size = len + 1; 186 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) 187 error("put"); 188 189 /* Store secure by number. */ 190 tbuf[0] = _PW_KEYBYNUM; 191 bcopy((char *)&cnt, tbuf + 1, sizeof(cnt)); 192 key.size = sizeof(cnt) + 1; 193 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) 194 error("put"); 195 196 /* Store secure by uid. */ 197 tbuf[0] = _PW_KEYBYUID; 198 bcopy((char *)&pwd.pw_uid, tbuf + 1, sizeof(pwd.pw_uid)); 199 key.size = sizeof(pwd.pw_uid) + 1; 200 if ((dp->put)(edp, &key, &data, R_NOOVERWRITE) == -1) 201 error("put"); 202 203 /* Create original format password file entry */ 204 if (makeold) 205 (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n", 206 pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos, 207 pwd.pw_dir, pwd.pw_shell); 208 } 209 (void)(dp->close)(dp); 210 (void)(edp->close)(edp); 211 if (makeold) { 212 (void)fsync(oldfp); 213 (void)fclose(oldfp); 214 } 215 216 /* Set master.passwd permissions, in case caller forgot. */ 217 (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR); 218 (void)fclose(fp); 219 220 /* Install as the real password files. */ 221 (void)sprintf(buf, "%s.tmp", _PATH_MP_DB); 222 mv(buf, _PATH_MP_DB); 223 (void)sprintf(buf, "%s.tmp", _PATH_SMP_DB); 224 mv(buf, _PATH_SMP_DB); 225 if (makeold) { 226 (void)sprintf(buf, "%s.orig", pname); 227 mv(buf, _PATH_PASSWD); 228 } 229 /* 230 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8) 231 * all use flock(2) on it to block other incarnations of themselves. 232 * The rename means that everything is unlocked, as the original file 233 * can no longer be accessed. 234 */ 235 mv(pname, _PATH_MASTERPASSWD); 236 exit(0); 237 } 238 239 scan(fp, pw) 240 FILE *fp; 241 struct passwd *pw; 242 { 243 static int lcnt; 244 static char line[LINE_MAX]; 245 char *p; 246 247 if (!fgets(line, sizeof(line), fp)) 248 return(0); 249 ++lcnt; 250 /* 251 * ``... if I swallow anything evil, put your fingers down my 252 * throat...'' 253 * -- The Who 254 */ 255 if (!(p = index(line, '\n'))) { 256 (void)fprintf(stderr, "pwd_mkdb: line too long\n"); 257 goto fmt; 258 259 } 260 *p = '\0'; 261 if (!pw_scan(line, pw)) { 262 (void)fprintf(stderr, "pwd_mkdb: at line #%d.\n", lcnt); 263 fmt: errno = EFTYPE; 264 error(pname); 265 exit(1); 266 } 267 } 268 269 mv(from, to) 270 char *from, *to; 271 { 272 int sverrno; 273 char buf[MAXPATHLEN]; 274 275 if (rename(from, to)) { 276 sverrno = errno; 277 (void)sprintf(buf, "%s to %s", from, to); 278 errno = sverrno; 279 error(buf); 280 } 281 } 282 283 error(name) 284 char *name; 285 { 286 (void)fprintf(stderr, "pwd_mkdb: %s: %s\n", name, strerror(errno)); 287 cleanup(); 288 exit(1); 289 } 290 291 cleanup() 292 { 293 char buf[MAXPATHLEN]; 294 295 switch(clean) { 296 case FILE_ORIG: 297 (void)sprintf(buf, "%s.orig", pname); 298 (void)unlink(buf); 299 /* FALLTHROUGH */ 300 case FILE_SECURE: 301 (void)sprintf(buf, "%s.tmp", _PATH_SMP_DB); 302 (void)unlink(buf); 303 /* FALLTHROUGH */ 304 case FILE_INSECURE: 305 (void)sprintf(buf, "%s.tmp", _PATH_MP_DB); 306 (void)unlink(buf); 307 } 308 } 309 310 usage() 311 { 312 (void)fprintf(stderr, "usage: pwd_mkdb [-p] file\n"); 313 exit(1); 314 } 315