pwd_mkdb.c revision 1.34.6.2 1 /* $NetBSD: pwd_mkdb.c,v 1.34.6.2 2008/12/28 01:21:23 christos 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\
64 The NetBSD Foundation, Inc. All rights reserved.\
65 Copyright (c) 1991, 1993, 1994\
66 The Regents of the University of California. All rights reserved.");
67 __SCCSID("from: @(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94");
68 __RCSID("$NetBSD: pwd_mkdb.c,v 1.34.6.2 2008/12/28 01:21:23 christos 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 void setversion(DB *);
142
143 static __inline uint16_t swap16(uint16_t sw)
144 {
145 return ((sw & 0x00ff) << 8) |
146 ((sw & 0xff00) >> 8);
147 }
148
149 static __inline uint32_t swap32(uint32_t sw) {
150 return ((sw & 0x000000ff) << 24) |
151 ((sw & 0x0000ff00) << 8) |
152 ((sw & 0x00ff0000) >> 8) |
153 ((sw & 0xff000000) >> 24);
154 }
155
156 static __inline uint64_t swap64(uint64_t sw) {
157 return ((sw & 0x00000000000000ffULL) << 56) |
158 ((sw & 0x000000000000ff00ULL) << 40) |
159 ((sw & 0x0000000000ff0000ULL) >> 24) |
160 ((sw & 0x00000000ff000000ULL) << 8) |
161 ((sw & 0x000000ff00000000ULL) >> 8) |
162 ((sw & 0x0000ff0000000000ULL) >> 24) |
163 ((sw & 0x00ff000000000000ULL) >> 40) |
164 ((sw & 0xff00000000000000ULL) >> 56);
165 }
166
167 #define SWAP(sw) \
168 ((sizeof(sw) == 2 ? (typeof(sw))swap16((uint16_t)sw) : \
169 (sizeof(sw) == 4 ? (typeof(sw))swap32((uint32_t)sw) : \
170 (sizeof(sw) == 8 ? (typeof(sw))swap64((uint64_t)sw) : abort(), 0))))
171
172 int
173 main(int argc, char *argv[])
174 {
175 int ch, makeold, tfd, lineno, found, rv, hasyp, secureonly;
176 struct passwd pwd, *tpwd;
177 char *username;
178 DB *dp, *edp;
179 FILE *fp, *oldfp;
180 sigset_t set;
181 int dbflg, uid_dbflg, newuser, olduid, flags;
182 char buf[MAXPATHLEN];
183 struct stat st;
184 u_int cachesize;
185
186 prefix[0] = '\0';
187 makeold = 0;
188 oldfp = NULL;
189 username = NULL;
190 hasyp = 0;
191 secureonly = 0;
192 found = 0;
193 newuser = 0;
194 dp = NULL;
195 cachesize = 0;
196
197 while ((ch = getopt(argc, argv, "BLc:d:psu:v")) != -1)
198 switch (ch) {
199 case 'B': /* big-endian output */
200 lorder = BIG_ENDIAN;
201 break;
202 case 'L': /* little-endian output */
203 lorder = LITTLE_ENDIAN;
204 break;
205 case 'c':
206 cachesize = atoi(optarg) * 1024 * 1024;
207 break;
208 case 'd': /* set prefix */
209 strlcpy(prefix, optarg, sizeof(prefix));
210 break;
211 case 'p': /* create V7 "file.orig" */
212 makeold = 1;
213 break;
214 case 's': /* modify secure db only */
215 secureonly = 1;
216 break;
217 case 'u': /* modify one user only */
218 username = optarg;
219 break;
220 case 'v': /* backward compatible */
221 break;
222 case '?':
223 default:
224 usage();
225 }
226 argc -= optind;
227 argv += optind;
228
229 if (argc != 1)
230 usage();
231 if (username != NULL)
232 if (username[0] == '+' || username[0] == '-')
233 usage();
234 if (secureonly)
235 makeold = 0;
236
237 /*
238 * This could be changed to allow the user to interrupt.
239 * Probably not worth the effort.
240 */
241 sigemptyset(&set);
242 sigaddset(&set, SIGTSTP);
243 sigaddset(&set, SIGHUP);
244 sigaddset(&set, SIGINT);
245 sigaddset(&set, SIGQUIT);
246 sigaddset(&set, SIGTERM);
247 (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
248
249 /* We don't care what the user wants. */
250 (void)umask(0);
251
252 if (username == NULL)
253 flags = O_RDWR | O_CREAT | O_EXCL;
254 else
255 flags = O_RDWR;
256
257 pname = *argv;
258 /* Open the original password file */
259 if ((fp = fopen(pname, "r")) == NULL)
260 error(pname);
261
262 openinfo.lorder = lorder;
263
264 if (fstat(fileno(fp), &st) == -1)
265 error(pname);
266
267 if (cachesize) {
268 openinfo.cachesize = cachesize;
269 } else {
270 /* Tweak openinfo values for large passwd files. */
271 cachesize = st.st_size * 20;
272 if (cachesize > MAX_CACHESIZE)
273 cachesize = MAX_CACHESIZE;
274 else if (cachesize < MIN_CACHESIZE)
275 cachesize = MIN_CACHESIZE;
276 openinfo.cachesize = cachesize;
277 }
278
279 /* Open the temporary insecure password database. */
280 if (!secureonly) {
281 (void)snprintf(pwd_db_tmp, sizeof(pwd_db_tmp), "%s%s.tmp",
282 prefix, _PATH_MP_DB);
283 if (username != NULL) {
284 snprintf(buf, sizeof(buf), "%s" _PATH_MP_DB, prefix);
285 cp(buf, pwd_db_tmp, PERM_INSECURE);
286 }
287 dp = dbopen(pwd_db_tmp, flags, PERM_INSECURE, DB_HASH,
288 &openinfo);
289 if (dp == NULL)
290 error(pwd_db_tmp);
291 setversion(dp);
292 clean |= FILE_INSECURE;
293 }
294
295 /* Open the temporary encrypted password database. */
296 (void)snprintf(pwd_Sdb_tmp, sizeof(pwd_Sdb_tmp), "%s%s.tmp", prefix,
297 _PATH_SMP_DB);
298 if (username != NULL) {
299 snprintf(buf, sizeof(buf), "%s" _PATH_SMP_DB, prefix);
300 cp(buf, pwd_Sdb_tmp, PERM_SECURE);
301 }
302 edp = dbopen(pwd_Sdb_tmp, flags, PERM_SECURE, DB_HASH, &openinfo);
303 if (!edp)
304 error(pwd_Sdb_tmp);
305 setversion(edp);
306 clean |= FILE_SECURE;
307
308 /*
309 * Open file for old password file. Minor trickiness -- don't want to
310 * chance the file already existing, since someone (stupidly) might
311 * still be using this for permission checking. So, open it first and
312 * fdopen the resulting fd. The resulting file should be readable by
313 * everyone.
314 */
315 if (makeold) {
316 (void)snprintf(oldpwdfile, sizeof(oldpwdfile), "%s.orig",
317 pname);
318 if ((tfd = open(oldpwdfile, O_WRONLY | O_CREAT | O_EXCL,
319 PERM_INSECURE)) < 0)
320 error(oldpwdfile);
321 clean |= FILE_ORIG;
322 if ((oldfp = fdopen(tfd, "w")) == NULL)
323 error(oldpwdfile);
324 }
325
326 if (username != NULL) {
327 uid_dbflg = 0;
328 dbflg = 0;
329
330 /*
331 * Determine if this is a new entry.
332 */
333 if (getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNAME, username, &tpwd))
334 newuser = 1;
335 else {
336 newuser = 0;
337 olduid = tpwd->pw_uid;
338 }
339
340 } else {
341 uid_dbflg = R_NOOVERWRITE;
342 dbflg = R_NOOVERWRITE;
343 }
344
345 /*
346 * If we see something go by that looks like YP, we save a special
347 * pointer record, which if YP is enabled in the C lib, will speed
348 * things up.
349 */
350 for (lineno = 0; scan(fp, &pwd, &flags, &lineno);) {
351 /*
352 * Create original format password file entry.
353 */
354 if (makeold) {
355 (void)fprintf(oldfp, "%s:*:%d:%d:%s:%s:%s\n",
356 pwd.pw_name, pwd.pw_uid, pwd.pw_gid, pwd.pw_gecos,
357 pwd.pw_dir, pwd.pw_shell);
358 if (ferror(oldfp))
359 wr_error(oldpwdfile);
360 }
361
362 if (username == NULL) {
363 /* Look like YP? */
364 if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-')
365 hasyp++;
366
367 /* Warn about potentially unsafe uid/gid overrides. */
368 if (pwd.pw_name[0] == '+') {
369 if ((flags & _PASSWORD_NOUID) == 0 &&
370 pwd.pw_uid == 0)
371 warnx("line %d: superuser override "
372 "in YP inclusion", lineno);
373 if ((flags & _PASSWORD_NOGID) == 0 &&
374 pwd.pw_gid == 0)
375 warnx("line %d: wheel override "
376 "in YP inclusion", lineno);
377 }
378
379 /* Write the database entry out. */
380 if (!secureonly)
381 putdbents(dp, &pwd, "*", flags, pwd_db_tmp,
382 lineno, dbflg, uid_dbflg);
383 continue;
384 } else if (strcmp(username, pwd.pw_name) != 0)
385 continue;
386
387 if (found) {
388 warnx("user `%s' listed twice in password file",
389 username);
390 bailout();
391 }
392
393 /*
394 * Ensure that the text file and database agree on
395 * which line the record is from.
396 */
397 rv = getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYNUM, &lineno, &tpwd);
398 if (newuser) {
399 if (rv == 0)
400 inconsistancy();
401 } else if (rv == -1 ||
402 strcmp(username, tpwd->pw_name) != 0)
403 inconsistancy();
404 else if (olduid != pwd.pw_uid) {
405 /*
406 * If we're changing UID, remove the BYUID
407 * record for the old UID only if it has the
408 * same username.
409 */
410 if (!getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYUID, &olduid,
411 &tpwd)) {
412 if (strcmp(username, tpwd->pw_name) == 0) {
413 if (!secureonly)
414 deldbent(dp, pwd_db_tmp,
415 _PW_KEYBYUID, &olduid);
416 deldbent(edp, pwd_Sdb_tmp,
417 _PW_KEYBYUID, &olduid);
418 }
419 } else
420 inconsistancy();
421 }
422
423 /*
424 * If there's an existing BYUID record for the new UID and
425 * the username doesn't match then be sure not to overwrite
426 * it.
427 */
428 if (!getdbent(edp, pwd_Sdb_tmp, _PW_KEYBYUID, &pwd.pw_uid,
429 &tpwd))
430 if (strcmp(username, tpwd->pw_name) != 0)
431 uid_dbflg = R_NOOVERWRITE;
432
433 /* Write the database entries out */
434 if (!secureonly)
435 putdbents(dp, &pwd, "*", flags, pwd_db_tmp, lineno,
436 dbflg, uid_dbflg);
437 putdbents(edp, &pwd, pwd.pw_passwd, flags, pwd_Sdb_tmp,
438 lineno, dbflg, uid_dbflg);
439
440 found = 1;
441 if (!makeold)
442 break;
443 }
444
445 if (!secureonly) {
446 /* Store YP token if needed. */
447 if (hasyp)
448 putyptoken(dp, pwd_db_tmp);
449
450 /* Close the insecure database. */
451 if ((*dp->close)(dp) < 0)
452 wr_error(pwd_db_tmp);
453 }
454
455 /*
456 * If rebuilding the databases, we re-parse the text file and write
457 * the secure entries out in a separate pass.
458 */
459 if (username == NULL) {
460 rewind(fp);
461 for (lineno = 0; scan(fp, &pwd, &flags, &lineno);)
462 putdbents(edp, &pwd, pwd.pw_passwd, flags, pwd_Sdb_tmp,
463 lineno, dbflg, uid_dbflg);
464
465 /* Store YP token if needed. */
466 if (hasyp)
467 putyptoken(edp, pwd_Sdb_tmp);
468 } else if (!found) {
469 warnx("user `%s' not found in password file", username);
470 bailout();
471 }
472
473 /* Close the secure database. */
474 if ((*edp->close)(edp) < 0)
475 wr_error(pwd_Sdb_tmp);
476
477 /* Install as the real password files. */
478 if (!secureonly)
479 install(pwd_db_tmp, _PATH_MP_DB);
480 install(pwd_Sdb_tmp, _PATH_SMP_DB);
481
482 /* Install the V7 password file. */
483 if (makeold) {
484 if (fflush(oldfp) == EOF)
485 wr_error(oldpwdfile);
486 if (fclose(oldfp) == EOF)
487 wr_error(oldpwdfile);
488 install(oldpwdfile, _PATH_PASSWD);
489 }
490
491 /* Set master.passwd permissions, in case caller forgot. */
492 (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
493 if (fclose(fp) == EOF)
494 wr_error(pname);
495
496 /*
497 * Move the temporary master password file LAST -- chpass(1),
498 * passwd(1), vipw(8) and friends all use its existence to block
499 * other incarnations of themselves. The rename means that
500 * everything is unlocked, as the original file can no longer be
501 * accessed.
502 */
503 install(pname, _PATH_MASTERPASSWD);
504 exit(EXIT_SUCCESS);
505 /* NOTREACHED */
506 }
507
508 int
509 scan(FILE *fp, struct passwd *pw, int *flags, int *lineno)
510 {
511 static char line[LINE_MAX];
512 char *p;
513 int oflags;
514
515 if (fgets(line, sizeof(line), fp) == NULL)
516 return (0);
517 (*lineno)++;
518
519 /*
520 * ``... if I swallow anything evil, put your fingers down my
521 * throat...''
522 * -- The Who
523 */
524 if ((p = strchr(line, '\n')) == NULL) {
525 warnx("line too long");
526 errno = EFTYPE; /* XXX */
527 error(pname);
528 }
529 *p = '\0';
530 if (strcmp(line, "+") == 0)
531 strcpy(line, "+:::::::::"); /* pw_scan() can't handle "+" */
532 oflags = 0;
533 if (!pw_scan(line, pw, &oflags)) {
534 warnx("at line #%d", *lineno);
535 errno = EFTYPE; /* XXX */
536 error(pname);
537 }
538 *flags = oflags;
539
540 return (1);
541 }
542
543 void
544 install(const char *from, const char *to)
545 {
546 char buf[MAXPATHLEN];
547 char errbuf[BUFSIZ];
548 int sverrno;
549
550 snprintf(buf, sizeof(buf), "%s%s", prefix, to);
551 if (rename(from, buf)) {
552 sverrno = errno;
553 (void)snprintf(errbuf, sizeof(errbuf), "%s to %s", from, buf);
554 errno = sverrno;
555 error(errbuf);
556 }
557 }
558
559 void
560 rm(const char *victim)
561 {
562
563 if (unlink(victim) < 0)
564 warn("unlink(%s)", victim);
565 }
566
567 void
568 cp(const char *from, const char *to, mode_t mode)
569 {
570 static char buf[MAXBSIZE];
571 int from_fd, rcount, to_fd, wcount, sverrno;
572
573 if ((from_fd = open(from, O_RDONLY, 0)) < 0)
574 error(from);
575 if ((to_fd = open(to, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0)
576 error(to);
577 while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
578 wcount = write(to_fd, buf, rcount);
579 if (rcount != wcount || wcount == -1) {
580 sverrno = errno;
581 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
582 errno = sverrno;
583 error(buf);
584 }
585 }
586
587 if (rcount < 0) {
588 sverrno = errno;
589 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
590 errno = sverrno;
591 error(buf);
592 }
593 }
594
595 void
596 wr_error(const char *str)
597 {
598 char errbuf[BUFSIZ];
599 int sverrno;
600
601 sverrno = errno;
602
603 (void)snprintf(errbuf, sizeof(errbuf),
604 "attempt to write %s failed", str);
605
606 errno = sverrno;
607 error(errbuf);
608 }
609
610 void
611 error(const char *str)
612 {
613
614 warn("%s", str);
615 bailout();
616 }
617
618 void
619 inconsistancy(void)
620 {
621
622 warnx("text files and databases are inconsistent");
623 warnx("re-build the databases without -u");
624 bailout();
625 }
626
627 void
628 bailout(void)
629 {
630
631 if ((clean & FILE_ORIG) != 0)
632 rm(oldpwdfile);
633 if ((clean & FILE_SECURE) != 0)
634 rm(pwd_Sdb_tmp);
635 if ((clean & FILE_INSECURE) != 0)
636 rm(pwd_db_tmp);
637
638 exit(EXIT_FAILURE);
639 }
640
641 void
642 setversion(DB *dp)
643 {
644 DBT data, key;
645 uint32_t version = sizeof(time_t) != sizeof(int32_t);
646
647 key.data = __UNCONST("VERSION");
648 key.size = strlen((const char *)key.data) + 1;
649
650 if (lorder != BYTE_ORDER)
651 version = SWAP(version);
652 data.data = &version;
653 data.size = sizeof(uint32_t);
654
655 if ((*dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
656 wr_error("setversion");
657 }
658
659 /*
660 * Write entries to a database for a single user.
661 *
662 * The databases actually contain three copies of the original data. Each
663 * password file entry is converted into a rough approximation of a ``struct
664 * passwd'', with the strings placed inline. This object is then stored as
665 * the data for three separate keys. The first key * is the pw_name field
666 * prepended by the _PW_KEYBYNAME character. The second key is the pw_uid
667 * field prepended by the _PW_KEYBYUID character. The third key is the line
668 * number in the original file prepended by the _PW_KEYBYNUM character.
669 * (The special characters are prepended to ensure that the keys do not
670 * collide.)
671 */
672 #define COMPACT(e) for (t = e; (*p++ = *t++) != '\0';)
673
674 void
675 putdbents(DB *dp, struct passwd *pw, const char *passwd, int flags,
676 const char *fn, int lineno, int dbflg, int uid_dbflg)
677 {
678 struct passwd pwd;
679 char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024], *p;
680 DBT data, key;
681 const char *t;
682 u_int32_t x;
683 int len;
684
685 memcpy(&pwd, pw, sizeof(pwd));
686 data.data = (u_char *)buf;
687 key.data = (u_char *)tbuf;
688
689 if (lorder != BYTE_ORDER) {
690 pwd.pw_uid = SWAP(pwd.pw_uid);
691 pwd.pw_gid = SWAP(pwd.pw_gid);
692 pwd.pw_change = SWAP(pwd.pw_change);
693 pwd.pw_expire = SWAP(pwd.pw_expire);
694 }
695
696 /* Create insecure data. */
697 p = buf;
698 COMPACT(pwd.pw_name);
699 COMPACT(passwd);
700 memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid));
701 p += sizeof(pwd.pw_uid);
702 memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid));
703 p += sizeof(pwd.pw_gid);
704 memmove(p, &pwd.pw_change, sizeof(pwd.pw_change));
705 p += sizeof(pwd.pw_change);
706 COMPACT(pwd.pw_class);
707 COMPACT(pwd.pw_gecos);
708 COMPACT(pwd.pw_dir);
709 COMPACT(pwd.pw_shell);
710 memmove(p, &pwd.pw_expire, sizeof(pwd.pw_expire));
711 p += sizeof(pwd.pw_expire);
712 x = flags;
713 if (lorder != BYTE_ORDER)
714 x = SWAP(x);
715 memmove(p, &x, sizeof(x));
716 p += sizeof(flags);
717 data.size = p - buf;
718
719 /* Store insecure by name. */
720 tbuf[0] = _PW_KEYBYNAME;
721 len = strlen(pwd.pw_name);
722 memmove(tbuf + 1, pwd.pw_name, len);
723 key.size = len + 1;
724 if ((*dp->put)(dp, &key, &data, dbflg) == -1)
725 wr_error(fn);
726
727 /* Store insecure by number. */
728 tbuf[0] = _PW_KEYBYNUM;
729 x = lineno;
730 if (lorder != BYTE_ORDER)
731 x = SWAP(x);
732 memmove(tbuf + 1, &x, sizeof(x));
733 key.size = sizeof(x) + 1;
734 if ((*dp->put)(dp, &key, &data, dbflg) == -1)
735 wr_error(fn);
736
737 /* Store insecure by uid. */
738 tbuf[0] = _PW_KEYBYUID;
739 memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
740 key.size = sizeof(pwd.pw_uid) + 1;
741 if ((*dp->put)(dp, &key, &data, uid_dbflg) == -1)
742 wr_error(fn);
743 }
744
745 int
746 deldbent(DB *dp, const char *fn, int type, void *keyp)
747 {
748 char tbuf[1024];
749 DBT key;
750 u_int32_t x;
751 int len, rv;
752
753 key.data = (u_char *)tbuf;
754
755 switch (tbuf[0] = type) {
756 case _PW_KEYBYNAME:
757 len = strlen((char *)keyp);
758 memcpy(tbuf + 1, keyp, len);
759 key.size = len + 1;
760 break;
761
762 case _PW_KEYBYNUM:
763 case _PW_KEYBYUID:
764 x = *(int *)keyp;
765 if (lorder != BYTE_ORDER)
766 x = SWAP(x);
767 memmove(tbuf + 1, &x, sizeof(x));
768 key.size = sizeof(x) + 1;
769 break;
770 }
771
772 if ((rv = (*dp->del)(dp, &key, 0)) == -1)
773 wr_error(fn);
774 return (rv);
775 }
776
777 int
778 getdbent(DB *dp, const char *fn, int type, void *keyp, struct passwd **tpwd)
779 {
780 static char buf[MAX(MAXPATHLEN, LINE_MAX * 2)];
781 static struct passwd pwd;
782 char tbuf[1024], *p;
783 DBT key, data;
784 u_int32_t x;
785 int len, rv;
786
787 data.data = (u_char *)buf;
788 data.size = sizeof(buf);
789 key.data = (u_char *)tbuf;
790
791 switch (tbuf[0] = type) {
792 case _PW_KEYBYNAME:
793 len = strlen((char *)keyp);
794 memcpy(tbuf + 1, keyp, len);
795 key.size = len + 1;
796 break;
797
798 case _PW_KEYBYNUM:
799 case _PW_KEYBYUID:
800 x = *(int *)keyp;
801 if (lorder != BYTE_ORDER)
802 x = SWAP(x);
803 memmove(tbuf + 1, &x, sizeof(x));
804 key.size = sizeof(x) + 1;
805 break;
806 }
807
808 if ((rv = (*dp->get)(dp, &key, &data, 0)) == 1)
809 return (rv);
810 if (rv == -1)
811 error(pwd_Sdb_tmp);
812
813 p = (char *)data.data;
814
815 pwd.pw_name = p;
816 while (*p++ != '\0')
817 ;
818 pwd.pw_passwd = p;
819 while (*p++ != '\0')
820 ;
821
822 memcpy(&pwd.pw_uid, p, sizeof(pwd.pw_uid));
823 p += sizeof(pwd.pw_uid);
824 memcpy(&pwd.pw_gid, p, sizeof(pwd.pw_gid));
825 p += sizeof(pwd.pw_gid);
826 memcpy(&pwd.pw_change, p, sizeof(pwd.pw_change));
827 p += sizeof(pwd.pw_change);
828
829 pwd.pw_class = p;
830 while (*p++ != '\0')
831 ;
832 pwd.pw_gecos = p;
833 while (*p++ != '\0')
834 ;
835 pwd.pw_dir = p;
836 while (*p++ != '\0')
837 ;
838 pwd.pw_shell = p;
839 while (*p++ != '\0')
840 ;
841
842 memcpy(&pwd.pw_expire, p, sizeof(pwd.pw_expire));
843 p += sizeof(pwd.pw_expire);
844
845 if (lorder != BYTE_ORDER) {
846 pwd.pw_uid = SWAP(pwd.pw_uid);
847 pwd.pw_gid = SWAP(pwd.pw_gid);
848 pwd.pw_change = SWAP(pwd.pw_change);
849 pwd.pw_expire = SWAP(pwd.pw_expire);
850 }
851
852 *tpwd = &pwd;
853 return (0);
854 }
855
856 void
857 putyptoken(DB *dp, const char *fn)
858 {
859 DBT data, key;
860
861 key.data = (u_char *)__yp_token;
862 key.size = strlen(__yp_token);
863 data.data = (u_char *)NULL;
864 data.size = 0;
865
866 if ((*dp->put)(dp, &key, &data, R_NOOVERWRITE) == -1)
867 wr_error(fn);
868 }
869
870 void
871 usage(void)
872 {
873
874 (void)fprintf(stderr,
875 "usage: pwd_mkdb [-BLps] [-c cachesize] [-d directory] [-u user] file\n");
876 exit(EXIT_FAILURE);
877 }
878