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