Bug Summary

File:src/usr.sbin/pwd_mkdb/pwd_mkdb.c
Warning:line 299, column 2
8th function call argument is an uninitialized value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name pwd_mkdb.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/pwd_mkdb/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/pwd_mkdb/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/pwd_mkdb/pwd_mkdb.c
1/* $OpenBSD: pwd_mkdb.c,v 1.59 2021/11/28 19:28:42 deraadt 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 * Portions Copyright (c) 1998, Todd C. Miller. All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <sys/types.h>
35#include <sys/stat.h>
36
37#include <db.h>
38#include <err.h>
39#include <errno(*__errno()).h>
40#include <fcntl.h>
41#include <grp.h>
42#include <limits.h>
43#include <pwd.h>
44#include <signal.h>
45#include <stdarg.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <unistd.h>
50#include <limits.h>
51#include <util.h>
52
53#define MINIMUM(a, b)(((a) < (b)) ? (a) : (b)) (((a) < (b)) ? (a) : (b))
54#define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b))
55#define _MAXBSIZE(64 * 1024) (64 * 1024)
56
57#define INSECURE1 1
58#define SECURE2 2
59#define PERM_INSECURE(0000400|0000200|0000040|0000004) (S_IRUSR0000400|S_IWUSR0000200|S_IRGRP0000040|S_IROTH0000004)
60#define PERM_SECURE(0000400|0000200) (S_IRUSR0000400|S_IWUSR0000200)
61
62#define FILE_SECURE0x01 0x01
63#define FILE_INSECURE0x02 0x02
64#define FILE_ORIG0x04 0x04
65
66#define SHADOW_GROUP"_shadow" "_shadow"
67
68HASHINFO openinfo = {
69 4096, /* bsize */
70 32, /* ffactor */
71 256, /* nelem */
72 2048 * 1024, /* cachesize */
73 NULL((void *)0), /* hash() */
74 0 /* lorder */
75};
76
77static char *pname; /* password file name */
78static char *basedir; /* dir holding master.passwd */
79static int clean; /* what to remove on cleanup */
80static int hasyp; /* are we running YP? */
81
82void cleanup(void);
83__dead__attribute__((__noreturn__)) void fatal(const char *, ...)
84 __attribute__((__format__ (printf, 1, 2)));
85__dead__attribute__((__noreturn__)) void fatalc(int, const char *, ...)
86 __attribute__((__format__ (printf, 2, 3)));
87__dead__attribute__((__noreturn__)) void fatalx(const char *, ...)
88 __attribute__((__format__ (printf, 1, 2)));
89int write_old_entry(FILE *, const struct passwd *);
90
91void cp(char *, char *, mode_t);
92void mv(char *, char *);
93int scan(FILE *, struct passwd *, int *);
94void usage(void);
95char *changedir(char *path, char *dir);
96void db_store(FILE *, FILE *, DB *, DB *,struct passwd *, int, char *, uid_t);
97
98int
99main(int argc, char **argv)
100{
101 DB *dp, *edp;
102 DBT data, key;
103 FILE *fp, *oldfp = NULL((void *)0);
104 struct stat st;
105 struct passwd pwd;
106 struct group *grp;
107 sigset_t set;
108 uid_t olduid;
1
'olduid' declared without an initial value
109 gid_t shadow;
110 int ch, tfd, makeold, secureonly, flags, checkonly;
111 char *username, buf[MAXIMUM(PATH_MAX, LINE_MAX * 2)(((1024) > (2048 * 2)) ? (1024) : (2048 * 2))];
112
113 flags = checkonly = makeold = secureonly = 0;
114 username = NULL((void *)0);
115 while ((ch = getopt(argc, argv, "cd:psu:v")) != -1)
2
Assuming the condition is false
3
Loop condition is false. Execution continues on line 142
116 switch (ch) {
117 case 'c': /* verify only */
118 checkonly = 1;
119 break;
120 case 'd':
121 basedir = optarg;
122 if (strlen(basedir) > PATH_MAX1024 - 40)
123 errx(1, "basedir too long");
124 break;
125 case 'p': /* create V7 "file.orig" */
126 makeold = 1;
127 break;
128 case 's': /* only update spwd.db */
129 secureonly = 1;
130 break;
131 case 'u': /* only update this record */
132 username = optarg;
133 if (strlen(username) > _PW_NAME_LEN31)
134 errx(1, "username too long");
135 break;
136 case 'v': /* backward compatible */
137 break;
138 case '?':
139 default:
140 usage();
141 }
142 argc -= optind;
143 argv += optind;
144
145 if (argc != 1 || (makeold
4.1
'makeold' is 0
&& secureonly) ||
4
Assuming 'argc' is equal to 1
146 (username
4.2
'username' is null
&& (*username == '+' || *username == '-')))
147 usage();
148
149 if ((grp = getgrnam(SHADOW_GROUP"_shadow")) == NULL((void *)0))
5
Assuming the condition is false
6
Taking false branch
150 errx(1, "cannot find `%s' in the group database, aborting",
151 SHADOW_GROUP"_shadow");
152 shadow = grp->gr_gid;
153
154 /*
155 * This could be changed to allow the user to interrupt.
156 * Probably not worth the effort.
157 */
158 sigemptyset(&set);
159 sigaddset(&set, SIGTSTP18);
160 sigaddset(&set, SIGHUP1);
161 sigaddset(&set, SIGINT2);
162 sigaddset(&set, SIGQUIT3);
163 sigaddset(&set, SIGTERM15);
164 (void)sigprocmask(SIG_BLOCK1, &set, (sigset_t *)NULL((void *)0));
165
166 /* We don't care what the user wants. */
167 (void)umask(0);
168
169 if (**argv != '/' && basedir == NULL((void *)0))
7
Assuming the condition is false
170 errx(1, "%s must be specified as an absolute path", *argv);
171
172 if ((pname = strdup(changedir(*argv, basedir))) == NULL((void *)0))
8
Assuming the condition is false
9
Taking false branch
173 err(1, NULL((void *)0));
174 /* Open the original password file */
175 if (!(fp = fopen(pname, "r")))
10
Assuming 'fp' is non-null
11
Taking false branch
176 fatal("%s", pname);
177
178 /* Check only if password database is valid */
179 if (checkonly
11.1
'checkonly' is 0
) {
12
Taking false branch
180 u_int cnt;
181
182 for (cnt = 1; scan(fp, &pwd, &flags); ++cnt)
183 ;
184 exit(0);
185 }
186
187 if (fstat(fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), &st) == -1)
13
Assuming '__isthreaded' is 0
14
'?' condition is true
15
Assuming the condition is false
16
Taking false branch
188 fatal("%s", pname);
189
190 /* Tweak openinfo values for large passwd files. */
191 if (st.st_size > (off_t)100*1024)
17
Assuming the condition is false
18
Taking false branch
192 openinfo.cachesize = MINIMUM(st.st_size * 20, (off_t)12*1024*1024)(((st.st_size * 20) < ((off_t)12*1024*1024)) ? (st.st_size
* 20) : ((off_t)12*1024*1024))
;
193 /* Estimate number of elements based on a 128-byte average entry. */
194 if (st.st_size / 128 * 3 > openinfo.nelem)
19
Assuming the condition is false
20
Taking false branch
195 openinfo.nelem = st.st_size / 128 * 3;
196
197 /* If only updating a single record, stash the old uid */
198 if (username
20.1
'username' is null
) {
21
Taking false branch
199 dp = dbopen(_PATH_MP_DB"/etc/pwd.db", O_RDONLY0x0000, 0, DB_HASH, NULL((void *)0));
200 if (dp == NULL((void *)0))
201 fatal(_PATH_MP_DB"/etc/pwd.db");
202 buf[0] = _PW_KEYBYNAME'1';
203 strlcpy(buf + 1, username, sizeof(buf) - 1);
204 key.data = (u_char *)buf;
205 key.size = strlen(buf + 1) + 1;
206 if ((dp->get)(dp, &key, &data, 0) == 0) {
207 char *p = (char *)data.data;
208 /* Skip to uid field */
209 while (*p++ != '\0')
210 ;
211 while (*p++ != '\0')
212 ;
213 memcpy(&olduid, p, sizeof(olduid));
214 } else
215 olduid = -1;
216 (dp->close)(dp);
217 }
218
219 /* Open the temporary encrypted password database. */
220 (void)snprintf(buf, sizeof(buf), "%s.tmp",
221 changedir(_PATH_SMP_DB"/etc/spwd.db", basedir));
222 if (username
21.1
'username' is null
) {
22
Taking false branch
223 cp(changedir(_PATH_SMP_DB"/etc/spwd.db", basedir), buf, PERM_SECURE(0000400|0000200));
224 edp = dbopen(buf,
225 O_RDWR0x0002, PERM_SECURE(0000400|0000200), DB_HASH, &openinfo);
226 } else {
227 edp = dbopen(buf,
228 O_RDWR0x0002|O_CREAT0x0200|O_EXCL0x0800, PERM_SECURE(0000400|0000200), DB_HASH, &openinfo);
229 }
230 if (!edp)
23
Assuming 'edp' is non-null
24
Taking false branch
231 fatal("%s", buf);
232 if (fchown(edp->fd(edp), -1, shadow) != 0)
25
Assuming the condition is true
26
Taking true branch
233 warn("%s: unable to set group to %s", _PATH_SMP_DB"/etc/spwd.db",
234 SHADOW_GROUP"_shadow");
235 else if (fchmod(edp->fd(edp), PERM_SECURE(0000400|0000200)|S_IRGRP0000040) != 0)
236 warn("%s: unable to make group readable", _PATH_SMP_DB"/etc/spwd.db");
237 clean |= FILE_SECURE0x01;
238
239 if (pledge("stdio rpath wpath cpath getpw fattr flock", NULL((void *)0)) == -1)
27
Assuming the condition is false
28
Taking false branch
240 err(1, "pledge");
241
242 /* Open the temporary insecure password database. */
243 if (!secureonly
28.1
'secureonly' is 0
) {
29
Taking true branch
244 (void)snprintf(buf, sizeof(buf), "%s.tmp",
245 changedir(_PATH_MP_DB"/etc/pwd.db", basedir));
246 if (username
29.1
'username' is null
) {
30
Taking false branch
247 cp(changedir(_PATH_MP_DB"/etc/pwd.db", basedir), buf, PERM_INSECURE(0000400|0000200|0000040|0000004));
248 dp = dbopen(buf, O_RDWR0x0002, PERM_INSECURE(0000400|0000200|0000040|0000004), DB_HASH,
249 &openinfo);
250 } else {
251 dp = dbopen(buf, O_RDWR0x0002|O_CREAT0x0200|O_EXCL0x0800, PERM_INSECURE(0000400|0000200|0000040|0000004),
252 DB_HASH, &openinfo);
253 }
254 if (dp == NULL((void *)0))
31
Assuming 'dp' is not equal to NULL
32
Taking false branch
255 fatal("%s", buf);
256 clean |= FILE_INSECURE0x02;
257 } else
258 dp = NULL((void *)0);
259
260 /*
261 * Open file for old password file. Minor trickiness -- don't want to
262 * change the file already existing, since someone (stupidly) might
263 * still be using this for permission checking. So, open it first and
264 * fdopen the resulting fd. The resulting file should be readable by
265 * everyone.
266 */
267 if (makeold
32.1
'makeold' is 0
) {
33
Taking false branch
268 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
269 if ((tfd = open(buf,
270 O_WRONLY0x0001|O_CREAT0x0200|O_EXCL0x0800, PERM_INSECURE(0000400|0000200|0000040|0000004))) == -1)
271 fatal("%s", buf);
272 if ((oldfp = fdopen(tfd, "w")) == NULL((void *)0))
273 fatal("%s", buf);
274 clean |= FILE_ORIG0x04;
275 }
276
277 /*
278 * The databases actually contain three copies of the original data.
279 * Each password file entry is converted into a rough approximation
280 * of a ``struct passwd'', with the strings placed inline. This
281 * object is then stored as the data for three separate keys. The
282 * first key * is the pw_name field prepended by the _PW_KEYBYNAME
283 * character. The second key is the pw_uid field prepended by the
284 * _PW_KEYBYUID character. The third key is the line number in the
285 * original file prepended by the _PW_KEYBYNUM character. (The special
286 * characters are prepended to ensure that the keys do not collide.)
287 *
288 * If we see something go by that looks like YP, we save a special
289 * pointer record, which if YP is enabled in the C lib, will speed
290 * things up.
291 */
292
293 /*
294 * Write the .db files.
295 * We do this three times, one per key type (for getpw{nam,uid,ent}).
296 * The first time through we also check for YP, issue warnings
297 * and save the V7 format passwd file if necessary.
298 */
299 db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYNAME'1', username, olduid);
34
8th function call argument is an uninitialized value
300 db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYUID'3', username, olduid);
301 db_store(fp, oldfp, edp, dp, &pwd, _PW_KEYBYNUM'2', username, olduid);
302
303 /* Store YP token, if needed. */
304 if (hasyp && !username) {
305 key.data = (u_char *)_PW_YPTOKEN"__YP!";
306 key.size = strlen(_PW_YPTOKEN"__YP!");
307 data.data = (u_char *)NULL((void *)0);
308 data.size = 0;
309
310 if ((edp->put)(edp, &key, &data, R_NOOVERWRITE8) == -1)
311 fatal("put");
312
313 if (dp && (dp->put)(dp, &key, &data, R_NOOVERWRITE8) == -1)
314 fatal("put");
315 }
316
317 if ((edp->close)(edp))
318 fatal("close edp");
319 if (dp && (dp->close)(dp))
320 fatal("close dp");
321 if (makeold) {
322 if (fclose(oldfp) == EOF(-1))
323 fatal("close old");
324 }
325
326 /* Set master.passwd permissions, in case caller forgot. */
327 (void)fchmod(fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), S_IRUSR0000400|S_IWUSR0000200);
328 if (fclose(fp) != 0)
329 fatal("fclose");
330
331 /* Install as the real password files. */
332 if (!secureonly) {
333 (void)snprintf(buf, sizeof(buf), "%s.tmp",
334 changedir(_PATH_MP_DB"/etc/pwd.db", basedir));
335 mv(buf, changedir(_PATH_MP_DB"/etc/pwd.db", basedir));
336 }
337 (void)snprintf(buf, sizeof(buf), "%s.tmp",
338 changedir(_PATH_SMP_DB"/etc/spwd.db", basedir));
339 mv(buf, changedir(_PATH_SMP_DB"/etc/spwd.db", basedir));
340 if (makeold) {
341 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
342 mv(buf, changedir(_PATH_PASSWD"/etc/passwd", basedir));
343 }
344
345 /*
346 * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
347 * all use flock(2) on it to block other incarnations of themselves.
348 * The rename means that everything is unlocked, as the original file
349 * can no longer be accessed.
350 */
351 mv(pname, changedir(_PATH_MASTERPASSWD"/etc/master.passwd", basedir));
352 exit(0);
353}
354
355int
356scan(FILE *fp, struct passwd *pw, int *flags)
357{
358 static int lcnt;
359 static char line[LINE_MAX2048];
360 char *p;
361
362 if (fgets(line, sizeof(line), fp) == NULL((void *)0))
363 return (0);
364 ++lcnt;
365 /*
366 * ``... if I swallow anything evil, put your fingers down my
367 * throat...''
368 * -- The Who
369 */
370 p = line;
371 if (*p != '\0' && *(p += strlen(line) - 1) != '\n') {
372 warnx("line too long");
373 goto fmt;
374 }
375 *p = '\0';
376 *flags = 0;
377 if (!pw_scan(line, pw, flags)) {
378 warnx("at line #%d", lcnt);
379fmt: fatalc(EFTYPE79, "%s", pname);
380 }
381
382 return (1);
383}
384
385void
386cp(char *from, char *to, mode_t mode)
387{
388 static char buf[_MAXBSIZE(64 * 1024)];
389 int from_fd, rcount, to_fd, wcount;
390
391 if ((from_fd = open(from, O_RDONLY0x0000)) == -1)
392 fatal("%s", from);
393 if ((to_fd = open(to, O_WRONLY0x0001|O_CREAT0x0200|O_EXCL0x0800, mode)) == -1)
394 fatal("%s", to);
395 while ((rcount = read(from_fd, buf, sizeof buf)) > 0) {
396 wcount = write(to_fd, buf, rcount);
397 if (rcount != wcount || wcount == -1)
398 fatal("%s to %s", from, to);
399 }
400 if (rcount == -1)
401 fatal("%s to %s", from, to);
402 close(to_fd);
403 close(from_fd);
404}
405
406void
407mv(char *from, char *to)
408{
409 if (rename(from, to))
410 fatal("%s to %s", from, to);
411}
412
413void
414fatal(const char *fmt, ...)
415{
416 va_list ap;
417
418 va_start(ap, fmt)__builtin_va_start(ap, fmt);
419 vwarn(fmt, ap);
420 va_end(ap)__builtin_va_end(ap);
421 cleanup();
422 exit(EXIT_FAILURE1);
423}
424
425void
426fatalc(int code, const char *fmt, ...)
427{
428 va_list ap;
429
430 va_start(ap, fmt)__builtin_va_start(ap, fmt);
431 vwarnc(code, fmt, ap);
432 va_end(ap)__builtin_va_end(ap);
433 cleanup();
434 exit(EXIT_FAILURE1);
435}
436
437void
438fatalx(const char *fmt, ...)
439{
440 va_list ap;
441
442 va_start(ap, fmt)__builtin_va_start(ap, fmt);
443 vwarnx(fmt, ap);
444 va_end(ap)__builtin_va_end(ap);
445 cleanup();
446 exit(EXIT_FAILURE1);
447}
448
449void
450cleanup(void)
451{
452 char buf[PATH_MAX1024];
453
454 if (clean & FILE_ORIG0x04) {
455 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
456 (void)unlink(buf);
457 }
458 if (clean & FILE_SECURE0x01) {
459 (void)snprintf(buf, sizeof(buf), "%s.tmp",
460 changedir(_PATH_SMP_DB"/etc/spwd.db", basedir));
461 (void)unlink(buf);
462 }
463 if (clean & FILE_INSECURE0x02) {
464 (void)snprintf(buf, sizeof(buf), "%s.tmp",
465 changedir(_PATH_MP_DB"/etc/pwd.db", basedir));
466 (void)unlink(buf);
467 }
468}
469
470void
471usage(void)
472{
473 (void)fprintf(stderr(&__sF[2]),
474 "usage: pwd_mkdb [-c] [-p | -s] [-d directory] [-u username] file\n");
475 exit(EXIT_FAILURE1);
476}
477
478char *
479changedir(char *path, char *dir)
480{
481 static char fixed[PATH_MAX1024];
482 char *p;
483
484 if (!dir)
485 return (path);
486
487 if ((p = strrchr(path, '/')) != NULL((void *)0))
488 path = p + 1;
489 snprintf(fixed, sizeof(fixed), "%s/%s", dir, path);
490 return (fixed);
491}
492
493int
494write_old_entry(FILE *to, const struct passwd *pw)
495{
496 char gidstr[16], uidstr[16];
497
498 if (to == NULL((void *)0))
499 return (0);
500
501 /* Preserve gid/uid -1 */
502 if (pw->pw_gid == (gid_t)-1)
503 strlcpy(gidstr, "-1", sizeof(gidstr));
504 else
505 snprintf(gidstr, sizeof(gidstr), "%u", (u_int)pw->pw_gid);
506
507 if (pw->pw_uid == -1)
508 strlcpy(uidstr, "-1", sizeof(uidstr));
509 else
510 snprintf(uidstr, sizeof(uidstr), "%u", (u_int)pw->pw_uid);
511
512 return (fprintf(to, "%s:*:%s:%s:%s:%s:%s\n", pw->pw_name, uidstr,
513 gidstr, pw->pw_gecos, pw->pw_dir, pw->pw_shell));
514}
515
516void
517db_store(FILE *fp, FILE *oldfp, DB *edp, DB *dp, struct passwd *pw,
518 int keytype, char *username, uid_t olduid)
519{
520 char *p, *t, buf[LINE_MAX2048 * 2], tbuf[_PW_BUF_LEN1024];
521 int flags = 0, dbmode, found = 0;
522 static int firsttime = 1;
523 DBT data, key;
524 size_t len;
525 u_int cnt;
526
527 /* If given a username just add that record to the existing db. */
528 dbmode = username ? 0 : R_NOOVERWRITE8;
529
530 rewind(fp);
531 data.data = (u_char *)buf;
532 key.data = (u_char *)tbuf;
533 for (cnt = 1; scan(fp, pw, &flags); ++cnt) {
534
535 if (firsttime) {
536 /* Look like YP? */
537 if ((pw->pw_name[0] == '+') || (pw->pw_name[0] == '-'))
538 hasyp++;
539
540 /* Warn about potentially unsafe uid/gid overrides. */
541 if (pw->pw_name[0] == '+') {
542 if (!(flags & _PASSWORD_NOUID0x01) && !pw->pw_uid)
543 warnx("line %d: superuser override in "
544 "YP inclusion", cnt);
545 if (!(flags & _PASSWORD_NOGID0x02) && !pw->pw_gid)
546 warnx("line %d: wheel override in "
547 "YP inclusion", cnt);
548 }
549
550 /* Create V7 format password file entry. */
551 if (write_old_entry(oldfp, pw) == -1)
552 fatal("write old");
553 }
554
555 /* Are we updating a specific record? */
556 if (username) {
557 if (strcmp(username, pw->pw_name) != 0)
558 continue;
559 found = 1;
560 /* If the uid changed, remove the old record by uid. */
561 if (olduid != -1 && olduid != pw->pw_uid) {
562 tbuf[0] = _PW_KEYBYUID'3';
563 memcpy(tbuf + 1, &olduid, sizeof(olduid));
564 key.size = sizeof(olduid) + 1;
565 (edp->del)(edp, &key, 0);
566 if (dp)
567 (dp->del)(dp, &key, 0);
568 }
569 /* XXX - should check to see if line number changed. */
570 }
571
572 /* Build the key. */
573 tbuf[0] = keytype;
574 switch (keytype) {
575 case _PW_KEYBYNUM'2':
576 memmove(tbuf + 1, &cnt, sizeof(cnt));
577 key.size = sizeof(cnt) + 1;
578 break;
579
580 case _PW_KEYBYNAME'1':
581 len = strlen(pw->pw_name);
582 memmove(tbuf + 1, pw->pw_name, len);
583 key.size = len + 1;
584 break;
585
586 case _PW_KEYBYUID'3':
587 memmove(tbuf + 1, &pw->pw_uid, sizeof(pw->pw_uid));
588 key.size = sizeof(pw->pw_uid) + 1;
589 break;
590 }
591
592#define COMPACT(e)t = e; while ((*p++ = *t++)); t = e; while ((*p++ = *t++));
593 /* Create the secure record. */
594 p = buf;
595 COMPACT(pw->pw_name)t = pw->pw_name; while ((*p++ = *t++));;
596 COMPACT(pw->pw_passwd)t = pw->pw_passwd; while ((*p++ = *t++));;
597 memmove(p, &pw->pw_uid, sizeof(uid_t));
598 p += sizeof(uid_t);
599 memmove(p, &pw->pw_gid, sizeof(gid_t));
600 p += sizeof(gid_t);
601 memmove(p, &pw->pw_change, sizeof(time_t));
602 p += sizeof(time_t);
603 COMPACT(pw->pw_class)t = pw->pw_class; while ((*p++ = *t++));;
604 COMPACT(pw->pw_gecos)t = pw->pw_gecos; while ((*p++ = *t++));;
605 COMPACT(pw->pw_dir)t = pw->pw_dir; while ((*p++ = *t++));;
606 COMPACT(pw->pw_shell)t = pw->pw_shell; while ((*p++ = *t++));;
607 memmove(p, &pw->pw_expire, sizeof(time_t));
608 p += sizeof(time_t);
609 memmove(p, &flags, sizeof(int));
610 p += sizeof(int);
611 data.size = p - buf;
612
613 /* Write the secure record. */
614 if ((edp->put)(edp, &key, &data, dbmode) == -1)
615 fatal("put");
616
617 if (dp == NULL((void *)0))
618 continue;
619
620 /* Star out password to make insecure record. */
621 p = buf + strlen(pw->pw_name) + 1; /* skip pw_name */
622 len = strlen(pw->pw_passwd);
623 explicit_bzero(p, len); /* zero pw_passwd */
624 t = p + len + 1; /* skip pw_passwd */
625 if (len != 0)
626 *p++ = '*';
627 *p++ = '\0';
628 memmove(p, t, data.size - (t - buf));
629 data.size -= len - 1;
630
631 /* Write the insecure record. */
632 if ((dp->put)(dp, &key, &data, dbmode) == -1)
633 fatal("put");
634 }
635 if (firsttime) {
636 firsttime = 0;
637 if (username && !found && olduid != -1)
638 fatalx("can't find user in master.passwd");
639 }
640}