+
+char *
+changedir(char *path, char *dir)
+{
+ static char fixed[MAXPATHLEN];
+ char *p;
+
+ if (!dir)
+ return (path);
+
+ if ((p = strrchr(path, '/')) != NULL)
+ path = p + 1;
+ snprintf(fixed, sizeof(fixed), "%s/%s", dir, path);
+ return (fixed);
+}
+
+void
+db_store(FILE *fp, FILE *oldfp, DB *edp, DB *dp, struct passwd *pw,
+ int keytype, char *username, uid_t olduid)
+{
+ int flags = 0;
+ int dbmode, found = 0;
+ u_int cnt;
+ char *p, *t, buf[LINE_MAX * 2], tbuf[1024];
+ DBT data, key;
+ size_t len;
+ static int firsttime = 1;
+
+ /* If given a username just add that record to the existing db. */
+ dbmode = username ? 0 : R_NOOVERWRITE;
+
+ rewind(fp);
+ data.data = (u_char *)buf;
+ key.data = (u_char *)tbuf;
+ for (cnt = 1; scan(fp, pw, &flags); ++cnt) {
+
+#ifdef __APPLE__
+ if (pw->pw_name == NULL)
+ continue;
+#endif
+
+ if (firsttime) {
+ /* Look like YP? */
+ if ((pw->pw_name[0] == '+') || (pw->pw_name[0] == '-'))
+ hasyp++;
+
+ /* Warn about potentially unsafe uid/gid overrides. */
+ if (pw->pw_name[0] == '+') {
+ if (!(flags & _PASSWORD_NOUID) && !pw->pw_uid)
+ warnx("line %d: superuser override in "
+ "YP inclusion", cnt);
+ if (!(flags & _PASSWORD_NOGID) && !pw->pw_gid)
+ warnx("line %d: wheel override in "
+ "YP inclusion", cnt);
+ }
+
+ /* Create V7 format password file entry. */
+ if (oldfp != NULL)
+ if (fprintf(oldfp, "%s:*:%u:%u:%s:%s:%s\n",
+ pw->pw_name, pw->pw_uid, pw->pw_gid,
+ pw->pw_gecos, pw->pw_dir, pw->pw_shell)
+ == EOF)
+ error("write old");
+ }
+
+ /* Are we updating a specific record? */
+ if (username) {
+ if (strcmp(username, pw->pw_name) != 0)
+ continue;
+ found = 1;
+ /* If the uid changed, remove the old record by uid. */
+ if (olduid != UID_MAX && olduid != pw->pw_uid) {
+ tbuf[0] = _PW_KEYBYUID;
+ memcpy(tbuf + 1, &olduid, sizeof(olduid));
+ key.size = sizeof(olduid) + 1;
+ (edp->del)(edp, &key, 0);
+ if (dp)
+ (dp->del)(dp, &key, 0);
+ }
+ /* XXX - should check to see if line number changed. */
+ }
+
+ /* Build the key. */
+ tbuf[0] = keytype;
+ switch (keytype) {
+ case _PW_KEYBYNUM:
+ memmove(tbuf + 1, &cnt, sizeof(cnt));
+ key.size = sizeof(cnt) + 1;
+ break;
+
+ case _PW_KEYBYNAME:
+ len = strlen(pw->pw_name);
+ memmove(tbuf + 1, pw->pw_name, len);
+ key.size = len + 1;
+ break;
+
+ case _PW_KEYBYUID:
+ memmove(tbuf + 1, &pw->pw_uid, sizeof(pw->pw_uid));
+ key.size = sizeof(pw->pw_uid) + 1;
+ break;
+ }
+
+#define COMPACT(e) t = e; while ((*p++ = *t++));
+ /* Create the secure record. */
+ p = buf;
+ COMPACT(pw->pw_name);
+ COMPACT(pw->pw_passwd);
+ memmove(p, &pw->pw_uid, sizeof(uid_t));
+ p += sizeof(uid_t);
+ memmove(p, &pw->pw_gid, sizeof(gid_t));
+ p += sizeof(gid_t);
+ memmove(p, &pw->pw_change, sizeof(time_t));
+ p += sizeof(time_t);
+ COMPACT(pw->pw_class);
+ COMPACT(pw->pw_gecos);
+ COMPACT(pw->pw_dir);
+ COMPACT(pw->pw_shell);
+ memmove(p, &pw->pw_expire, sizeof(time_t));
+ p += sizeof(time_t);
+ memmove(p, &flags, sizeof(int));
+ p += sizeof(int);
+ data.size = p - buf;
+
+ /* Write the secure record. */
+ if ((edp->put)(edp, &key, &data, dbmode) == -1)
+ error("put");
+
+ if (dp == NULL)
+ continue;
+
+ /* Star out password to make insecure record. */
+ p = buf + strlen(pw->pw_name) + 1; /* skip pw_name */
+ len = strlen(pw->pw_passwd);
+ memset(p, 0, len); /* zero pw_passwd */
+ t = p + len + 1; /* skip pw_passwd */
+ if (len != 0)
+ *p++ = '*';
+ *p++ = '\0';
+ memmove(p, t, data.size - (t - buf));
+ data.size -= len - 1;
+
+ /* Write the insecure record. */
+ if ((dp->put)(dp, &key, &data, dbmode) == -1)
+ error("put");
+ }
+ if (firsttime) {
+ firsttime = 0;
+ if (username && !found && olduid != UID_MAX)
+ errorx("can't find user in master.passwd");
+ }
+}