vsftpd 530 Login incorrect 但密码正确的 PAM / shell 配置坑

7次阅读

530 Login incorrect 的根本原因通常是 PAM 或 shell 限制:/etc/shells 缺失用户 shell、pam_shells.so 配置错误或用户 shell 为 /sbin/nologin 且未配 allow_writeable_chroot。

vsftpd 530 Login incorrect 但密码正确的 PAM / shell 配置坑

vsftpd 报 530 Login incorrect 但密码确实正确

这是 vsftpd 最典型的“假失败”:用户能正常 ssh 登录,passwd 验证无误,但 FTP 就是拒绝。根本原因几乎都出在 PAM 或 shell 限制上,而非密码本身。

/etc/shells 文件里没加 ftp 用户的 shell

vsftpd 默认启用 check_shell=YES(尤其在 RHEL/centos 系统),它会严格检查用户 shell 是否列在 /etc/shells 中。哪怕你用 /bin/bash,如果该路径没被显式写入 /etc/shells,登录就直接被 PAM 拒绝,日志里只显示模糊的 530

实操建议:

  • 运行 cat /etc/shells 确认目标 shell(如 /bin/bash/bin/sh)是否在列表中
  • 若缺失,用 echo "/bin/bash" >> /etc/shells 追加(注意权限,需 root)
  • 改完不用重启 vsftpd,PAM 会实时读取
  • 临时验证可先设 check_shell=NO 测试,但不推荐长期关闭

PAM 配置误启了 pam_shells.so 或顺序错乱

很多系统默认的 /etc/pam.d/vsftpd 包含 auth [success=ignore default=bad] pam_shells.so 这类规则——它和 /etc/shells 联动,但失败时不输出具体原因,只让 vsftpd 返回 530

常见错误场景:

  • 手动修改过 PAM 文件,把 pam_shells.so 放到了 pam_unix.so 前面,导致还没校验密码就因 shell 检查失败而终止
  • 使用了第三方 vsftpd 包(如某些 docker 镜像),PAM 配置自带冗余限制
  • /etc/pam.d/vsftpd 不存在,系统 fallback 到 /etc/pam.d/ftp 或通用配置,行为不可控

建议动作:

  • 确认 /etc/pam.d/vsftpd 存在且内容简洁,核心 auth 行应类似:
    auth [default=ignore] pam_succeed_if.so user != root
    auth required pam_unix.so
  • 注释掉所有带 pam_shells.so 的行,或确保它出现在 pam_unix.so 之后(仅用于 post-auth 检查)
  • 开启 vsftpd 调试:在 /etc/vsftpd.conflog_ftp_protocol=YES + xferlog_enable=YES,再看 /var/log/vsftpd.log

用户 shell 被设为 /sbin/nologin/bin/false 但未配 allow_writeable_chroot

为安全把 ftp 用户 shell 设成 /sbin/nologin 是常见做法,但这会让 vsftpd 在 chroot 前就拒绝登录(尤其启用 chroot_local_user=YES 时)。错误不是发生在认证阶段,而是 session 初始化环节。

关键点:

  • /sbin/nologin/bin/false 不在 /etc/shells 中 —— 即使你加了,vsftpd 也可能因内部逻辑跳过
  • 若坚持用非登录 shell,必须同时满足:
    chroot_local_user=YES
    allow_writeable_chroot=YES(注意:这有安全风险,仅限私有环境)
    • 用户主目录不能有写权限(vsftpd 会检查 ls -ld /home/ftpuser
  • 更稳妥的做法是用 /bin/bash + sudo usermod -s /bin/bash username,再通过 chmod 755 /home/username 控制目录权限

真正卡住人的地方往往不是密码输错,而是 PAM 没报错、vsftpd 不打详细日志、shell 列表和配置文件又分散在不同位置——三者稍一错位,530 就成了黑盒。动手前先确认 getent passwd usernamegetent shells 输出,比反复重置密码有用得多。

text=ZqhQzanResources