pwd_mkdb.c revision 1.23 1 /* $NetBSD: pwd_mkdb.c,v 1.23 2002/01/29 10:20:38 tv Exp $ */
2
3 /*
4 * Copyright (c) 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 * Portions Copyright(C) 1994, Jason Downs. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #if HAVE_CONFIG_H
38 #include "config.h"
39 #else
40 #define HAVE_ERR_H 1
41 #define HAVE_UTIL_H 1
42 #endif
43
44 #include <sys/cdefs.h>
45 #ifndef lint
46 __COPYRIGHT("@(#) Copyright (c) 2000\n\
47 The NetBSD Foundation, Inc. All rights reserved.\n\
48 Copyright (c) 1991, 1993, 1994\n\
49 The Regents of the University of California. All rights reserved.\n");
50 __SCCSID("from: @(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94");
51 __RCSID("$NetBSD: pwd_mkdb.c,v 1.23 2002/01/29 10:20:38 tv Exp $");
52 #endif /* not lint */
53
54 #include <sys/param.h>
55 #include <sys/stat.h>
56
57 #include <db.h>
58 #include <errno.h>
59 #include <fcntl.h>
60 #include <limits.h>
61 #include <signal.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66
67 #if HAVE_CONFIG_H
68 #include "compat_pwd.h"
69 #else
70 #include <pwd.h>
71 #endif
72 #if HAVE_ERR_H
73 #include <err.h>
74 #endif
75 #if HAVE_UTIL_H
76 #include <util.h>
77 #endif
78
79 #define MAX_CACHESIZE 8*1024*1024
80 #define MIN_CACHESIZE 2*1024*1024
81
82 #define PERM_INSECURE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
83 #define PERM_SECURE (S_IRUSR | S_IWUSR)
84
85 #if HAVE_CONFIG_H
86 static const char __yp_token[] = "__YP!";
87 #else
88 /* Pull this out of the C library. */
89 extern const char __yp_token[];
90 #endif
91
92 HASHINFO openinfo = {
93 4096, /* bsize */
94 32, /* ffactor */
95 256, /* nelem */
96 0, /* cachesize */
97 NULL, /* hash() */
98 0 /* lorder */
99 };
100
101 #define FILE_INSECURE 0x01
102 #define FILE_SECURE 0x02
103 #define FILE_ORIG 0x04
104
105 static char *pname; /* password file name */
106 static char prefix[MAXPATHLEN];
107 static char oldpwdfile[MAX(MAXPATHLEN, LINE_MAX * 2)];
108 static char pwd_db_tmp[MAX(MAXPATHLEN, LINE_MAX * 2)];
109 static char pwd_Sdb_tmp[MAX(MAXPATHLEN, LINE_MAX * 2)];
110 static int lorder = BYTE_ORDER;
111 static int clean;
112
113 void bailout(void);
114 void cp(const char *, const char *, mode_t);
115 int deldbent(DB *, const char *, int, void *);
116 void error(const char *);
117 int getdbent(DB *, const char *, int, void *, struct passwd **);
118 void inconsistancy(void);
119 void install(const char *, const char *);
120 int main(int, char **);
121 void putdbents(DB *, struct passwd *, const char *, int, const char *, int,
122 int, int);
123 void putyptoken(DB *, const char *);
124 void rm(const char *);
125 int scan(FILE *, struct passwd *, int *, int *);
126 void usage(void);
127 void wr_error(const char *);
128
129 int
130 main(int argc, char *argv[])
131 {
132 int ch, makeold, tfd, lineno, found, rv, hasyp, secureonly;
133 struct passwd pwd, *tpwd;
134 char *username;
135 DB *dp, *edp;
136 FILE *fp, *oldfp;
137 sigset_t set;
138 int dbflg, uid_dbflg, newuser, olduid, flags;
139 char buf[MAXPATHLEN];
140 struct stat st;
141 u_int cachesize;
142
143 prefix[0] = '\0';
144 makeold = 0;
145 oldfp = NULL;
146 username = NULL;
147 hasyp = 0;
148 secureonly = 0;
149
150 while ((ch = getopt(argc, argv, "BLd:psu:v")) != -1)
151 switch (ch) {
152 case 'B': /* big-endian output */
153 lorder = BIG_ENDIAN;
154 break;
155 case 'L': /* little-endian output */
156 lorder = LITTLE_ENDIAN;
157 break;
158 case 'd': /* set prefix */
159 strncpy(prefix, optarg, sizeof(prefix));
160 prefix[sizeof(prefix)-1] = '\0';
161 break;
162 case 'p': /* create V7 "file.orig" */
163 makeold = 1;
164 break;
165 case 's': /* modify secure db only */
166 secureonly = 1;
167 break;
168 case 'u': /* modify one user only */
169 username = optarg;
170 break;
171 case 'v': /* backward compatible */
172 break;
173 case '?':
174 default:
175 usage();
176 }
177 argc -= optind;
178 argv += optind;
179
180 if (argc != 1)
181 usage();
182 if (username != NULL)
183 if (username[0] == '+' || username[0] == '-')
184 usage();
185 if (secureonly)
186 makeold = 0;
187
188 /*
189 * This could be changed to allow the user to interrupt.
190 * Probably not worth the effort.
191 */
192 sigemptyset(&set);
193 sigaddset(&set, SIGTSTP);
194 sigaddset(&set, SIGHUP);
195 sigaddset(&set, SIGINT);
196 sigaddset(&set, SIGQUIT);
197 sigaddset(&set, SIGTERM);
198 (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
199
200 /* We don't care what the user wants. */
201 (void)umask(0);
202
203 if (username == NULL)
204 flags = O_RDWR | O_CREAT | O_EXCL;
205 else
206 flags = O_RDWR;
207
208 pname = *argv;
209 /* Open the original password file */
210 if ((fp = fopen(pname, "r")) == NULL)
211 error(pname);
212
213 openinfo.lorder = lorder;
214
215 if (fstat(fileno(fp), &st) == -1)
216 error(pname);
217
218 /* Tweak openinfo values for large passwd files. */
219 cachesize = st.st_size * 20;
220 if (cachesize > MAX_CACHESIZE)
221 cachesize = MAX_CACHESIZE;
222 else if (cachesize < MIN_CACHESIZE)
223 cachesize = MIN_CACHESIZE;
224 openinfo.cachesize = cachesize;
225
226 /* Open the temporary insecure password database. */
227 if (!secureonly) {
228 (void)snprintf(pwd_db_tmp, sizeof(pwd_db_tmp), "%s%s.tmp",
229 prefix, _PATH_MP_DB);
230 if (username != NULL) {
231 snprintf(buf, sizeof(buf), "%s" _PATH_MP_DB, prefix);
232 cp(buf, pwd_db_tmp, PERM_INSECURE);
233 }
234 dp = dbopen(pwd_db_tmp, flags, PERM_INSECURE, DB_HASH,
235 &openinfo);
236 if (dp == NULL)
237 error(pwd_db_tmp);
238 clean |= FILE_INSECURE;
239 }
240
241 /* Open the temporary encrypted password database. */
242 (void)snprintf(pwd_Sdb_tmp, sizeof(pwd_Sdb_tmp), "%s%s.tmp", prefix,
243 _PATH_SMP_DB);
244 if (username != NULL) {
245 snprintf(buf, sizeof(buf), "%s" _PATH_SMP_DB, prefix);
246 cp(buf, pwd_Sdb_tmp, PERM_SECURE);
247 }
248 edp = dbopen(pwd_Sdb_tmp, flags, PERM_SECURE, DB_HASH, &openinfo);
249 if (!edp)
250 error(pwd_Sdb_tmp);
251 clean |= FILE_SECURE;
252
253 /*
254 * Open file for old password file. Minor trickiness -- don't want to
255 * chance the file already existing, since someone (stupidly) might
256 * still be using this for permission checking. So, open it first and
257 * fdopen the resulting fd. The resulting file should be readable by
258 * everyone.
259 */
260 if (makeold) {
261 (void)snprintf(oldpwdfile, sizeof(oldpwdfile), "%s.orig",
262 pname);
263 if ((tfd = open(oldpwdfile, O_WRONLY | O_CREAT | O_EXCL,
264 PERM_INSECURE)) < 0)
265 error(oldpwdfile);
266 clean |= FILE_ORIG;
267 if ((oldfp = fdopen(tfd, "w")) == NULL)
268 error(oldpwdfile);
269 }
270
271 if (username != NULL) {
272 uid_dbflg = 0;
273 dbflg = 0;
274 found = 0;
275
276 /*
277 * Determine if this is a new entry.
278 */
279 if (getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNAME, username, &tpwd))
280 newuser = 1;
281 else {
282 newuser = 0;
283 olduid = tpwd->pw_uid;
284 }
285
286 } else {
287 uid_dbflg = R_NOOVERWRITE;
288 dbflg = R_NOOVERWRITE;
289 }
290
291 /*
292 * If we see something go by that looks like YP, we save a special
293 * pointer record, which if YP is enabled in the C lib, will speed
294 * things up.
295 */
296 for (lineno = 0; scan(fp, &pwd, &flags, &lineno);) {
297 /*
298 * Create original format password file entry.
299 */
300 if (makeold) {
301 (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
302 pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
303 pwd.pw_dir, pwd.pw_shell);
304 if (ferror(oldfp))
305 wr_error(oldpwdfile);
306 }
307
308 if (username == NULL) {
309 /* Look like YP? */
310 if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-')
311 hasyp++;
312
313 /* Warn about potentially unsafe uid/gid overrides. */
314 if (pwd.pw_name[0] == '+') {
315 if ((flags & _PASSWORD_NOUID) == 0 &&
316 pwd.pw_uid == 0)
317 warnx("line %d: superuser override "
318 "in YP inclusion", lineno);
319 if ((flags & _PASSWORD_NOGID) == 0 &&
320 pwd.pw_gid == 0)
321 warnx("line %d: wheel override "
322 "in YP inclusion", lineno);
323 }
324
325 /* Write the database entry out. */
326 if (!secureonly)
327 putdbents(dp, &pwd, "*", flags, pwd_db_tmp,
328 lineno, dbflg, uid_dbflg);
329 continue;
330 } else if (strcmp(username, pwd.pw_name) != 0)
331 continue;
332
333 if (found) {
334 warnx("user `%s' listed twice in password file",
335 username);
336 bailout();
337 }
338
339 /*
340 * Ensure that the text file and database agree on
341 * which line the record is from.
342 */
343 rv = getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNUM, &lineno, &tpwd);
344 if (newuser) {
345 if (rv == 0)
346 inconsistancy();
347 } else if (rv == -1 ||
348 strcmp(username, tpwd->pw_name) != 0)
349 inconsistancy();
350 else if (olduid != pwd.pw_uid) {
351 /*
352 * If we're changing UID, remove the BYUID
353 * record for the old UID only if it has the
354 * same username.
355 */
356 if (!getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYUID, &olduid,
357 &tpwd)) {
358 if (strcmp(username, tpwd->pw_name) == 0) {
359 if (!secureonly)
360 deldbent(dp, pwd_db_tmp,
361 _PW_KEYBYUID, &olduid);
362 deldbent(edp, pwd_Sdb_tmp,
363 _PW_KEYBYUID, &olduid);
364 }
365 } else
366 inconsistancy();
367 }
368
369 /*
370 * If there's an existing BYUID record for the new UID and
371 * the username doesn't match then be sure not to overwrite
372 * it.
373 */
374 if (!getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYUID, &pwd.pw_uid,
375 &tpwd))
376 if (strcmp(username, tpwd->pw_name) != 0)
377 uid_dbflg = R_NOOVERWRITE;
378
379 /* Write the database entries out */
380 if (!secureonly)
381 putdbents(dp, &pwd, "*", flags, pwd_db_tmp, lineno,
382 dbflg, uid_dbflg);
383 putdbents(edp, &pwd, pwd.pw_passwd, flags, pwd_Sdb_tmp,
384 lineno, dbflg, uid_dbflg);
385
386 found = 1;
387 if (!makeold)
388 break;
389 }
390
391 if (!secureonly) {
392 /* Store YP token if needed. */
393 if (hasyp)
394 putyptoken(dp, pwd_db_tmp);
395
396 /* Close the insecure database. */
397 if ((*dp->close)(dp) < 0)
398 wr_error(pwd_db_tmp);
399 }
400
401 /*
402 * If rebuilding the databases, we re-parse the text file and write
403 * the secure entries out in a separate pass.
404 */
405 if (username == NULL) {
406 rewind(fp);
407 for (lineno = 0; scan(fp, &pwd, &flags, &lineno);)
408 putdbents(edp, &pwd, pwd.pw_passwd, flags, pwd_Sdb_tmp,
409 lineno, dbflg, uid_dbflg);
410
411 /* Store YP token if needed. */
412 if (hasyp)
413 putyptoken(edp, pwd_Sdb_tmp);
414 } else if (!found) {
415 warnx("user `%s' not found in password file", username);
416 bailout();
417 }
418
419 /* Close the secure database. */
420 if ((*edp->close)(edp) < 0)
421 wr_error(pwd_Sdb_tmp);
422
423 /* Install as the real password files. */
424 if (!secureonly)
425 install(pwd_db_tmp, _PATH_MP_DB);
426 install(pwd_Sdb_tmp, _PATH_SMP_DB);
427
428 /* Install the V7 password file. */
429 if (makeold) {
430 if (fflush(oldfp) == EOF)
431 wr_error(oldpwdfile);
432 if (fclose(oldfp) == EOF)
433 wr_error(oldpwdfile);
434 install(oldpwdfile, _PATH_PASSWD);
435 }
436
437 /* Set master.passwd permissions, in case caller forgot. */
438 (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
439 if (fclose(fp) == EOF)
440 wr_error(pname);
441
442 /*
443 * Move the temporary master password file LAST -- chpass(1),
444 * passwd(1), vipw(8) and friends all use its existance to block
445 * other incarnations of themselves. The rename means that
446 * everything is unlocked, as the original file can no longer be
447 * accessed.
448 */
449 install(pname, _PATH_MASTERPASSWD);
450 exit(EXIT_SUCCESS);
451 /* NOTREACHED */
452 }
453
454 int
455 scan(FILE *fp, struct passwd *pw, int *flags, int *lineno)
456 {
457 static char line[LINE_MAX];
458 char *p;
459 int oflags;
460
461 if (fgets(line, sizeof(line), fp) == NULL)
462 return (0);
463 (*lineno)++;
464
465 /*
466 * ``... if I swallow anything evil, put your fingers down my
467 * throat...''
468 * -- The Who
469 */
470 if ((p = strchr(line, '\n')) == NULL) {
471 warnx("line too long");
472 errno = EFTYPE; /* XXX */
473 error(pname);
474 }
475 *p = '\0';
476 if (strcmp(line, "+") == 0)
477 strcpy(line, "+:::::::::"); /* pw_scan() can't handle "+" */
478 oflags = 0;
479 if (!pw_scan(line, pw, &oflags)) {
480 warnx("at line #%d", *lineno);
481 errno = EFTYPE; /* XXX */
482 error(pname);
483 }
484 *flags = oflags;
485
486 return (1);
487 }
488
489 void
490 install(const char *from, const char *to)
491 {
492 char buf[MAXPATHLEN];
493 int sverrno;
494
495 snprintf(buf, sizeof(buf), "%s%s", prefix, to);
496 if (rename(from, buf)) {
497 sverrno = errno;
498 (void)snprintf(buf, sizeof(buf), "%s to %s", from, buf);
499 errno = sverrno;
500 error(buf);
501 }
502 }
503
504 void
505 rm(const char *victim)
506 {
507
508 if (unlink(victim) < 0)
509 warn("unlink(%s)", victim);
510 }
511
512 void
513 cp(const char *from, const char *to, mode_t mode)
514 {
515 static char buf[MAXBSIZE];
516 int from_fd, rcount, to_fd, wcount, sverrno;
517
518 if ((from_fd = open(from, O_RDONLY, 0)) < 0)
519 error(from);
520 if ((to_fd = open(to, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0)
521 error(to);
522 while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
523 wcount = write(to_fd, buf, rcount);
524 if (rcount != wcount || wcount == -1) {
525 sverrno = errno;
526 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
527 errno = sverrno;
528 error(buf);
529 }
530 }
531
532 if (rcount < 0) {
533 sverrno = errno;
534 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
535 errno = sverrno;
536 error(buf);
537 }
538 }
539
540 void
541 wr_error(const char *str)
542 {
543 char errbuf[BUFSIZ];
544 int sverrno;
545
546 sverrno = errno;
547
548 (void)snprintf(errbuf, sizeof(errbuf),
549 "attempt to write %s failed", str);
550
551 errno = sverrno;
552 error(errbuf);
553 }
554
555 void
556 error(const char *str)
557 {
558
559 warn("%s", str);
560 bailout();
561 }
562
563 void
564 inconsistancy(void)
565 {
566
567 warnx("text files and databases are inconsistent");
568 warnx("re-build the databases without -u");
569 bailout();
570 }
571
572 void
573 bailout(void)
574 {
575
576 if ((clean & FILE_ORIG) != 0)
577 rm(oldpwdfile);
578 if ((clean & FILE_SECURE) != 0)
579 rm(pwd_Sdb_tmp);
580 if ((clean & FILE_INSECURE) != 0)
581 rm(pwd_db_tmp);
582
583 exit(EXIT_FAILURE);
584 }
585
586 /*
587 * Write entries to a database for a single user.
588 *
589 * The databases actually contain three copies of the original data. Each
590 * password file entry is converted into a rough approximation of a ``struct
591 * passwd'', with the strings placed inline. This object is then stored as
592 * the data for three separate keys. The first key * is the pw_name field
593 * prepended by the _PW_KEYBYNAME character. The second key is the pw_uid
594 * field prepended by the _PW_KEYBYUID character. The third key is the line
595 * number in the original file prepended by the _PW_KEYBYNUM character.
596 * (The special characters are prepended to ensure that the keys do not
597 * collide.)
598 */
599 #define COMPACT(e) for (t = e; (*p++ = *t++) != '\0';)
600
601 void
602 putdbents(DB *dp, struct passwd *pw, const char *passwd, int flags,
603 const char *fn, int lineno, int dbflg, int uid_dbflg)
604 {
605 struct passwd pwd;
606 char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024], *p;
607 DBT data, key;
608 const char *t;
609 u_int32_t x;
610 int len;
611
612 memcpy(&pwd, pw, sizeof(pwd));
613 data.data = (u_char *)buf;
614 key.data = (u_char *)tbuf;
615
616 if (lorder != BYTE_ORDER) {
617 M_32_SWAP(pwd.pw_uid);
618 M_32_SWAP(pwd.pw_gid);
619 M_32_SWAP(pwd.pw_change);
620 M_32_SWAP(pwd.pw_expire);
621 }
622
623 /* Create insecure data. */
624 p = buf;
625 COMPACT(pwd.pw_name);
626 COMPACT(passwd);
627 memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid));
628 p += sizeof(pwd.pw_uid);
629 memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid));
630 p += sizeof(pwd.pw_gid);
631 memmove(p, &pwd.pw_change, sizeof(pwd.pw_change));
632 p += sizeof(pwd.pw_change);
633 COMPACT(pwd.pw_class);
634 COMPACT(pwd.pw_gecos);
635 COMPACT(pwd.pw_dir);
636 COMPACT(pwd.pw_shell);
637 memmove(p, &pwd.pw_expire, sizeof(pwd.pw_expire));
638 p += sizeof(pwd.pw_expire);
639 x = flags;
640 if (lorder != BYTE_ORDER)
641 M_32_SWAP(x);
642 memmove(p, &x, sizeof(x));
643 p += sizeof(flags);
644 data.size = p - buf;
645
646 /* Store insecure by name. */
647 tbuf[0] = _PW_KEYBYNAME;
648 len = strlen(pwd.pw_name);
649 memmove(tbuf + 1, pwd.pw_name, len);
650 key.size = len + 1;
651 if ((*dp->put)(dp, &key, &data, dbflg) == -1)
652 wr_error(fn);
653
654 /* Store insecure by number. */
655 tbuf[0] = _PW_KEYBYNUM;
656 x = lineno;
657 if (lorder != BYTE_ORDER)
658 M_32_SWAP(x);
659 memmove(tbuf + 1, &x, sizeof(x));
660 key.size = sizeof(x) + 1;
661 if ((*dp->put)(dp, &key, &data, dbflg) == -1)
662 wr_error(fn);
663
664 /* Store insecure by uid. */
665 tbuf[0] = _PW_KEYBYUID;
666 memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
667 key.size = sizeof(pwd.pw_uid) + 1;
668 if ((*dp->put)(dp, &key, &data, uid_dbflg) == -1)
669 wr_error(fn);
670 }
671
672 int
673 deldbent(DB *dp, const char *fn, int type, void *keyp)
674 {
675 char tbuf[1024];
676 DBT key;
677 u_int32_t x;
678 int len, rv;
679
680 key.data = (u_char *)tbuf;
681
682 switch (tbuf[0] = type) {
683 case _PW_KEYBYNAME:
684 len = strlen((char *)keyp);
685 memcpy(tbuf + 1, keyp, len);
686 key.size = len + 1;
687 break;
688
689 case _PW_KEYBYNUM:
690 case _PW_KEYBYUID:
691 x = *(int *)keyp;
692 if (lorder != BYTE_ORDER)
693 M_32_SWAP(x);
694 memmove(tbuf + 1, &x, sizeof(x));
695 key.size = sizeof(x) + 1;
696 break;
697 }
698
699 if ((rv = (*dp->del)(dp, &key, 0)) == -1)
700 wr_error(fn);
701 return (rv);
702 }
703
704 int
705 getdbent(DB *dp, const char *fn, int type, void *keyp, struct passwd **tpwd)
706 {
707 static char buf[MAX(MAXPATHLEN, LINE_MAX * 2)];
708 static struct passwd pwd;
709 char tbuf[1024], *p;
710 DBT key, data;
711 u_int32_t x;
712 int len, rv;
713
714 data.data = (u_char *)buf;
715 data.size = sizeof(buf);
716 key.data = (u_char *)tbuf;
717
718 switch (tbuf[0] = type) {
719 case _PW_KEYBYNAME:
720 len = strlen((char *)keyp);
721 memcpy(tbuf + 1, keyp, len);
722 key.size = len + 1;
723 break;
724
725 case _PW_KEYBYNUM:
726 case _PW_KEYBYUID:
727 x = *(int *)keyp;
728 if (lorder != BYTE_ORDER)
729 M_32_SWAP(x);
730 memmove(tbuf + 1, &x, sizeof(x));
731 key.size = sizeof(x) + 1;
732 break;
733 }
734
735 if ((rv = (*dp->get)(dp, &key, &data, 0)) == 1)
736 return (rv);
737 if (rv == -1)
738 error(pwd_Sdb_tmp);
739
740 p = (char *)data.data;
741
742 pwd.pw_name = p;
743 while (*p++ != '\0')
744 ;
745 pwd.pw_passwd = p;
746 while (*p++ != '\0')
747 ;
748
749 memcpy(&pwd.pw_uid, p, sizeof(pwd.pw_uid));
750 p += sizeof(pwd.pw_uid);
751 memcpy(&pwd.pw_gid, p, sizeof(pwd.pw_gid));
752 p += sizeof(pwd.pw_gid);
753 memcpy(&pwd.pw_change, p, sizeof(pwd.pw_change));
754 p += sizeof(pwd.pw_change);
755
756 pwd.pw_class = p;
757 while (*p++ != '\0')
758 ;
759 pwd.pw_gecos = p;
760 while (*p++ != '\0')
761 ;
762 pwd.pw_dir = p;
763 while (*p++ != '\0')
764 ;
765 pwd.pw_shell = p;
766 while (*p++ != '\0')
767 ;
768
769 memcpy(&pwd.pw_expire, p, sizeof(pwd.pw_expire));
770 p += sizeof(pwd.pw_expire);
771
772 if (lorder != BYTE_ORDER) {
773 M_32_SWAP(pwd.pw_uid);
774 M_32_SWAP(pwd.pw_gid);
775 M_32_SWAP(pwd.pw_change);
776 M_32_SWAP(pwd.pw_expire);
777 }
778
779 *tpwd = &pwd;
780 return (0);
781 }
782
783 void
784 putyptoken(DB *dp, const char *fn)
785 {
786 DBT data, key;
787
788 key.data = (u_char *)__yp_token;
789 key.size = strlen(__yp_token);
790 data.data = (u_char *)NULL;
791 data.size = 0;
792
793 if ((*dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
794 wr_error(fn);
795 }
796
797 void
798 usage(void)
799 {
800
801 (void)fprintf(stderr,
802 "usage: pwd_mkdb [-BLps] [-d directory] [-u user] file\n");
803 exit(EXIT_FAILURE);
804 }
805