将spwd.db转换为master.passwd,指定路径

将spwd.db转换为master.passwd,指定路径

我需要根据 spwd.db 和 pwd.db 生成 master.passwd,就像使用 一样pwd_mkdb -p。但是,我需要指定输入和输出路径。

因此,给定somesuch/spwd.dbsomesuch/pwd.db,我想要生成somesuch/master.passwd

我天真地尝试了一些类似的事情,但pwd_mkdb -p -d somesuch/ somesuch/spwd.db没有成功(“文件类型或格式不合适”)。

答案1

您无法使用 pwd_mkdb 生成master.passwdspwd.db-p选项仅生成一个/etc/passwd文件,该文件不是包含密码哈希值!

正确的做法是从备份中恢复master.passwd。如果你没有备份,这是一个很好的例子,说明为什么你应该备份所有配置数据!

检查/var/backups的备份副本master.passwd

如果找不到备份,则必须master.passwd从 的内容中重建spwd.db。文件/etc/pwd.db/etc/spwd.db是 Berkeley 数据库文件:

file /etc/pwd.db
/etc/pwd.db: Berkeley DB 1.85 (Hash, version 2, native byte-order)

如果您想读取这些数据库,您可以使用db4_dump185来自的程序/usr/ports/databases/db4

以这种方式读取文件时,请注意源代码中的以下信息/usr/src/usr.sbin/pwd_mkdb/pwd_mkdb.c

    /*
     * The databases actually contain three copies of the original data.
     * Each password file entry is converted into a rough approximation
     * of a ``struct passwd'', with the strings placed inline.  This
     * object is then stored as the data for three separate keys.  The
     * first key * is the pw_name field prepended by the _PW_KEYBYNAME
     * character.  The second key is the pw_uid field prepended by the
     * _PW_KEYBYUID character.  The third key is the line number in the
     * original file prepended by the _PW_KEYBYNUM character.  (The special
     * characters are prepended to ensure that the keys do not collide.)
     */

阅读上述源代码,了解行如何存储在散列数据库中:

#define COMPACT(e)      t = e; while ((*p++ = *t++));
#define SCALAR(e)       store = htonl((uint32_t)(e));      \
                        memmove(p, &store, sizeof(store)); \
                        p += sizeof(store);
#define LSCALAR(e)      store = HTOL((uint32_t)(e));       \
                        memmove(p, &store, sizeof(store)); \
                        p += sizeof(store);
#define HTOL(e)         (openinfo.lorder == BYTE_ORDER ? \
                        (uint32_t)(e) : \
                        bswap32((uint32_t)(e)))

                    /* Create secure data. */
                    p = sbuf;
                    COMPACT(pwd.pw_name);
                    COMPACT(pwd.pw_passwd);
                    SCALAR(pwd.pw_uid);
                    SCALAR(pwd.pw_gid);
                    SCALAR(pwd.pw_change);
                    COMPACT(pwd.pw_class);
                    COMPACT(pwd.pw_gecos);
                    COMPACT(pwd.pw_dir);
                    COMPACT(pwd.pw_shell);
                    SCALAR(pwd.pw_expire);
                    SCALAR(pwd.pw_fields);
                    sdata.size = p - sbuf;

答案2

因为我确实想审计一个系统以确认文件/etc/spwd.db是否如其/etc/master.passwd所述,所以我写了以下内容。我怀疑它并不完整,但对我的情况来说已经足够了。如果您认为缺少了某些内容 - 让分支default:发出switch一些调试信息 - 它至少会抱怨我忽略的版本条目。

祝你好运。

#include <stdio.h>
#include <sys/types.h>
#include <limits.h>
#include <db.h>
#include <fcntl.h>
#include <sys/endian.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <pwd.h>

