]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pwd_mkdb/pwd_mkdb.c
This commit was generated by cvs2svn to compensate for changes in r138298,
[FreeBSD/FreeBSD.git] / usr.sbin / pwd_mkdb / pwd_mkdb.c
1 /*-
2  * Copyright (c) 1991, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #if 0
31 #ifndef lint
32 static const char copyright[] =
33 "@(#) Copyright (c) 1991, 1993, 1994\n\
34         The Regents of the University of California.  All rights reserved.\n";
35 #endif /* not lint */
36
37 #ifndef lint
38 static char sccsid[] = "@(#)pwd_mkdb.c  8.5 (Berkeley) 4/20/94";
39 #endif /* not lint */
40 #endif
41 #include <sys/cdefs.h>
42 __FBSDID("$FreeBSD$");
43
44 #include <sys/param.h>
45 #include <sys/stat.h>
46 #include <arpa/inet.h>
47
48 #include <db.h>
49 #include <err.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <limits.h>
53 #include <pwd.h>
54 #include <signal.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <unistd.h>
59
60 #include "pw_scan.h"
61
62 #define INSECURE        1
63 #define SECURE          2
64 #define PERM_INSECURE   (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
65 #define PERM_SECURE     (S_IRUSR|S_IWUSR)
66 #define LEGACY_VERSION(x)  _PW_VERSIONED(x, 3)
67 #define CURRENT_VERSION(x) _PW_VERSIONED(x, 4)
68
69 HASHINFO openinfo = {
70         4096,           /* bsize */
71         32,             /* ffactor */
72         256,            /* nelem */
73         2048 * 1024,    /* cachesize */
74         NULL,           /* hash() */
75         0               /* lorder */
76 };
77
78 static enum state { FILE_INSECURE, FILE_SECURE, FILE_ORIG } clean;
79 static struct passwd pwd;                       /* password structure */
80 static char *pname;                             /* password file name */
81 static char prefix[MAXPATHLEN];
82
83 static int is_comment;  /* flag for comments */
84 static char line[LINE_MAX];
85
86 void    cleanup(void);
87 void    error(const char *);
88 void    cp(char *, char *, mode_t mode);
89 void    mv(char *, char *);
90 int     scan(FILE *, struct passwd *);
91 static void     usage(void);
92
93 int
94 main(int argc, char *argv[])
95 {
96         static char verskey[] = _PWD_VERSION_KEY;
97         char version = _PWD_CURRENT_VERSION;
98         DB *dp, *sdp, *pw_db;
99         DBT data, sdata, key;
100         FILE *fp, *oldfp;
101         sigset_t set;
102         int ch, cnt, ypcnt, makeold, tfd, yp_enabled = 0;
103         unsigned int len;
104         int32_t pw_change, pw_expire;
105         uint32_t store;
106         const char *t;
107         char *p;
108         char buf[MAX(MAXPATHLEN, LINE_MAX * 2)], tbuf[1024];
109         char sbuf[MAX(MAXPATHLEN, LINE_MAX * 2)];
110         char buf2[MAXPATHLEN];
111         char sbuf2[MAXPATHLEN];
112         char *username;
113         u_int method, methoduid;
114         int Cflag, dflag, iflag;
115         int nblock = 0;
116
117         iflag = dflag = Cflag = 0;
118         strcpy(prefix, _PATH_PWD);
119         makeold = 0;
120         username = NULL;
121         while ((ch = getopt(argc, argv, "CNd:ips:u:v")) != -1)
122                 switch(ch) {
123                 case 'C':                       /* verify only */
124                         Cflag = 1;
125                         break;
126                 case 'N':                       /* do not wait for lock */
127                         nblock = LOCK_NB;       /* will fail if locked */
128                         break;
129                 case 'd':
130                         dflag++;
131                         strlcpy(prefix, optarg, sizeof(prefix));
132                         break;
133                 case 'i':
134                         iflag++;
135                         break;
136                 case 'p':                       /* create V7 "file.orig" */
137                         makeold = 1;
138                         break;
139                 case 's':                       /* change default cachesize */
140                         openinfo.cachesize = atoi(optarg) * 1024 * 1024;
141                         break;
142                 case 'u':                       /* only update this record */
143                         username = optarg;
144                         break;
145                 case 'v':                       /* backward compatible */
146                         break;
147                 default:
148                         usage();
149                 }
150         argc -= optind;
151         argv += optind;
152
153         if (argc != 1 || (username && (*username == '+' || *username == '-')))
154                 usage();
155
156         /*
157          * This could be changed to allow the user to interrupt.
158          * Probably not worth the effort.
159          */
160         sigemptyset(&set);
161         sigaddset(&set, SIGTSTP);
162         sigaddset(&set, SIGHUP);
163         sigaddset(&set, SIGINT);
164         sigaddset(&set, SIGQUIT);
165         sigaddset(&set, SIGTERM);
166         (void)sigprocmask(SIG_BLOCK, &set, (sigset_t *)NULL);
167
168         /* We don't care what the user wants. */
169         (void)umask(0);
170
171         pname = *argv;
172
173         /*
174          * Open and lock the original password file.  We have to check
175          * the hardlink count after we get the lock to handle any potential
176          * unlink/rename race.
177          *
178          * This lock is necessary when someone runs pwd_mkdb manually, directly
179          * on master.passwd, to handle the case where a user might try to
180          * change his password while pwd_mkdb is running. 
181          */
182         for (;;) {
183                 struct stat st;
184
185                 if (!(fp = fopen(pname, "r")))
186                         error(pname);
187                 if (flock(fileno(fp), LOCK_EX|nblock) < 0 && !(dflag && iflag))
188                         error("flock");
189                 if (fstat(fileno(fp), &st) < 0)
190                         error(pname);
191                 if (st.st_nlink != 0)
192                         break;
193                 fclose(fp);
194                 fp = NULL;
195         }
196
197         /* check only if password database is valid */
198         if (Cflag) {
199                 for (cnt = 1; scan(fp, &pwd); ++cnt);
200                 exit(0);
201         }
202
203         /* Open the temporary insecure password database. */
204         (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB);
205         (void)snprintf(sbuf, sizeof(sbuf), "%s/%s.tmp", prefix, _SMP_DB);
206         if (username) {
207                 int use_version;
208
209                 (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB);
210                 (void)snprintf(sbuf2, sizeof(sbuf2), "%s/%s", prefix, _SMP_DB);
211
212                 clean = FILE_INSECURE;
213                 cp(buf2, buf, PERM_INSECURE);
214                 dp = dbopen(buf,
215                     O_RDWR|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
216                 if (dp == NULL)
217                         error(buf);
218
219                 clean = FILE_SECURE;
220                 cp(sbuf2, sbuf, PERM_SECURE);
221                 sdp = dbopen(sbuf,
222                     O_RDWR|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
223                 if (sdp == NULL)
224                         error(sbuf);
225
226                 /*
227                  * Do some trouble to check if we should store this users 
228                  * uid. Don't use getpwnam/getpwuid as that interferes 
229                  * with NIS.
230                  */
231                 pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
232                 if (!pw_db)
233                         error(_MP_DB);
234
235                 key.data = verskey;
236                 key.size = sizeof(verskey)-1;
237                 if ((pw_db->get)(pw_db, &key, &data, 0) == 0)
238                         use_version = *(unsigned char *)data.data;
239                 else
240                         use_version = 3;
241                 buf[0] = _PW_VERSIONED(_PW_KEYBYNAME, use_version);
242                 len = strlen(username);
243
244                 /* Only check that username fits in buffer */
245                 memmove(buf + 1, username, MIN(len, sizeof(buf) - 1));
246                 key.data = (u_char *)buf;
247                 key.size = len + 1;
248                 if ((pw_db->get)(pw_db, &key, &data, 0) == 0) {
249                         p = (char *)data.data;
250
251                         /* jump over pw_name and pw_passwd, to get to pw_uid */
252                         while (*p++)
253                                 ;
254                         while (*p++)
255                                 ;
256
257                         buf[0] = _PW_VERSIONED(_PW_KEYBYUID, use_version);
258                         memmove(buf + 1, p, sizeof(store));
259                         key.data = (u_char *)buf;
260                         key.size = sizeof(store) + 1;
261
262                         if ((pw_db->get)(pw_db, &key, &data, 0) == 0) {
263                                 /* First field of data.data holds pw_pwname */
264                                 if (!strcmp(data.data, username))
265                                         methoduid = 0;
266                                 else
267                                         methoduid = R_NOOVERWRITE;
268                         } else {
269                                 methoduid = R_NOOVERWRITE;
270                         }
271                 } else {
272                         methoduid = R_NOOVERWRITE;
273                 }
274                 if ((pw_db->close)(pw_db))
275                         error("close pw_db");
276                 method = 0;
277         } else {
278                 dp = dbopen(buf,
279                     O_RDWR|O_CREAT|O_EXCL, PERM_INSECURE, DB_HASH, &openinfo);
280                 if (dp == NULL)
281                         error(buf);
282                 clean = FILE_INSECURE;
283
284                 sdp = dbopen(sbuf,
285                     O_RDWR|O_CREAT|O_EXCL, PERM_SECURE, DB_HASH, &openinfo);
286                 if (sdp == NULL)
287                         error(sbuf);
288                 clean = FILE_SECURE;
289
290                 method = R_NOOVERWRITE;
291                 methoduid = R_NOOVERWRITE;
292         }
293
294         /*
295          * Open file for old password file.  Minor trickiness -- don't want to
296          * chance the file already existing, since someone (stupidly) might
297          * still be using this for permission checking.  So, open it first and
298          * fdopen the resulting fd.  The resulting file should be readable by
299          * everyone.
300          */
301         if (makeold) {
302                 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
303                 if ((tfd = open(buf,
304                     O_WRONLY|O_CREAT|O_EXCL, PERM_INSECURE)) < 0)
305                         error(buf);
306                 if ((oldfp = fdopen(tfd, "w")) == NULL)
307                         error(buf);
308                 clean = FILE_ORIG;
309         }
310
311         /*
312          * The databases actually contain three copies of the original data.
313          * Each password file entry is converted into a rough approximation
314          * of a ``struct passwd'', with the strings placed inline.  This
315          * object is then stored as the data for three separate keys.  The
316          * first key * is the pw_name field prepended by the _PW_KEYBYNAME
317          * character.  The second key is the pw_uid field prepended by the
318          * _PW_KEYBYUID character.  The third key is the line number in the
319          * original file prepended by the _PW_KEYBYNUM character.  (The special
320          * characters are prepended to ensure that the keys do not collide.)
321          */
322         /* In order to transition this file into a machine-independent
323          * form, we have to change the format of entries.  However, since
324          * older binaries will still expect the old MD format entries, we 
325          * create those as usual and use versioned tags for the new entries.
326          */
327         if (username == NULL) {
328                 /* Do not add the VERSION tag when updating a single
329                  * user.  When operating on `old format' databases, this
330                  * would result in applications `seeing' only the updated
331                  * entries.
332                  */
333                 key.data = verskey;
334                 key.size = sizeof(verskey)-1;
335                 data.data = &version;
336                 data.size = 1;
337                 if ((dp->put)(dp, &key, &data, 0) == -1)
338                         error("put");
339                 if ((dp->put)(sdp, &key, &data, 0) == -1)
340                         error("put");
341         }
342         ypcnt = 1;
343         data.data = (u_char *)buf;
344         sdata.data = (u_char *)sbuf;
345         key.data = (u_char *)tbuf;
346         for (cnt = 1; scan(fp, &pwd); ++cnt) {
347                 if (!is_comment && 
348                     (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-'))
349                         yp_enabled = 1;
350                 if (is_comment)
351                         --cnt;
352 #define COMPACT(e)      t = e; while ((*p++ = *t++));
353 #define SCALAR(e)       store = htonl((uint32_t)(e));      \
354                         memmove(p, &store, sizeof(store)); \
355                         p += sizeof(store);
356                 if (!is_comment && 
357                     (!username || (strcmp(username, pwd.pw_name) == 0))) {
358                         pw_change = pwd.pw_change;
359                         pw_expire = pwd.pw_expire;
360                         /* Create insecure data. */
361                         p = buf;
362                         COMPACT(pwd.pw_name);
363                         COMPACT("*");
364                         SCALAR(pwd.pw_uid);
365                         SCALAR(pwd.pw_gid);
366                         SCALAR(pwd.pw_change);
367                         COMPACT(pwd.pw_class);
368                         COMPACT(pwd.pw_gecos);
369                         COMPACT(pwd.pw_dir);
370                         COMPACT(pwd.pw_shell);
371                         SCALAR(pwd.pw_expire);
372                         SCALAR(pwd.pw_fields);
373                         data.size = p - buf;
374
375                         /* Create secure data. */
376                         p = sbuf;
377                         COMPACT(pwd.pw_name);
378                         COMPACT(pwd.pw_passwd);
379                         SCALAR(pwd.pw_uid);
380                         SCALAR(pwd.pw_gid);
381                         SCALAR(pwd.pw_change);
382                         COMPACT(pwd.pw_class);
383                         COMPACT(pwd.pw_gecos);
384                         COMPACT(pwd.pw_dir);
385                         COMPACT(pwd.pw_shell);
386                         SCALAR(pwd.pw_expire);
387                         SCALAR(pwd.pw_fields);
388                         sdata.size = p - sbuf;
389
390                         /* Store insecure by name. */
391                         tbuf[0] = CURRENT_VERSION(_PW_KEYBYNAME);
392                         len = strlen(pwd.pw_name);
393                         memmove(tbuf + 1, pwd.pw_name, len);
394                         key.size = len + 1;
395                         if ((dp->put)(dp, &key, &data, method) == -1)
396                                 error("put");
397
398                         /* Store insecure by number. */
399                         tbuf[0] = CURRENT_VERSION(_PW_KEYBYNUM);
400                         store = htonl(cnt);
401                         memmove(tbuf + 1, &store, sizeof(store));
402                         key.size = sizeof(store) + 1;
403                         if ((dp->put)(dp, &key, &data, method) == -1)
404                                 error("put");
405
406                         /* Store insecure by uid. */
407                         tbuf[0] = CURRENT_VERSION(_PW_KEYBYUID);
408                         store = htonl(pwd.pw_uid);
409                         memmove(tbuf + 1, &store, sizeof(store));
410                         key.size = sizeof(store) + 1;
411                         if ((dp->put)(dp, &key, &data, methoduid) == -1)
412                                 error("put");
413
414                         /* Store secure by name. */
415                         tbuf[0] = CURRENT_VERSION(_PW_KEYBYNAME);
416                         len = strlen(pwd.pw_name);
417                         memmove(tbuf + 1, pwd.pw_name, len);
418                         key.size = len + 1;
419                         if ((sdp->put)(sdp, &key, &sdata, method) == -1)
420                                 error("put");
421
422                         /* Store secure by number. */
423                         tbuf[0] = CURRENT_VERSION(_PW_KEYBYNUM);
424                         store = htonl(cnt);
425                         memmove(tbuf + 1, &store, sizeof(store));
426                         key.size = sizeof(store) + 1;
427                         if ((sdp->put)(sdp, &key, &sdata, method) == -1)
428                                 error("put");
429
430                         /* Store secure by uid. */
431                         tbuf[0] = CURRENT_VERSION(_PW_KEYBYUID);
432                         store = htonl(pwd.pw_uid);
433                         memmove(tbuf + 1, &store, sizeof(store));
434                         key.size = sizeof(store) + 1;
435                         if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1)
436                                 error("put");
437
438                         /* Store insecure and secure special plus and special minus */
439                         if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') {
440                                 tbuf[0] = CURRENT_VERSION(_PW_KEYYPBYNUM);
441                                 store = htonl(ypcnt);
442                                 memmove(tbuf + 1, &store, sizeof(store));
443                                 ypcnt++;
444                                 key.size = sizeof(store) + 1;
445                                 if ((dp->put)(dp, &key, &data, method) == -1)
446                                         error("put");
447                                 if ((sdp->put)(sdp, &key, &sdata, method) == -1)
448                                         error("put");
449                         }
450
451                         /* Create insecure data. (legacy version) */
452                         p = buf;
453                         COMPACT(pwd.pw_name);
454                         COMPACT("*");
455                         memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid));
456                         p += sizeof(int);
457                         memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid));
458                         p += sizeof(int);
459                         memmove(p, &pw_change, sizeof(pw_change));
460                         p += sizeof(pw_change);
461                         COMPACT(pwd.pw_class);
462                         COMPACT(pwd.pw_gecos);
463                         COMPACT(pwd.pw_dir);
464                         COMPACT(pwd.pw_shell);
465                         memmove(p, &pw_expire, sizeof(pw_expire));
466                         p += sizeof(pw_expire);
467                         memmove(p, &pwd.pw_fields, sizeof pwd.pw_fields);
468                         p += sizeof pwd.pw_fields;
469                         data.size = p - buf;
470
471                         /* Create secure data. (legacy version) */
472                         p = sbuf;
473                         COMPACT(pwd.pw_name);
474                         COMPACT(pwd.pw_passwd);
475                         memmove(p, &pwd.pw_uid, sizeof(pwd.pw_uid));
476                         p += sizeof(int);
477                         memmove(p, &pwd.pw_gid, sizeof(pwd.pw_gid));
478                         p += sizeof(int);
479                         memmove(p, &pw_change, sizeof(pw_change));
480                         p += sizeof(pw_change);
481                         COMPACT(pwd.pw_class);
482                         COMPACT(pwd.pw_gecos);
483                         COMPACT(pwd.pw_dir);
484                         COMPACT(pwd.pw_shell);
485                         memmove(p, &pw_expire, sizeof(pw_expire));
486                         p += sizeof(pw_expire);
487                         memmove(p, &pwd.pw_fields, sizeof pwd.pw_fields);
488                         p += sizeof pwd.pw_fields;
489                         sdata.size = p - sbuf;
490
491                         /* Store insecure by name. */
492                         tbuf[0] = LEGACY_VERSION(_PW_KEYBYNAME);
493                         len = strlen(pwd.pw_name);
494                         memmove(tbuf + 1, pwd.pw_name, len);
495                         key.size = len + 1;
496                         if ((dp->put)(dp, &key, &data, method) == -1)
497                                 error("put");
498
499                         /* Store insecure by number. */
500                         tbuf[0] = LEGACY_VERSION(_PW_KEYBYNUM);
501                         memmove(tbuf + 1, &cnt, sizeof(cnt));
502                         key.size = sizeof(cnt) + 1;
503                         if ((dp->put)(dp, &key, &data, method) == -1)
504                                 error("put");
505
506                         /* Store insecure by uid. */
507                         tbuf[0] = LEGACY_VERSION(_PW_KEYBYUID);
508                         memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
509                         key.size = sizeof(pwd.pw_uid) + 1;
510                         if ((dp->put)(dp, &key, &data, methoduid) == -1)
511                                 error("put");
512
513                         /* Store secure by name. */
514                         tbuf[0] = LEGACY_VERSION(_PW_KEYBYNAME);
515                         len = strlen(pwd.pw_name);
516                         memmove(tbuf + 1, pwd.pw_name, len);
517                         key.size = len + 1;
518                         if ((sdp->put)(sdp, &key, &sdata, method) == -1)
519                                 error("put");
520
521                         /* Store secure by number. */
522                         tbuf[0] = LEGACY_VERSION(_PW_KEYBYNUM);
523                         memmove(tbuf + 1, &cnt, sizeof(cnt));
524                         key.size = sizeof(cnt) + 1;
525                         if ((sdp->put)(sdp, &key, &sdata, method) == -1)
526                                 error("put");
527
528                         /* Store secure by uid. */
529                         tbuf[0] = LEGACY_VERSION(_PW_KEYBYUID);
530                         memmove(tbuf + 1, &pwd.pw_uid, sizeof(pwd.pw_uid));
531                         key.size = sizeof(pwd.pw_uid) + 1;
532                         if ((sdp->put)(sdp, &key, &sdata, methoduid) == -1)
533                                 error("put");
534
535                         /* Store insecure and secure special plus and special minus */
536                         if (pwd.pw_name[0] == '+' || pwd.pw_name[0] == '-') {
537                                 tbuf[0] = LEGACY_VERSION(_PW_KEYYPBYNUM);
538                                 memmove(tbuf + 1, &ypcnt, sizeof(cnt));
539                                 ypcnt++;
540                                 key.size = sizeof(cnt) + 1;
541                                 if ((dp->put)(dp, &key, &data, method) == -1)
542                                         error("put");
543                                 if ((sdp->put)(sdp, &key, &sdata, method) == -1)
544                                         error("put");
545                         }
546                 }
547                 /* Create original format password file entry */
548                 if (is_comment && makeold){     /* copy comments */
549                         if (fprintf(oldfp, "%s\n", line) < 0)
550                                 error("write old");
551                 } else if (makeold) {
552                         char uidstr[20];
553                         char gidstr[20];
554
555                         snprintf(uidstr, sizeof(uidstr), "%u", pwd.pw_uid);
556                         snprintf(gidstr, sizeof(gidstr), "%u", pwd.pw_gid);
557
558                         if (fprintf(oldfp, "%s:*:%s:%s:%s:%s:%s\n",
559                             pwd.pw_name, pwd.pw_fields & _PWF_UID ? uidstr : "",
560                             pwd.pw_fields & _PWF_GID ? gidstr : "",
561                             pwd.pw_gecos, pwd.pw_dir, pwd.pw_shell) < 0)
562                                 error("write old");
563                 }
564         }
565         /* If YP enabled, set flag. */
566         if (yp_enabled) {
567                 buf[0] = yp_enabled + 2;
568                 data.size = 1;
569                 key.size = 1;
570                 tbuf[0] = CURRENT_VERSION(_PW_KEYYPENABLED);
571                 if ((dp->put)(dp, &key, &data, method) == -1)
572                         error("put");
573                 if ((sdp->put)(sdp, &key, &data, method) == -1)
574                         error("put");
575                 tbuf[0] = LEGACY_VERSION(_PW_KEYYPENABLED);
576                 key.size = 1;
577                 if ((dp->put)(dp, &key, &data, method) == -1)
578                         error("put");
579                 if ((sdp->put)(sdp, &key, &data, method) == -1)
580                         error("put");
581         }
582
583         if ((dp->close)(dp) == -1)
584                 error("close");
585         if ((sdp->close)(sdp) == -1)
586                 error("close");
587         if (makeold) {
588                 (void)fflush(oldfp);
589                 if (fclose(oldfp) == EOF)
590                         error("close old");
591         }
592
593         /* Set master.passwd permissions, in case caller forgot. */
594         (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR);
595
596         /* Install as the real password files. */
597         (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB);
598         (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _MP_DB);
599         mv(buf, buf2);
600         (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB);
601         (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _SMP_DB);
602         mv(buf, buf2);
603         if (makeold) {
604                 (void)snprintf(buf2, sizeof(buf2), "%s/%s", prefix, _PASSWD);
605                 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
606                 mv(buf, buf2);
607         }
608         /*
609          * Move the master password LAST -- chpass(1), passwd(1) and vipw(8)
610          * all use flock(2) on it to block other incarnations of themselves.
611          * The rename means that everything is unlocked, as the original file
612          * can no longer be accessed.
613          */
614         (void)snprintf(buf, sizeof(buf), "%s/%s", prefix, _MASTERPASSWD);
615         mv(pname, buf);
616
617         /*
618          * Close locked password file after rename()
619          */
620         if (fclose(fp) == EOF)
621                 error("close fp");
622
623         exit(0);
624 }
625
626 int
627 scan(fp, pw)
628         FILE *fp;
629         struct passwd *pw;
630 {
631         static int lcnt;
632         char *p;
633
634         if (!fgets(line, sizeof(line), fp))
635                 return (0);
636         ++lcnt;
637         /*
638          * ``... if I swallow anything evil, put your fingers down my
639          * throat...''
640          *      -- The Who
641          */
642         if (!(p = strchr(line, '\n'))) {
643                 /*
644                  * XXX: This may also happen if the last line in a
645                  * file does not have a trailing newline.
646                  */
647                 warnx("line #%d too long", lcnt);
648                 goto fmt;
649
650         }
651         *p = '\0';
652
653         /* 
654          * Ignore comments: ^[ \t]*#
655          */
656         for (p = line; *p != '\0'; p++)
657                 if (*p != ' ' && *p != '\t')
658                         break;
659         if (*p == '#' || *p == '\0') {
660                 is_comment = 1;
661                 return(1);
662         } else
663                 is_comment = 0;
664
665         if (!__pw_scan(line, pw, _PWSCAN_WARN|_PWSCAN_MASTER)) {
666                 warnx("at line #%d", lcnt);
667 fmt:            errno = EFTYPE; /* XXX */
668                 error(pname);
669         }
670
671         return (1);
672 }
673
674 void                    
675 cp(from, to, mode)              
676         char *from, *to;
677         mode_t mode;    
678 {               
679         static char buf[MAXBSIZE];
680         int from_fd, rcount, to_fd, wcount;
681
682         if ((from_fd = open(from, O_RDONLY, 0)) < 0)
683                 error(from);
684         if ((to_fd = open(to, O_WRONLY|O_CREAT|O_EXCL, mode)) < 0)
685                 error(to);
686         while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
687                 wcount = write(to_fd, buf, rcount);
688                 if (rcount != wcount || wcount == -1) {
689                         int sverrno = errno;
690
691                         (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
692                         errno = sverrno;
693                         error(buf);
694                 }
695         }
696         if (rcount < 0) {
697                 int sverrno = errno;
698
699                 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
700                 errno = sverrno;
701                 error(buf);
702         }
703 }
704
705
706 void
707 mv(from, to)
708         char *from, *to;
709 {
710         char buf[MAXPATHLEN];
711
712         if (rename(from, to)) {
713                 int sverrno = errno;
714                 (void)snprintf(buf, sizeof(buf), "%s to %s", from, to);
715                 errno = sverrno;
716                 error(buf);
717         }
718 }
719
720 void
721 error(name)
722         const char *name;
723 {
724
725         warn("%s", name);
726         cleanup();
727         exit(1);
728 }
729
730 void
731 cleanup()
732 {
733         char buf[MAXPATHLEN];
734
735         switch(clean) {
736         case FILE_ORIG:
737                 (void)snprintf(buf, sizeof(buf), "%s.orig", pname);
738                 (void)unlink(buf);
739                 /* FALLTHROUGH */
740         case FILE_SECURE:
741                 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _SMP_DB);
742                 (void)unlink(buf);
743                 /* FALLTHROUGH */
744         case FILE_INSECURE:
745                 (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB);
746                 (void)unlink(buf);
747         }
748 }
749
750 static void
751 usage()
752 {
753
754         (void)fprintf(stderr,
755 "usage: pwd_mkdb [-C] [-N] [-i] [-p] [-d <dest dir>] [-s <cachesize>] [-u <local username>] file\n");
756         exit(1);
757 }