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