#define _PW_VERSION_MASK    '\xF0'
#define _PW_VERSIONED(x, v) ((unsigned char)(((x) & 0xCF) | ((v)<<4)))
#define _PW_KEYBYNAME       '\x31'  /* stored by name */
#define _PW_KEYBYNUM        '\x32'  /* stored by entry in the "file" */
#define _PW_KEYBYUID        '\x33'  /* stored by uid */
#define _PW_KEYYPENABLED    '\x34'  /* YP is enabled */
#define _PW_KEYYPBYNUM      '\x35'  /* special +@netgroup entries */
#define _NPW_KEYBYNAME      '\x41'  /* stored by name */
#define _NPW_KEYBYNUM       '\x42'  /* stored by entry in the "file" */
#define _NPW_KEYBYUID       '\x43'  /* stored by uid */
#define _NPW_KEYYPENABLED   '\x44'  /* YP is enabled */
#define _NPW_KEYYPBYNUM     '\x45'  /* special +@netgroup entries */
#define _PWD_VERSION_KEY    "\xFF" "VERSION"


static HASHINFO openinfo = {
  4096,           /* bsize */
  32,             /* ffactor */
  256,            /* nelem */
  2048 * 1024,    /* cachesize */
  NULL,           /* hash() */
  BIG_ENDIAN      /* lorder */
};

void die(char *reason) {
  printf("FATAL: %s\n", reason? reason: strerror(errno));
  exit(1);
}

#define UNCOMPACT(field, name) \
  plen = strlen(p); \
  if (i + plen > len) die("data malformed"); \
  field = p; \
  i += plen + 1; \
  p += plen + 1
#define UNSCALAR(field) \
  if (i + sizeof(uint32_t) > len) die("data malformed"); \
  field = (*unscalar_func)(*(uint32_t *)p); \
  i += sizeof(uint32_t); \
  p += sizeof(uint32_t)

uint32_t uint32_t_noop(uint32_t data) {
  return data;
}

void print_pwd(uint32_t (*unscalar_func)(uint32_t), size_t len, char *data) {
  struct passwd pwd;
  size_t plen, i = 0;
  char *p;

  p = data;
  UNCOMPACT(pwd.pw_name, "pwd.pw_name");
  UNCOMPACT(pwd.pw_passwd, "pwd.pw_passwd");
  UNSCALAR(pwd.pw_uid);
  UNSCALAR(pwd.pw_gid);
  UNSCALAR(pwd.pw_change);
  UNCOMPACT(pwd.pw_class, "pwd.pw_class");
  UNCOMPACT(pwd.pw_gecos, "pwd.pw_gecos");
  UNCOMPACT(pwd.pw_dir, "pwd.pw_dir");
  UNCOMPACT(pwd.pw_shell, "pwd.pw_shell");
  UNSCALAR(pwd.pw_expire);
  UNSCALAR(pwd.pw_fields);

  printf("%s:%s:" "%d:%d:" "%s:" "%ld:%ld:" "%s:%s:%s\n",
         pwd.pw_name, pwd.pw_passwd,
         pwd.pw_uid, pwd.pw_gid,
         pwd.pw_class,
         pwd.pw_change, pwd.pw_expire,
         pwd.pw_gecos, pwd.pw_dir, pwd.pw_shell);
}

int main(int argc, char *argv[]) {
  DB *db;
  DBT key, data;
  int rc;

  db = dbopen(argv[1], O_RDONLY, 0777, DB_HASH, &openinfo);


  for (;;) {
    rc = db->seq(db, &key, &data, R_NEXT);
    if (rc == -1) die("R_NEXT");
    if (rc == 1) break;

    // Overdone - letting sort -u reduce this later.
    switch (*(char *)key.data) {
      case _PW_KEYBYNAME:
      case _PW_KEYBYNUM:
      case _PW_KEYBYUID:
        print_pwd(uint32_t_noop, data.size, (char *)data.data);
        break;   ;;
      case _NPW_KEYBYNAME:
      case _NPW_KEYBYNUM:
      case _NPW_KEYBYUID:
        print_pwd(ntohl, data.size, (char *)data.data);
        break;   ;;
      default:
        break;   ;;

    }
  }
}

相关内容