Linux pwck命令

pwck 命令用于验证系统用户认证文件(/etc/passwd/etc/shadow)的完整性。它会检查文件格式、字段数量、用户和组的存在性以及一致性。

命令简介

pwck 是 "password check" 的缩写,用于检查用户认证文件的完整性。它主要验证以下内容:

  • /etc/passwd 文件的格式和字段数量
  • /etc/shadow 文件的格式和字段数量
  • 用户和组的存在性
  • 用户主目录是否存在
  • 用户登录 shell 是否有效
  • 两个文件之间的一致性
注意: pwck 命令通常需要 root 权限才能完全访问 /etc/shadow 文件。普通用户运行可能只能检查 /etc/passwd 文件。

命令语法

pwck [选项] [passwd [shadow]]
pwck [选项] [文件]

参数说明:

  • passwd:指定 passwd 文件路径(默认为 /etc/passwd
  • shadow:指定 shadow 文件路径(默认为 /etc/shadow

常用选项

选项 说明
-r, --read-only 只读模式,不修改文件
-s, --sort 按 UID 排序 passwd 和 shadow 文件
--root 目录 在指定根目录下操作(chroot)
-q, --quiet 安静模式,只显示错误信息
-h, --help 显示帮助信息
-V, --version 显示版本信息

用户认证文件格式

1. /etc/passwd 文件格式

每行包含7个字段,用冒号分隔:

用户名:密码占位符:UID:GID:用户信息:家目录:登录shell
字段 说明 示例
用户名 用户登录名 root, alice, bob
密码占位符 x 表示密码在 /etc/shadow 中 x
UID 用户 ID (0=root, 1-999=系统用户, 1000+=普通用户) 0, 1000, 1001
GID 主组 ID 0, 1000, 1001
用户信息 注释或全名(GECOS 字段) Alice Smith,,,
家目录 用户主目录路径 /root, /home/alice
登录 shell 用户默认 shell /bin/bash, /usr/sbin/nologin

2. /etc/shadow 文件格式

每行包含9个字段,用冒号分隔:

用户名:加密密码:最后修改:最小天数:最大天数:警告天数:不活动天数:失效日期:保留字段
字段 说明 示例
用户名 用户登录名(与 passwd 一致) root, alice
加密密码 加密后的密码,! 或 * 表示锁定,空表示无密码 $6$salt$hash, !, *
最后修改 1970-01-01 起的天数 19182
最小天数 密码修改后最少使用天数 0
最大天数 密码最多使用天数(到期需修改) 99999
警告天数 密码到期前多少天开始警告 7
不活动天数 密码到期后账户还能使用的天数
失效日期 账户失效日期(1970-01-01 起的天数)
保留字段 保留

命令示例

1. 基本使用:检查系统用户文件

检查默认的 /etc/passwd/etc/shadow 文件:

# 以 root 用户运行完整检查
sudo pwck

# 以普通用户运行(只能检查 /etc/passwd)
pwck

# 指定文件检查
sudo pwck /etc/passwd /etc/shadow

# 检查备份文件
sudo pwck /etc/passwd.bak /etc/shadow.bak

输出示例:

$ sudo pwck
user 'ftp': directory '/home/ftp' does not exist
user 'news': directory '/etc/news' does not exist
user 'uucp': directory '/var/spool/uucp' does not exist
user 'gopher': directory '/var/gopher' does not exist
user 'ftp': program '/usr/sbin/nologin' does not exist
pwck: no changes

2. 只读模式检查

检查但不修改文件:

# 只读模式,不修改文件
sudo pwck -r

# 安静模式,只显示错误
sudo pwck -q

# 只读且安静模式
sudo pwck -rq

3. 排序用户文件

按 UID 排序用户文件:

# 按 UID 排序 passwd 和 shadow 文件
sudo pwck -s

# 排序并检查
sudo pwck -s /etc/passwd /etc/shadow

# 检查排序后的结果
head -10 /etc/passwd

4. 检查特定问题

检查常见的用户认证问题:

# 检查无效的登录 shell
sudo pwck | grep "does not exist"

# 检查不存在的家目录
sudo pwck | grep "directory.*does not exist"

# 检查 UID 重复
sudo cut -d: -f3 /etc/passwd | sort -n | uniq -d

# 检查 GID 是否有效
sudo pwck 2>&1 | grep "invalid group"

5. 在 chroot 环境中检查

检查 chroot 环境中的用户文件:

# 检查 /mnt/chroot 中的用户文件
sudo pwck --root /mnt/chroot

# 检查特定目录
sudo pwck --root /backup/system /etc/passwd /etc/shadow

常见错误和修复方法

错误1:家目录不存在
# 错误信息
user 'alice': directory '/home/alice' does not exist

# 修复方法:
# 1. 创建缺失的家目录
sudo mkdir /home/alice
sudo chown alice:alice /home/alice

# 2. 或修改用户的家目录设置
sudo usermod -d /new/home/dir alice

# 3. 如果用户不需要家目录,设置有效目录
sudo usermod -d /tmp alice
错误2:无效的登录 shell
# 错误信息
user 'ftp': program '/usr/sbin/nologin' does not exist

# 修复方法:
# 1. 安装缺失的 shell
sudo apt-get install util-linux  # 包含 nologin

# 2. 修改用户的登录 shell
sudo usermod -s /bin/bash ftp
# 或设置为有效 shell
sudo usermod -s /usr/sbin/nologin ftp

# 3. 检查有效 shell 列表
cat /etc/shells
错误3:passwd 和 shadow 不一致
# 错误信息
user 'bob': no matching shadow entry

# 修复方法:
# 1. 检查用户是否在 shadow 文件中
sudo grep '^bob:' /etc/shadow

# 2. 如果不存在,从 passwd 同步到 shadow
sudo pwck  # 交互式修复,按提示操作

# 3. 手动添加 shadow 条目
sudo vipw -s  # 编辑 shadow 文件
# 或使用 useradd 创建
sudo useradd -M -s /bin/bash bob
错误4:字段数量不正确
# 错误信息
invalid line: too few fields
invalid line: too many fields

# 修复方法:
# 1. 检查问题行
sudo awk -F: 'NF != 7 {print NR ": " $0}' /etc/passwd
sudo awk -F: 'NF != 9 {print NR ": " $0}' /etc/shadow

# 2. 手动编辑修复
sudo vipw  # 编辑 passwd 文件
sudo vipw -s  # 编辑 shadow 文件

# 3. 使用工具修复
sudo pwck  # 交互式修复

系统维护脚本

脚本1:定期用户文件完整性检查
#!/bin/bash
# userfile_integrity_check.sh - 定期检查用户文件完整性

LOG_FILE="/var/log/userfile_check.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')

echo "=== 用户文件完整性检查 - $DATE ===" | tee -a "$LOG_FILE"

# 检查 passwd 和 shadow 文件
echo "1. 运行 pwck 检查..." | tee -a "$LOG_FILE"
sudo pwck -r 2>&1 | tee -a "$LOG_FILE"

echo "2. 运行 grpck 检查组文件..." | tee -a "$LOG_FILE"
sudo grpck -r 2>&1 | tee -a "$LOG_FILE"

# 检查文件权限
echo "3. 检查文件权限..." | tee -a "$LOG_FILE"
ls -l /etc/passwd /etc/shadow /etc/group /etc/gshadow 2>&1 | tee -a "$LOG_FILE"

# 检查重复 UID/GID
echo "4. 检查重复 UID..." | tee -a "$LOG_FILE"
cut -d: -f3 /etc/passwd | sort -n | uniq -d | tee -a "$LOG_FILE"

echo "5. 检查重复 GID..." | tee -a "$LOG_FILE"
cut -d: -f3 /etc/group | sort -n | uniq -d | tee -a "$LOG_FILE"

# 检查无效 shell
echo "6. 检查无效登录 shell..." | tee -a "$LOG_FILE"
while IFS=: read -r user _ _ _ _ _ shell; do
    if [ -n "$shell" ] && [ ! -x "$shell" ] && [ "$shell" != "/usr/sbin/nologin" ]; then
        echo "警告: 用户 $user 使用无效 shell: $shell" | tee -a "$LOG_FILE"
    fi
done < /etc/passwd

echo "=== 检查完成 ===" | tee -a "$LOG_FILE"
脚本2:自动化修复常见问题
#!/bin/bash
# auto_fix_userfiles.sh - 自动修复常见用户文件问题

# 只运行修复模式
FIX_MODE=${1:-dry}  # dry 或 apply

echo "用户文件自动修复工具"
echo "模式: $FIX_MODE"

# 1. 运行 pwck 获取问题列表
PROBLEMS=$(sudo pwck -r 2>&1)

# 2. 解析并处理问题
while IFS= read -r line; do
    if [[ $line =~ "directory.*does not exist" ]]; then
        # 提取用户名和目录
        user=$(echo "$line" | grep -o "user '[^']*'" | cut -d"'" -f2)
        dir=$(echo "$line" | grep -o "directory '[^']*'" | cut -d"'" -f2)

        echo "问题: $line"

        if [ "$FIX_MODE" = "apply" ]; then
            if [ "$user" = "nobody" ] || [ "$user" = "nogroup" ]; then
                echo "跳过系统用户: $user"
            elif [ -n "$user" ] && [ -n "$dir" ]; then
                echo "修复: 为用户 $user 创建目录 $dir"
                sudo mkdir -p "$dir"
                sudo chown "$user:$user" "$dir"
            fi
        fi

    elif [[ $line =~ "program.*does not exist" ]]; then
        # 提取用户名和程序
        user=$(echo "$line" | grep -o "user '[^']*'" | cut -d"'" -f2)
        program=$(echo "$line" | grep -o "program '[^']*'" | cut -d"'" -f2)

        echo "问题: $line"

        if [ "$FIX_MODE" = "apply" ]; then
            if [ -n "$user" ] && [ -n "$program" ]; then
                # 检查是否有可用的替代 shell
                if [ -x "/bin/bash" ]; then
                    echo "修复: 设置用户 $user 的 shell 为 /bin/bash"
                    sudo usermod -s /bin/bash "$user"
                elif [ -x "/bin/sh" ]; then
                    echo "修复: 设置用户 $user 的 shell 为 /bin/sh"
                    sudo usermod -s /bin/sh "$user"
                fi
            fi
        fi
    fi
done <<< "$PROBLEMS"

if [ "$FIX_MODE" = "dry" ]; then
    echo ""
    echo "这是干运行模式,要实际应用修复,请运行:"
    echo "sudo $0 apply"
fi

最佳实践

用户认证文件管理最佳实践
  • 定期检查: 每月至少运行一次 pwckgrpck
  • 备份文件: 修改用户文件前备份 /etc/passwd/etc/shadow/etc/group/etc/gshadow
  • 使用工具: 使用 useraddusermoduserdel 等工具修改,避免直接编辑文件
  • 监控日志: 设置日志监控,检测异常的用户文件修改
  • 权限控制: 确保用户文件有正确的权限(passwd: 644, shadow: 600 或 400)
  • 一致性检查: 在系统更新或用户管理操作后运行完整性检查

常见问题

命令 检查的文件 主要功能
pwck /etc/passwd, /etc/shadow 检查用户账户完整性,验证用户字段、家目录、shell等
grpck /etc/group, /etc/gshadow 检查组账户完整性,验证组字段、组成员等

两者都是系统完整性检查工具,建议同时运行以确保用户和组信息的一致性。

可以通过 cron 定期自动运行 pwck 检查:

# 1. 创建检查脚本
sudo nano /usr/local/bin/check_userfiles.sh

# 脚本内容:
#!/bin/bash
LOG="/var/log/pwck_$(date +%Y%m%d).log"
echo "=== pwck 检查 $(date) ===" > "$LOG"
sudo pwck -r >> "$LOG" 2>&1
echo "=== grpck 检查 $(date) ===" >> "$LOG"
sudo grpck -r >> "$LOG" 2>&1

# 2. 设置可执行权限
sudo chmod +x /usr/local/bin/check_userfiles.sh

# 3. 添加到 crontab
sudo crontab -e
# 添加以下行(每月1号凌晨2点运行)
0 2 1 * * /usr/local/bin/check_userfiles.sh

# 4. 检查日志
ls -la /var/log/pwck_*.log

pwck 检查失败的常见处理步骤:

  1. 备份文件:
    sudo cp /etc/passwd /etc/passwd.backup
    sudo cp /etc/shadow /etc/shadow.backup
  2. 分析错误: 仔细阅读 pwck 的错误信息,确定问题类型
  3. 手动修复: 根据错误类型使用适当命令修复
    # 修复家目录
    sudo mkdir /home/username
    sudo chown username:username /home/username
    
    # 修复无效 shell
    sudo usermod -s /bin/bash username
    
    # 修复缺失的 shadow 条目
    sudo useradd -M -s /bin/bash username  # 重新创建用户
    # 或手动编辑
    sudo vipw -s
  4. 验证修复: 再次运行 pwck 确保问题解决
  5. 记录变更: 记录修复内容和时间,便于审计

注意: 如果不确定如何修复,可以先在测试环境中尝试,或咨询系统管理员。

相关命令

  • grpck - 检查组文件完整性
  • vipw - 安全编辑 passwd 文件
  • vigr - 安全编辑 group 文件
  • usermod - 修改用户账户
  • useradd - 添加新用户
  • chage - 更改用户密码过期信息