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