1 1.61 christos /* $NetBSD: pwd_mkdb.c,v 1.61 2024/10/04 20:32:20 christos Exp $ */ 2 1.36 jmmv 3 1.36 jmmv /* 4 1.36 jmmv * Copyright (c) 2000, 2009 The NetBSD Foundation, Inc. 5 1.36 jmmv * All rights reserved. 6 1.36 jmmv * 7 1.36 jmmv * Redistribution and use in source and binary forms, with or without 8 1.36 jmmv * modification, are permitted provided that the following conditions 9 1.36 jmmv * are met: 10 1.36 jmmv * 1. Redistributions of source code must retain the above copyright 11 1.36 jmmv * notice, this list of conditions and the following disclaimer. 12 1.36 jmmv * 2. Redistributions in binary form must reproduce the above copyright 13 1.36 jmmv * notice, this list of conditions and the following disclaimer in the 14 1.36 jmmv * documentation and/or other materials provided with the distribution. 15 1.36 jmmv * 16 1.36 jmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.36 jmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.36 jmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.36 jmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.36 jmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.36 jmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.36 jmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.36 jmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.36 jmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.36 jmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.36 jmmv * POSSIBILITY OF SUCH DAMAGE. 27 1.36 jmmv */ 28 1.19 ad 29 1.11 fair /* 30 1.5 mycroft * Copyright (c) 1991, 1993, 1994 31 1.5 mycroft * The Regents of the University of California. All rights reserved. 32 1.26 agc * 33 1.26 agc * Redistribution and use in source and binary forms, with or without 34 1.26 agc * modification, are permitted provided that the following conditions 35 1.26 agc * are met: 36 1.26 agc * 1. Redistributions of source code must retain the above copyright 37 1.26 agc * notice, this list of conditions and the following disclaimer. 38 1.26 agc * 2. Redistributions in binary form must reproduce the above copyright 39 1.26 agc * notice, this list of conditions and the following disclaimer in the 40 1.26 agc * documentation and/or other materials provided with the distribution. 41 1.26 agc * 3. Neither the name of the University nor the names of its contributors 42 1.26 agc * may be used to endorse or promote products derived from this software 43 1.26 agc * without specific prior written permission. 44 1.26 agc * 45 1.26 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 46 1.26 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 47 1.26 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 48 1.26 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 49 1.26 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 50 1.26 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 51 1.26 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 52 1.26 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 53 1.26 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 54 1.26 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 55 1.26 agc * SUCH DAMAGE. 56 1.26 agc */ 57 1.26 agc 58 1.26 agc /* 59 1.6 phil * Portions Copyright(C) 1994, Jason Downs. All rights reserved. 60 1.1 cgd * 61 1.1 cgd * Redistribution and use in source and binary forms, with or without 62 1.1 cgd * modification, are permitted provided that the following conditions 63 1.1 cgd * are met: 64 1.1 cgd * 1. Redistributions of source code must retain the above copyright 65 1.1 cgd * notice, this list of conditions and the following disclaimer. 66 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 67 1.1 cgd * notice, this list of conditions and the following disclaimer in the 68 1.1 cgd * documentation and/or other materials provided with the distribution. 69 1.1 cgd * 70 1.27 agc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 71 1.27 agc * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 72 1.27 agc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 73 1.27 agc * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 74 1.27 agc * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 75 1.27 agc * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 76 1.27 agc * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 77 1.27 agc * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 78 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 79 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 80 1.1 cgd * SUCH DAMAGE. 81 1.1 cgd */ 82 1.1 cgd 83 1.28 lukem #if HAVE_NBTOOL_CONFIG_H 84 1.28 lukem #include "nbtool_config.h" 85 1.23 tv #endif 86 1.23 tv 87 1.10 lukem #include <sys/cdefs.h> 88 1.28 lukem #if !defined(lint) 89 1.36 jmmv __COPYRIGHT("@(#) Copyright (c) 2000, 2009\ 90 1.34 lukem The NetBSD Foundation, Inc. All rights reserved.\ 91 1.34 lukem Copyright (c) 1991, 1993, 1994\ 92 1.34 lukem The Regents of the University of California. All rights reserved."); 93 1.61 christos __RCSID("$NetBSD: pwd_mkdb.c,v 1.61 2024/10/04 20:32:20 christos Exp $"); 94 1.1 cgd #endif /* not lint */ 95 1.1 cgd 96 1.29 jmc #if HAVE_NBTOOL_CONFIG_H 97 1.29 jmc #include "compat_pwd.h" 98 1.29 jmc #else 99 1.29 jmc #include <pwd.h> 100 1.29 jmc #endif 101 1.29 jmc 102 1.1 cgd #include <sys/param.h> 103 1.1 cgd #include <sys/stat.h> 104 1.39 apb #include <sys/types.h> 105 1.39 apb 106 1.39 apb #ifndef HAVE_NBTOOL_CONFIG_H 107 1.39 apb #include <machine/bswap.h> 108 1.39 apb #endif 109 1.5 mycroft 110 1.1 cgd #include <db.h> 111 1.24 tv #include <err.h> 112 1.1 cgd #include <errno.h> 113 1.5 mycroft #include <fcntl.h> 114 1.52 christos #include <syslog.h> 115 1.1 cgd #include <limits.h> 116 1.5 mycroft #include <signal.h> 117 1.1 cgd #include <stdio.h> 118 1.5 mycroft #include <stdlib.h> 119 1.52 christos #include <stdarg.h> 120 1.1 cgd #include <string.h> 121 1.5 mycroft #include <unistd.h> 122 1.56 pooka 123 1.56 pooka #ifndef HAVE_NBTOOL_CONFIG_H 124 1.24 tv #include <util.h> 125 1.56 pooka #endif 126 1.23 tv 127 1.22 ad #define MAX_CACHESIZE 8*1024*1024 128 1.22 ad #define MIN_CACHESIZE 2*1024*1024 129 1.22 ad 130 1.19 ad #define PERM_INSECURE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) 131 1.19 ad #define PERM_SECURE (S_IRUSR | S_IWUSR) 132 1.1 cgd 133 1.60 christos // Defined in libc 134 1.23 tv static const char __yp_token[] = "__YP!"; 135 1.6 phil 136 1.41 christos static HASHINFO openinfo = { 137 1.5 mycroft 4096, /* bsize */ 138 1.5 mycroft 32, /* ffactor */ 139 1.5 mycroft 256, /* nelem */ 140 1.22 ad 0, /* cachesize */ 141 1.5 mycroft NULL, /* hash() */ 142 1.5 mycroft 0 /* lorder */ 143 1.5 mycroft }; 144 1.1 cgd 145 1.22 ad #define FILE_INSECURE 0x01 146 1.22 ad #define FILE_SECURE 0x02 147 1.22 ad #define FILE_ORIG 0x04 148 1.22 ad 149 1.42 christos 150 1.42 christos struct pwddb { 151 1.42 christos DB *db; 152 1.42 christos char dbname[MAX(MAXPATHLEN, LINE_MAX * 2)]; 153 1.42 christos const char *fname; 154 1.42 christos uint32_t rversion; 155 1.42 christos uint32_t wversion; 156 1.42 christos }; 157 1.42 christos 158 1.22 ad static char *pname; /* password file name */ 159 1.22 ad static char prefix[MAXPATHLEN]; 160 1.22 ad static char oldpwdfile[MAX(MAXPATHLEN, LINE_MAX * 2)]; 161 1.22 ad static int lorder = BYTE_ORDER; 162 1.52 christos static int logsyslog; 163 1.22 ad static int clean; 164 1.42 christos static int verbose; 165 1.42 christos static int warning; 166 1.42 christos static struct pwddb sdb, idb; 167 1.42 christos 168 1.22 ad 169 1.61 christos static void bailout(void) __dead; 170 1.61 christos static void cp(const char *, const char *, mode_t); 171 1.61 christos static void deldbent(struct pwddb *, int, void *); 172 1.61 christos static void mkpw_error(const char *, ...) __dead; 173 1.61 christos static void mkpw_warning(const char *, ...); 174 1.61 christos static int getdbent(struct pwddb *, int, void *, struct passwd **); 175 1.61 christos static void inconsistency(void) __dead; 176 1.61 christos static void install(const char *, const char *); 177 1.61 christos static void putdbents(struct pwddb *, struct passwd *, const char *, int, 178 1.61 christos int, u_int, u_int); 179 1.61 christos static void putyptoken(struct pwddb *); 180 1.61 christos static void rm(const char *); 181 1.61 christos static int scan(FILE *, struct passwd *, int *, int *); 182 1.61 christos static void usage(void) __dead; 183 1.61 christos static void wr_error(const char *) __dead; 184 1.61 christos static uint32_t getversion(const char *); 185 1.61 christos static void setversion(struct pwddb *); 186 1.35 christos 187 1.44 christos #ifndef __lint__ 188 1.35 christos #define SWAP(sw) \ 189 1.39 apb ((sizeof(sw) == 2 ? (typeof(sw))bswap16((uint16_t)sw) : \ 190 1.39 apb (sizeof(sw) == 4 ? (typeof(sw))bswap32((uint32_t)sw) : \ 191 1.39 apb (sizeof(sw) == 8 ? (typeof(sw))bswap64((uint64_t)sw) : (abort(), 0))))) 192 1.44 christos #else 193 1.44 christos #define SWAP(sw) sw 194 1.44 christos #endif 195 1.5 mycroft 196 1.42 christos static void 197 1.42 christos closedb(struct pwddb *db) 198 1.42 christos { 199 1.42 christos if ((*db->db->close)(db->db) < 0) 200 1.42 christos wr_error(db->dbname); 201 1.42 christos } 202 1.42 christos 203 1.42 christos static void 204 1.42 christos opendb(struct pwddb *db, const char *dbname, const char *username, 205 1.44 christos uint32_t req_version, int flags, mode_t perm) 206 1.42 christos { 207 1.42 christos char buf[MAXPATHLEN]; 208 1.42 christos 209 1.42 christos (void)snprintf(db->dbname, sizeof(db->dbname), "%s%s.tmp", prefix, 210 1.42 christos dbname); 211 1.42 christos 212 1.42 christos if (username != NULL) { 213 1.44 christos (void)snprintf(buf, sizeof(buf), "%s%s", prefix, dbname); 214 1.42 christos cp(buf, db->dbname, perm); 215 1.42 christos } 216 1.42 christos 217 1.42 christos db->db = dbopen(db->dbname, flags, perm, DB_HASH, &openinfo); 218 1.42 christos if (db->db == NULL) 219 1.52 christos mkpw_error("Cannot open `%s'", db->dbname); 220 1.42 christos 221 1.42 christos db->fname = dbname; 222 1.42 christos db->rversion = getversion(dbname); 223 1.42 christos if (req_version == ~0U) 224 1.42 christos db->wversion = db->rversion; 225 1.42 christos else 226 1.42 christos db->wversion = req_version; 227 1.42 christos 228 1.42 christos if (warning && db->rversion == 0 && db->wversion == 0) { 229 1.52 christos mkpw_warning("Database %s is a version %u database.", 230 1.42 christos db->fname, db->rversion); 231 1.52 christos mkpw_warning("Use %s -V 1 to upgrade once you've recompiled " 232 1.42 christos "all your binaries.", getprogname()); 233 1.42 christos } 234 1.42 christos if (db->wversion != db->rversion) { 235 1.44 christos if (username != NULL) { 236 1.52 christos mkpw_warning("You cannot change a single " 237 1.44 christos "record from version %u to version %u\n", 238 1.52 christos db->rversion, db->wversion); 239 1.44 christos bailout(); 240 1.44 christos } else if (verbose) { 241 1.52 christos mkpw_warning("Changing %s from version %u to version %u", 242 1.52 christos db->fname, db->rversion, db->wversion); 243 1.42 christos } 244 1.44 christos } else { 245 1.44 christos if (verbose) 246 1.52 christos mkpw_warning("File `%s' version %u requested %u", 247 1.52 christos db->fname, db->rversion, db->wversion); 248 1.42 christos } 249 1.44 christos 250 1.42 christos setversion(db); 251 1.42 christos } 252 1.42 christos 253 1.5 mycroft int 254 1.19 ad main(int argc, char *argv[]) 255 1.1 cgd { 256 1.42 christos int ch, makeold, tfd, lineno, found, rv, hasyp, secureonly; 257 1.22 ad struct passwd pwd, *tpwd; 258 1.22 ad char *username; 259 1.1 cgd FILE *fp, *oldfp; 260 1.1 cgd sigset_t set; 261 1.44 christos u_int dbflg, uid_dbflg; 262 1.44 christos int newuser, olduid, flags; 263 1.22 ad struct stat st; 264 1.22 ad u_int cachesize; 265 1.42 christos uint32_t req_version; 266 1.1 cgd 267 1.21 tron prefix[0] = '\0'; 268 1.1 cgd makeold = 0; 269 1.22 ad oldfp = NULL; 270 1.22 ad username = NULL; 271 1.22 ad hasyp = 0; 272 1.22 ad secureonly = 0; 273 1.30 lukem found = 0; 274 1.30 lukem newuser = 0; 275 1.31 sketch cachesize = 0; 276 1.41 christos verbose = 0; 277 1.42 christos warning = 0; 278 1.52 christos logsyslog = 0; 279 1.42 christos req_version = ~0U; 280 1.22 ad 281 1.52 christos while ((ch = getopt(argc, argv, "BLc:d:lpsu:V:vw")) != -1) 282 1.22 ad switch (ch) { 283 1.22 ad case 'B': /* big-endian output */ 284 1.22 ad lorder = BIG_ENDIAN; 285 1.22 ad break; 286 1.22 ad case 'L': /* little-endian output */ 287 1.22 ad lorder = LITTLE_ENDIAN; 288 1.22 ad break; 289 1.31 sketch case 'c': 290 1.31 sketch cachesize = atoi(optarg) * 1024 * 1024; 291 1.31 sketch break; 292 1.19 ad case 'd': /* set prefix */ 293 1.44 christos (void)strlcpy(prefix, optarg, sizeof(prefix)); 294 1.8 lukem break; 295 1.52 christos case 'l': 296 1.52 christos openlog(getprogname(), LOG_PID, LOG_AUTH); 297 1.52 christos logsyslog = 1; 298 1.52 christos break; 299 1.1 cgd case 'p': /* create V7 "file.orig" */ 300 1.1 cgd makeold = 1; 301 1.1 cgd break; 302 1.22 ad case 's': /* modify secure db only */ 303 1.22 ad secureonly = 1; 304 1.1 cgd break; 305 1.22 ad case 'u': /* modify one user only */ 306 1.22 ad username = optarg; 307 1.17 mycroft break; 308 1.41 christos case 'V': 309 1.42 christos req_version = (uint32_t)atoi(optarg); 310 1.52 christos if (req_version > 1) { 311 1.52 christos mkpw_warning("Unknown version %u", req_version); 312 1.52 christos return EXIT_FAILURE; 313 1.52 christos } 314 1.41 christos break; 315 1.41 christos case 'v': 316 1.41 christos verbose++; 317 1.17 mycroft break; 318 1.42 christos case 'w': 319 1.42 christos warning++; 320 1.42 christos break; 321 1.1 cgd case '?': 322 1.1 cgd default: 323 1.1 cgd usage(); 324 1.1 cgd } 325 1.1 cgd argc -= optind; 326 1.1 cgd argv += optind; 327 1.1 cgd 328 1.1 cgd if (argc != 1) 329 1.1 cgd usage(); 330 1.22 ad if (username != NULL) 331 1.22 ad if (username[0] == '+' || username[0] == '-') 332 1.22 ad usage(); 333 1.22 ad if (secureonly) 334 1.22 ad makeold = 0; 335 1.4 cgd 336 1.1 cgd /* 337 1.5 mycroft * This could be changed to allow the user to interrupt. 338 1.5 mycroft * Probably not worth the effort. 339 1.1 cgd */ 340 1.44 christos (void)sigemptyset(&set); 341 1.44 christos (void)sigaddset(&set, SIGTSTP); 342 1.44 christos (void)sigaddset(&set, SIGHUP); 343 1.44 christos (void)sigaddset(&set, SIGINT); 344 1.44 christos (void)sigaddset(&set, SIGQUIT); 345 1.44 christos (void)sigaddset(&set, SIGTERM); 346 1.55 plunky (void)sigprocmask(SIG_BLOCK, &set, NULL); 347 1.1 cgd 348 1.5 mycroft /* We don't care what the user wants. */ 349 1.5 mycroft (void)umask(0); 350 1.5 mycroft 351 1.22 ad if (username == NULL) 352 1.22 ad flags = O_RDWR | O_CREAT | O_EXCL; 353 1.22 ad else 354 1.22 ad flags = O_RDWR; 355 1.22 ad 356 1.1 cgd pname = *argv; 357 1.1 cgd /* Open the original password file */ 358 1.19 ad if ((fp = fopen(pname, "r")) == NULL) 359 1.52 christos mkpw_error("Cannot open `%s'", pname); 360 1.1 cgd 361 1.17 mycroft openinfo.lorder = lorder; 362 1.17 mycroft 363 1.22 ad if (fstat(fileno(fp), &st) == -1) 364 1.52 christos mkpw_error("Cannot stat `%s'", pname); 365 1.22 ad 366 1.31 sketch if (cachesize) { 367 1.31 sketch openinfo.cachesize = cachesize; 368 1.31 sketch } else { 369 1.31 sketch /* Tweak openinfo values for large passwd files. */ 370 1.44 christos cachesize = (u_int)(st.st_size * 20); 371 1.31 sketch if (cachesize > MAX_CACHESIZE) 372 1.31 sketch cachesize = MAX_CACHESIZE; 373 1.31 sketch else if (cachesize < MIN_CACHESIZE) 374 1.31 sketch cachesize = MIN_CACHESIZE; 375 1.31 sketch openinfo.cachesize = cachesize; 376 1.31 sketch } 377 1.22 ad 378 1.1 cgd /* Open the temporary insecure password database. */ 379 1.22 ad if (!secureonly) { 380 1.42 christos opendb(&idb, _PATH_MP_DB, username, req_version, 381 1.42 christos flags, PERM_INSECURE); 382 1.22 ad clean |= FILE_INSECURE; 383 1.22 ad } 384 1.61 christos 385 1.22 ad 386 1.22 ad /* Open the temporary encrypted password database. */ 387 1.42 christos opendb(&sdb, _PATH_SMP_DB, username, req_version, flags, PERM_SECURE); 388 1.22 ad clean |= FILE_SECURE; 389 1.1 cgd 390 1.1 cgd /* 391 1.1 cgd * Open file for old password file. Minor trickiness -- don't want to 392 1.1 cgd * chance the file already existing, since someone (stupidly) might 393 1.1 cgd * still be using this for permission checking. So, open it first and 394 1.5 mycroft * fdopen the resulting fd. The resulting file should be readable by 395 1.5 mycroft * everyone. 396 1.1 cgd */ 397 1.1 cgd if (makeold) { 398 1.11 fair (void)snprintf(oldpwdfile, sizeof(oldpwdfile), "%s.orig", 399 1.19 ad pname); 400 1.19 ad if ((tfd = open(oldpwdfile, O_WRONLY | O_CREAT | O_EXCL, 401 1.19 ad PERM_INSECURE)) < 0) 402 1.52 christos mkpw_error("Cannot create `%s'", oldpwdfile); 403 1.22 ad clean |= FILE_ORIG; 404 1.5 mycroft if ((oldfp = fdopen(tfd, "w")) == NULL) 405 1.52 christos mkpw_error("Cannot fdopen `%s'", oldpwdfile); 406 1.22 ad } 407 1.22 ad 408 1.22 ad if (username != NULL) { 409 1.22 ad uid_dbflg = 0; 410 1.22 ad dbflg = 0; 411 1.22 ad 412 1.22 ad /* 413 1.22 ad * Determine if this is a new entry. 414 1.22 ad */ 415 1.42 christos if (getdbent(&sdb, _PW_KEYBYNAME, username, &tpwd)) 416 1.22 ad newuser = 1; 417 1.22 ad else { 418 1.22 ad newuser = 0; 419 1.22 ad olduid = tpwd->pw_uid; 420 1.22 ad } 421 1.22 ad 422 1.22 ad } else { 423 1.22 ad uid_dbflg = R_NOOVERWRITE; 424 1.22 ad dbflg = R_NOOVERWRITE; 425 1.1 cgd } 426 1.1 cgd 427 1.1 cgd /* 428 1.6 phil * If we see something go by that looks like YP, we save a special 429 1.6 phil * pointer record, which if YP is enabled in the C lib, will speed 430 1.6 phil * things up. 431 1.1 cgd */ 432 1.19 ad for (lineno = 0; scan(fp, &pwd, &flags, &lineno);) { 433 1.9 thorpej /* 434 1.22 ad * Create original format password file entry. 435 1.9 thorpej */ 436 1.11 fair if (makeold) { 437 1.5 mycroft (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n", 438 1.5 mycroft pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos, 439 1.5 mycroft pwd.pw_dir, pwd.pw_shell); 440 1.19 ad if (ferror(oldfp)) 441 1.11 fair wr_error(oldpwdfile); 442 1.11 fair } 443 1.22 ad 444 1.22 ad if (username == NULL) { 445 1.22 ad /* Look like YP? */ 446 1.22 ad if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') 447 1.22 ad hasyp++; 448 1.22 ad 449 1.22 ad /* Warn about potentially unsafe uid/gid overrides. */ 450 1.22 ad if (pwd.pw_name[0] == '+') { 451 1.22 ad if ((flags & _PASSWORD_NOUID) == 0 && 452 1.22 ad pwd.pw_uid == 0) 453 1.52 christos mkpw_warning("line %d: superuser " 454 1.52 christos "override in YP inclusion", lineno); 455 1.22 ad if ((flags & _PASSWORD_NOGID) == 0 && 456 1.22 ad pwd.pw_gid == 0) 457 1.52 christos mkpw_warning("line %d: wheel override " 458 1.22 ad "in YP inclusion", lineno); 459 1.22 ad } 460 1.22 ad 461 1.22 ad /* Write the database entry out. */ 462 1.22 ad if (!secureonly) 463 1.42 christos putdbents(&idb, &pwd, "*", flags, lineno, dbflg, 464 1.42 christos uid_dbflg); 465 1.22 ad continue; 466 1.22 ad } else if (strcmp(username, pwd.pw_name) != 0) 467 1.22 ad continue; 468 1.22 ad 469 1.22 ad if (found) { 470 1.52 christos mkpw_warning("user `%s' listed twice in password file", 471 1.22 ad username); 472 1.22 ad bailout(); 473 1.22 ad } 474 1.22 ad 475 1.22 ad /* 476 1.22 ad * Ensure that the text file and database agree on 477 1.22 ad * which line the record is from. 478 1.22 ad */ 479 1.42 christos rv = getdbent(&sdb, _PW_KEYBYNUM, &lineno, &tpwd); 480 1.22 ad if (newuser) { 481 1.22 ad if (rv == 0) 482 1.44 christos inconsistency(); 483 1.48 enami } else if (rv == 1 || strcmp(username, tpwd->pw_name) != 0) 484 1.44 christos inconsistency(); 485 1.40 lukem else if ((uid_t)olduid != pwd.pw_uid) { 486 1.22 ad /* 487 1.22 ad * If we're changing UID, remove the BYUID 488 1.22 ad * record for the old UID only if it has the 489 1.22 ad * same username. 490 1.22 ad */ 491 1.42 christos if (!getdbent(&sdb, _PW_KEYBYUID, &olduid, &tpwd)) { 492 1.22 ad if (strcmp(username, tpwd->pw_name) == 0) { 493 1.22 ad if (!secureonly) 494 1.42 christos deldbent(&idb, _PW_KEYBYUID, 495 1.42 christos &olduid); 496 1.42 christos deldbent(&sdb, _PW_KEYBYUID, &olduid); 497 1.22 ad } 498 1.22 ad } else 499 1.44 christos inconsistency(); 500 1.22 ad } 501 1.22 ad 502 1.22 ad /* 503 1.22 ad * If there's an existing BYUID record for the new UID and 504 1.22 ad * the username doesn't match then be sure not to overwrite 505 1.22 ad * it. 506 1.22 ad */ 507 1.42 christos if (!getdbent(&sdb, _PW_KEYBYUID, &pwd.pw_uid, &tpwd)) 508 1.22 ad if (strcmp(username, tpwd->pw_name) != 0) 509 1.22 ad uid_dbflg = R_NOOVERWRITE; 510 1.22 ad 511 1.22 ad /* Write the database entries out */ 512 1.22 ad if (!secureonly) 513 1.42 christos putdbents(&idb, &pwd, "*", flags, lineno, dbflg, 514 1.42 christos uid_dbflg); 515 1.42 christos putdbents(&sdb, &pwd, pwd.pw_passwd, flags, lineno, dbflg, 516 1.42 christos uid_dbflg); 517 1.22 ad 518 1.22 ad found = 1; 519 1.22 ad if (!makeold) 520 1.22 ad break; 521 1.22 ad } 522 1.22 ad 523 1.22 ad if (!secureonly) { 524 1.22 ad /* Store YP token if needed. */ 525 1.22 ad if (hasyp) 526 1.42 christos putyptoken(&idb); 527 1.22 ad 528 1.22 ad /* Close the insecure database. */ 529 1.42 christos closedb(&idb); 530 1.22 ad } 531 1.22 ad 532 1.22 ad /* 533 1.22 ad * If rebuilding the databases, we re-parse the text file and write 534 1.22 ad * the secure entries out in a separate pass. 535 1.22 ad */ 536 1.22 ad if (username == NULL) { 537 1.22 ad rewind(fp); 538 1.22 ad for (lineno = 0; scan(fp, &pwd, &flags, &lineno);) 539 1.42 christos putdbents(&sdb, &pwd, pwd.pw_passwd, flags, 540 1.42 christos lineno, dbflg, uid_dbflg); 541 1.22 ad 542 1.22 ad /* Store YP token if needed. */ 543 1.22 ad if (hasyp) 544 1.42 christos putyptoken(&sdb); 545 1.22 ad } else if (!found) { 546 1.52 christos mkpw_warning("user `%s' not found in password file", username); 547 1.22 ad bailout(); 548 1.5 mycroft } 549 1.6 phil 550 1.22 ad /* Close the secure database. */ 551 1.42 christos closedb(&sdb); 552 1.22 ad 553 1.22 ad /* Install as the real password files. */ 554 1.22 ad if (!secureonly) 555 1.42 christos install(idb.dbname, idb.fname); 556 1.42 christos install(sdb.dbname, sdb.fname); 557 1.6 phil 558 1.22 ad /* Install the V7 password file. */ 559 1.5 mycroft if (makeold) { 560 1.19 ad if (fflush(oldfp) == EOF) 561 1.11 fair wr_error(oldpwdfile); 562 1.19 ad if (fclose(oldfp) == EOF) 563 1.11 fair wr_error(oldpwdfile); 564 1.22 ad install(oldpwdfile, _PATH_PASSWD); 565 1.5 mycroft } 566 1.5 mycroft 567 1.1 cgd /* Set master.passwd permissions, in case caller forgot. */ 568 1.1 cgd (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR); 569 1.19 ad if (fclose(fp) == EOF) 570 1.11 fair wr_error(pname); 571 1.1 cgd 572 1.19 ad /* 573 1.22 ad * Move the temporary master password file LAST -- chpass(1), 574 1.33 wiz * passwd(1), vipw(8) and friends all use its existence to block 575 1.22 ad * other incarnations of themselves. The rename means that 576 1.22 ad * everything is unlocked, as the original file can no longer be 577 1.22 ad * accessed. 578 1.19 ad */ 579 1.19 ad install(pname, _PATH_MASTERPASSWD); 580 1.19 ad exit(EXIT_SUCCESS); 581 1.19 ad /* NOTREACHED */ 582 1.1 cgd } 583 1.1 cgd 584 1.61 christos static int 585 1.19 ad scan(FILE *fp, struct passwd *pw, int *flags, int *lineno) 586 1.1 cgd { 587 1.1 cgd static char line[LINE_MAX]; 588 1.1 cgd char *p; 589 1.17 mycroft int oflags; 590 1.1 cgd 591 1.44 christos if (fgets(line, (int)sizeof(line), fp) == NULL) 592 1.5 mycroft return (0); 593 1.19 ad (*lineno)++; 594 1.19 ad 595 1.1 cgd /* 596 1.1 cgd * ``... if I swallow anything evil, put your fingers down my 597 1.1 cgd * throat...'' 598 1.1 cgd * -- The Who 599 1.1 cgd */ 600 1.19 ad if ((p = strchr(line, '\n')) == NULL) { 601 1.19 ad errno = EFTYPE; /* XXX */ 602 1.52 christos mkpw_error("%s, %d: line too long", pname, *lineno); 603 1.1 cgd } 604 1.1 cgd *p = '\0'; 605 1.44 christos if (strcmp(line, "+") == 0) { 606 1.44 christos /* pw_scan() can't handle "+" */ 607 1.44 christos (void)strcpy(line, "+:::::::::"); 608 1.44 christos } 609 1.17 mycroft oflags = 0; 610 1.17 mycroft if (!pw_scan(line, pw, &oflags)) { 611 1.19 ad errno = EFTYPE; /* XXX */ 612 1.52 christos mkpw_error("%s, %d: Syntax mkpw_error", pname, *lineno); 613 1.1 cgd } 614 1.17 mycroft *flags = oflags; 615 1.5 mycroft 616 1.5 mycroft return (1); 617 1.1 cgd } 618 1.1 cgd 619 1.61 christos static void 620 1.19 ad install(const char *from, const char *to) 621 1.1 cgd { 622 1.1 cgd char buf[MAXPATHLEN]; 623 1.1 cgd 624 1.44 christos (void)snprintf(buf, sizeof(buf), "%s%s", prefix, to); 625 1.52 christos if (rename(from, buf)) 626 1.52 christos mkpw_error("Cannot rename `%s' to `%s'", from, buf); 627 1.1 cgd } 628 1.1 cgd 629 1.61 christos static void 630 1.22 ad rm(const char *victim) 631 1.22 ad { 632 1.22 ad 633 1.22 ad if (unlink(victim) < 0) 634 1.22 ad warn("unlink(%s)", victim); 635 1.22 ad } 636 1.22 ad 637 1.61 christos static void 638 1.61 christos cp(const char *from, const char *to, mode_t mode) 639 1.61 christos { 640 1.22 ad static char buf[MAXBSIZE]; 641 1.52 christos int from_fd, to_fd; 642 1.44 christos ssize_t rcount, wcount; 643 1.22 ad 644 1.22 ad if ((from_fd = open(from, O_RDONLY, 0)) < 0) 645 1.52 christos mkpw_error("Cannot open `%s'", from); 646 1.53 wiz if ((to_fd = open(to, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) { 647 1.53 wiz (void)close(from_fd); 648 1.52 christos mkpw_error("Cannot open `%s'", to); 649 1.53 wiz } 650 1.22 ad while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { 651 1.44 christos wcount = write(to_fd, buf, (size_t)rcount); 652 1.53 wiz if (rcount != wcount || wcount == -1) { 653 1.53 wiz (void)close(from_fd); 654 1.53 wiz (void)close(to_fd); 655 1.50 joerg goto on_error; 656 1.53 wiz } 657 1.22 ad } 658 1.22 ad 659 1.50 joerg close(from_fd); 660 1.50 joerg if (close(to_fd)) 661 1.51 snj goto on_error; 662 1.53 wiz if (rcount < 0) 663 1.53 wiz goto on_error; 664 1.50 joerg return; 665 1.50 joerg 666 1.50 joerg on_error: 667 1.52 christos mkpw_error("Cannot copy `%s' to `%s'", from, to); 668 1.22 ad } 669 1.22 ad 670 1.61 christos static void 671 1.19 ad wr_error(const char *str) 672 1.11 fair { 673 1.52 christos mkpw_error("Cannot write `%s'", str); 674 1.52 christos } 675 1.19 ad 676 1.61 christos static void 677 1.52 christos mkpw_error(const char *fmt, ...) 678 1.52 christos { 679 1.52 christos va_list ap; 680 1.52 christos va_start(ap, fmt); 681 1.52 christos if (logsyslog) { 682 1.52 christos int sverrno = errno; 683 1.52 christos char efmt[BUFSIZ]; 684 1.52 christos snprintf(efmt, sizeof(efmt), "%s (%%m)", fmt); 685 1.52 christos errno = sverrno; 686 1.52 christos vsyslog(LOG_ERR, efmt, ap); 687 1.52 christos } else 688 1.52 christos vwarn(fmt, ap); 689 1.52 christos va_end(ap); 690 1.52 christos bailout(); 691 1.11 fair } 692 1.11 fair 693 1.61 christos static void 694 1.52 christos mkpw_warning(const char *fmt, ...) 695 1.1 cgd { 696 1.52 christos va_list ap; 697 1.52 christos va_start(ap, fmt); 698 1.52 christos if (logsyslog) 699 1.52 christos vsyslog(LOG_WARNING, fmt, ap); 700 1.52 christos else 701 1.52 christos vwarnx(fmt, ap); 702 1.52 christos va_end(ap); 703 1.1 cgd } 704 1.1 cgd 705 1.61 christos static void 706 1.44 christos inconsistency(void) 707 1.11 fair { 708 1.19 ad 709 1.52 christos mkpw_warning("text files and databases are inconsistent"); 710 1.52 christos mkpw_warning("re-build the databases without -u"); 711 1.22 ad bailout(); 712 1.11 fair } 713 1.11 fair 714 1.61 christos static void 715 1.22 ad bailout(void) 716 1.1 cgd { 717 1.19 ad 718 1.22 ad if ((clean & FILE_ORIG) != 0) 719 1.11 fair rm(oldpwdfile); 720 1.22 ad if ((clean & FILE_SECURE) != 0) 721 1.42 christos rm(sdb.dbname); 722 1.22 ad if ((clean & FILE_INSECURE) != 0) 723 1.42 christos rm(idb.dbname); 724 1.22 ad 725 1.22 ad exit(EXIT_FAILURE); 726 1.1 cgd } 727 1.1 cgd 728 1.61 christos static uint32_t 729 1.41 christos getversion(const char *fname) 730 1.35 christos { 731 1.35 christos DBT data, key; 732 1.36 jmmv int ret; 733 1.41 christos uint32_t version = 0; 734 1.42 christos DB *db; 735 1.35 christos 736 1.42 christos db = dbopen(fname, O_RDONLY, PERM_INSECURE, DB_HASH, NULL); 737 1.42 christos if (db == NULL) { 738 1.45 christos /* If we are building on a separate root, assume version 1 */ 739 1.57 christos if ((errno == EACCES && prefix[0]) || errno == ENOENT) 740 1.45 christos return 1; 741 1.52 christos mkpw_warning("Cannot open database `%s'", fname); 742 1.41 christos bailout(); 743 1.41 christos } 744 1.35 christos key.data = __UNCONST("VERSION"); 745 1.35 christos key.size = strlen((const char *)key.data) + 1; 746 1.35 christos 747 1.42 christos switch (ret = (*db->get)(db, &key, &data, 0)) { 748 1.41 christos case -1: /* Error */ 749 1.52 christos mkpw_warning("Cannot get VERSION record from database `%s'", 750 1.52 christos fname); 751 1.41 christos goto out; 752 1.41 christos case 0: 753 1.41 christos if (data.size != sizeof(version)) { 754 1.52 christos mkpw_warning("Bad VERSION record in database `%s'", fname); 755 1.41 christos goto out; 756 1.41 christos } 757 1.44 christos (void)memcpy(&version, data.data, sizeof(version)); 758 1.41 christos /*FALLTHROUGH*/ 759 1.41 christos case 1: 760 1.42 christos if (ret == 1) 761 1.52 christos mkpw_warning("Database `%s' has no version info", 762 1.52 christos fname); 763 1.42 christos (*db->close)(db); 764 1.41 christos return version; 765 1.41 christos default: 766 1.52 christos mkpw_warning("internal mkpw_error db->get returns %d", ret); 767 1.41 christos goto out; 768 1.36 jmmv } 769 1.41 christos out: 770 1.42 christos (*db->close)(db); 771 1.41 christos bailout(); 772 1.44 christos /*NOTREACHED*/ 773 1.36 jmmv } 774 1.36 jmmv 775 1.61 christos static void 776 1.42 christos setversion(struct pwddb *db) 777 1.36 jmmv { 778 1.36 jmmv DBT data, key; 779 1.36 jmmv key.data = __UNCONST("VERSION"); 780 1.36 jmmv key.size = strlen((const char *)key.data) + 1; 781 1.36 jmmv 782 1.42 christos data.data = &db->wversion; 783 1.35 christos data.size = sizeof(uint32_t); 784 1.35 christos 785 1.43 christos if ((*db->db->put)(db->db, &key, &data, 0) != 0) { 786 1.52 christos mkpw_warning("Can't write VERSION record to `%s'", db->dbname); 787 1.42 christos bailout(); 788 1.42 christos } 789 1.35 christos } 790 1.35 christos 791 1.41 christos 792 1.19 ad /* 793 1.61 christos * Write entries to a database for a single user. 794 1.19 ad * 795 1.19 ad * The databases actually contain three copies of the original data. Each 796 1.19 ad * password file entry is converted into a rough approximation of a ``struct 797 1.19 ad * passwd'', with the strings placed inline. This object is then stored as 798 1.19 ad * the data for three separate keys. The first key * is the pw_name field 799 1.19 ad * prepended by the _PW_KEYBYNAME character. The second key is the pw_uid 800 1.19 ad * field prepended by the _PW_KEYBYUID character. The third key is the line 801 1.61 christos * number in the original file prepended by the _PW_KEYBYNUM character. 802 1.19 ad * (The special characters are prepended to ensure that the keys do not 803 1.19 ad * collide.) 804 1.19 ad */ 805 1.19 ad #define COMPACT(e) for (t = e; (*p++ = *t++) != '\0';) 806 1.19 ad 807 1.61 christos static void 808 1.42 christos putdbents(struct pwddb *db, struct passwd *pw, const char *passwd, int flags, 809 1.61 christos int lineno, u_int dbflg, u_int uid_dbflg) 810 1.19 ad { 811 1.19 ad struct passwd pwd; 812 1.19 ad char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024], *p; 813 1.19 ad DBT data, key; 814 1.19 ad const char *t; 815 1.19 ad u_int32_t x; 816 1.44 christos size_t len; 817 1.19 ad 818 1.44 christos (void)memcpy(&pwd, pw, sizeof(pwd)); 819 1.19 ad data.data = (u_char *)buf; 820 1.19 ad key.data = (u_char *)tbuf; 821 1.19 ad 822 1.19 ad if (lorder != BYTE_ORDER) { 823 1.35 christos pwd.pw_uid = SWAP(pwd.pw_uid); 824 1.35 christos pwd.pw_gid = SWAP(pwd.pw_gid); 825 1.19 ad } 826 1.19 ad 827 1.41 christos #define WRITEPWTIMEVAR(pwvar) \ 828 1.41 christos do { \ 829 1.42 christos if (db->wversion == 0 && \ 830 1.44 christos /*CONSTCOND*/sizeof(pwvar) == sizeof(uint64_t)) { \ 831 1.41 christos uint32_t tmp = (uint32_t)pwvar; \ 832 1.41 christos if (lorder != BYTE_ORDER) \ 833 1.41 christos tmp = SWAP(tmp); \ 834 1.44 christos (void)memmove(p, &tmp, sizeof(tmp)); \ 835 1.41 christos p += sizeof(tmp); \ 836 1.42 christos } else if (db->wversion == 1 && \ 837 1.44 christos /*CONSTCOND*/sizeof(pwvar) == sizeof(uint32_t)) { \ 838 1.41 christos uint64_t tmp = pwvar; \ 839 1.41 christos if (lorder != BYTE_ORDER) \ 840 1.41 christos tmp = SWAP(tmp); \ 841 1.44 christos (void)memmove(p, &tmp, sizeof(tmp)); \ 842 1.41 christos p += sizeof(tmp); \ 843 1.41 christos } else { \ 844 1.41 christos if (lorder != BYTE_ORDER) \ 845 1.41 christos pwvar = SWAP(pwvar); \ 846 1.44 christos (void)memmove(p, &pwvar, sizeof(pwvar)); \ 847 1.41 christos p += sizeof(pwvar); \ 848 1.41 christos } \ 849 1.59 rillig } while (0) 850 1.41 christos 851 1.19 ad /* Create insecure data. */ 852 1.19 ad p = buf; 853 1.19 ad COMPACT(pwd.pw_name); 854 1.19 ad COMPACT(passwd); 855 1.44 christos (void)memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid)); 856 1.19 ad p += sizeof(pwd.pw_uid); 857 1.44 christos (void)memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid)); 858 1.19 ad p += sizeof(pwd.pw_gid); 859 1.41 christos WRITEPWTIMEVAR(pwd.pw_change); 860 1.19 ad COMPACT(pwd.pw_class); 861 1.19 ad COMPACT(pwd.pw_gecos); 862 1.19 ad COMPACT(pwd.pw_dir); 863 1.19 ad COMPACT(pwd.pw_shell); 864 1.41 christos WRITEPWTIMEVAR(pwd.pw_expire); 865 1.19 ad x = flags; 866 1.19 ad if (lorder != BYTE_ORDER) 867 1.35 christos x = SWAP(x); 868 1.44 christos (void)memmove(p, &x, sizeof(x)); 869 1.48 enami p += sizeof(x); 870 1.19 ad data.size = p - buf; 871 1.19 ad 872 1.19 ad /* Store insecure by name. */ 873 1.19 ad tbuf[0] = _PW_KEYBYNAME; 874 1.19 ad len = strlen(pwd.pw_name); 875 1.44 christos (void)memmove(tbuf + 1, pwd.pw_name, len); 876 1.19 ad key.size = len + 1; 877 1.42 christos if ((*db->db->put)(db->db, &key, &data, dbflg) == -1) 878 1.42 christos wr_error(db->dbname); 879 1.22 ad 880 1.19 ad /* Store insecure by number. */ 881 1.19 ad tbuf[0] = _PW_KEYBYNUM; 882 1.19 ad x = lineno; 883 1.19 ad if (lorder != BYTE_ORDER) 884 1.35 christos x = SWAP(x); 885 1.44 christos (void)memmove(tbuf + 1, &x, sizeof(x)); 886 1.19 ad key.size = sizeof(x) + 1; 887 1.42 christos if ((*db->db->put)(db->db, &key, &data, dbflg) == -1) 888 1.42 christos wr_error(db->dbname); 889 1.19 ad 890 1.19 ad /* Store insecure by uid. */ 891 1.19 ad tbuf[0] = _PW_KEYBYUID; 892 1.44 christos (void)memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid)); 893 1.19 ad key.size = sizeof(pwd.pw_uid) + 1; 894 1.42 christos if ((*db->db->put)(db->db, &key, &data, uid_dbflg) == -1) 895 1.42 christos wr_error(db->dbname); 896 1.22 ad } 897 1.22 ad 898 1.61 christos static void 899 1.42 christos deldbent(struct pwddb *db, int type, void *keyp) 900 1.22 ad { 901 1.22 ad char tbuf[1024]; 902 1.22 ad DBT key; 903 1.22 ad u_int32_t x; 904 1.44 christos size_t len; 905 1.22 ad 906 1.22 ad key.data = (u_char *)tbuf; 907 1.22 ad 908 1.22 ad switch (tbuf[0] = type) { 909 1.22 ad case _PW_KEYBYNAME: 910 1.22 ad len = strlen((char *)keyp); 911 1.44 christos (void)memcpy(tbuf + 1, keyp, len); 912 1.22 ad key.size = len + 1; 913 1.22 ad break; 914 1.22 ad 915 1.22 ad case _PW_KEYBYNUM: 916 1.22 ad case _PW_KEYBYUID: 917 1.22 ad x = *(int *)keyp; 918 1.22 ad if (lorder != BYTE_ORDER) 919 1.35 christos x = SWAP(x); 920 1.44 christos (void)memmove(tbuf + 1, &x, sizeof(x)); 921 1.22 ad key.size = sizeof(x) + 1; 922 1.22 ad break; 923 1.22 ad } 924 1.22 ad 925 1.44 christos if ((*db->db->del)(db->db, &key, 0) == -1) 926 1.42 christos wr_error(db->dbname); 927 1.22 ad } 928 1.22 ad 929 1.61 christos static int 930 1.42 christos getdbent(struct pwddb *db, int type, void *keyp, struct passwd **tpwd) 931 1.22 ad { 932 1.22 ad static char buf[MAX(MAXPATHLEN, LINE_MAX * 2)]; 933 1.22 ad static struct passwd pwd; 934 1.22 ad char tbuf[1024], *p; 935 1.22 ad DBT key, data; 936 1.22 ad u_int32_t x; 937 1.44 christos size_t len; 938 1.44 christos int rv; 939 1.22 ad 940 1.22 ad data.data = (u_char *)buf; 941 1.22 ad data.size = sizeof(buf); 942 1.22 ad key.data = (u_char *)tbuf; 943 1.22 ad 944 1.22 ad switch (tbuf[0] = type) { 945 1.22 ad case _PW_KEYBYNAME: 946 1.22 ad len = strlen((char *)keyp); 947 1.44 christos (void)memcpy(tbuf + 1, keyp, len); 948 1.22 ad key.size = len + 1; 949 1.22 ad break; 950 1.22 ad 951 1.22 ad case _PW_KEYBYNUM: 952 1.22 ad case _PW_KEYBYUID: 953 1.22 ad x = *(int *)keyp; 954 1.22 ad if (lorder != BYTE_ORDER) 955 1.35 christos x = SWAP(x); 956 1.44 christos (void)memmove(tbuf + 1, &x, sizeof(x)); 957 1.22 ad key.size = sizeof(x) + 1; 958 1.22 ad break; 959 1.22 ad } 960 1.22 ad 961 1.42 christos if ((rv = (*db->db->get)(db->db, &key, &data, 0)) == 1) 962 1.22 ad return (rv); 963 1.22 ad if (rv == -1) 964 1.52 christos mkpw_error("Error getting record from `%s'", db->dbname); 965 1.22 ad 966 1.22 ad p = (char *)data.data; 967 1.22 ad 968 1.22 ad pwd.pw_name = p; 969 1.22 ad while (*p++ != '\0') 970 1.41 christos continue; 971 1.22 ad pwd.pw_passwd = p; 972 1.22 ad while (*p++ != '\0') 973 1.41 christos continue; 974 1.22 ad 975 1.44 christos (void)memcpy(&pwd.pw_uid, p, sizeof(pwd.pw_uid)); 976 1.22 ad p += sizeof(pwd.pw_uid); 977 1.44 christos (void)memcpy(&pwd.pw_gid, p, sizeof(pwd.pw_gid)); 978 1.22 ad p += sizeof(pwd.pw_gid); 979 1.41 christos 980 1.41 christos #define READPWTIMEVAR(pwvar) \ 981 1.41 christos do { \ 982 1.42 christos if (db->rversion == 0 && \ 983 1.44 christos /*CONSTCOND*/sizeof(pwvar) == sizeof(uint64_t)) { \ 984 1.41 christos uint32_t tmp; \ 985 1.44 christos (void)memcpy(&tmp, p, sizeof(tmp)); \ 986 1.41 christos p += sizeof(tmp); \ 987 1.41 christos if (lorder != BYTE_ORDER) \ 988 1.41 christos pwvar = SWAP(tmp); \ 989 1.41 christos else \ 990 1.41 christos pwvar = tmp; \ 991 1.42 christos } else if (db->rversion == 1 && \ 992 1.44 christos /*CONSTCOND*/sizeof(pwvar) == sizeof(uint32_t)) { \ 993 1.41 christos uint64_t tmp; \ 994 1.44 christos (void)memcpy(&tmp, p, sizeof(tmp)); \ 995 1.41 christos p += sizeof(tmp); \ 996 1.41 christos if (lorder != BYTE_ORDER) \ 997 1.41 christos pwvar = (uint32_t)SWAP(tmp); \ 998 1.41 christos else \ 999 1.41 christos pwvar = (uint32_t)tmp; \ 1000 1.41 christos } else { \ 1001 1.44 christos (void)memcpy(&pwvar, p, sizeof(pwvar)); \ 1002 1.41 christos p += sizeof(pwvar); \ 1003 1.41 christos if (lorder != BYTE_ORDER) \ 1004 1.41 christos pwvar = SWAP(pwvar); \ 1005 1.41 christos } \ 1006 1.59 rillig } while (0) 1007 1.61 christos 1008 1.41 christos READPWTIMEVAR(pwd.pw_change); 1009 1.22 ad 1010 1.22 ad pwd.pw_class = p; 1011 1.22 ad while (*p++ != '\0') 1012 1.41 christos continue; 1013 1.22 ad pwd.pw_gecos = p; 1014 1.22 ad while (*p++ != '\0') 1015 1.41 christos continue; 1016 1.22 ad pwd.pw_dir = p; 1017 1.22 ad while (*p++ != '\0') 1018 1.41 christos continue; 1019 1.22 ad pwd.pw_shell = p; 1020 1.22 ad while (*p++ != '\0') 1021 1.41 christos continue; 1022 1.22 ad 1023 1.41 christos READPWTIMEVAR(pwd.pw_expire); 1024 1.22 ad 1025 1.22 ad if (lorder != BYTE_ORDER) { 1026 1.35 christos pwd.pw_uid = SWAP(pwd.pw_uid); 1027 1.35 christos pwd.pw_gid = SWAP(pwd.pw_gid); 1028 1.22 ad } 1029 1.22 ad 1030 1.22 ad *tpwd = &pwd; 1031 1.22 ad return (0); 1032 1.19 ad } 1033 1.19 ad 1034 1.61 christos static void 1035 1.42 christos putyptoken(struct pwddb *db) 1036 1.19 ad { 1037 1.19 ad DBT data, key; 1038 1.19 ad 1039 1.40 lukem key.data = __UNCONST(__yp_token); 1040 1.19 ad key.size = strlen(__yp_token); 1041 1.55 plunky data.data = NULL; 1042 1.19 ad data.size = 0; 1043 1.19 ad 1044 1.42 christos if ((*db->db->put)(db->db, &key, &data, R_NOOVERWRITE) == -1) 1045 1.42 christos wr_error(db->dbname); 1046 1.19 ad } 1047 1.19 ad 1048 1.61 christos static void 1049 1.19 ad usage(void) 1050 1.1 cgd { 1051 1.5 mycroft 1052 1.22 ad (void)fprintf(stderr, 1053 1.52 christos "Usage: %s [-BLlpsvw] [-c cachesize] [-d directory] [-u user] " 1054 1.41 christos "[-V version] file\n", 1055 1.41 christos getprogname()); 1056 1.19 ad exit(EXIT_FAILURE); 1057 1.1 cgd } 1058