尝试通过 pam-mysql 更改密码时出现令牌错误

尝试通过 pam-mysql 更改密码时出现令牌错误

我目前正在为网络托管服务准备一台机器,我决定使用 MySQL 来存储我们所有的用户(因为我们的其他服务已经在使用它了)。为此,我使用libnss-mysqlpam-mysql。但是,尽管大多数设置都能正常运行,但在尝试使用 更改用户密码时,我遇到了一个问题passwd

目前,可以创建一个用户 ( INSERT INTO) 并使用 以该用户身份登录su。计算机不会提示输入密码,并直接授予对用户 shell 的访问权限。但是,一旦我以该用户身份登录,passwd就会出现以下结果:

$ passwd myuser
passwd: Authentication token manipulation error
passwd: password unchanged

根据 MySQL 日志,passwd调用时会进行查询,因此与 MySQL 的连接没有问题。此外,当我尝试使用passwd不存在的用户进行调用时,我得到了相应的passwd: user 'doesnotexist' does not existpasswd确实找到了一个用户,但无法修改其信息。auth.log日志文件显示:

pam_unix(passwd:chauthtok): user "myuser" does not exist in /etc/passwd
pam_mysql - option verbose is set to "1"
pam_mysql - pam_sm_chauthtok() called.
pam_mysql - pam_mysql_open_db() called.
pam_mysql - pam_mysql_open_db() returning 0.
pam_mysql - pam_sm_chauthtok() returning 0.
pam_mysql - pam_mysql_release_ctx() called.
pam_mysql - pam_mysql_destroy_ctx() called.
pam_mysql - pam_mysql_close_db() called.

当调用passwd -Sa以获取所有帐户的状态时,帐户确实myuser会出现。此外,getent passwdgetent shadow都返回有效的条目myuser

$ passwd -Sa
...
messagebus L 06/28/2014 0 99999 7 -1
mysql L 06/28/2014 0 99999 7 -1
myuser P 01/01/1970 0 99999 7 -1

$ getent passwd myuser
myuser:x:5001:5000:First Last:/home/members/myuser:/bin/bash

$ getent shadow myuser
myuser:$6$...:0:0:99999:7:::0

然而,在请求有关老化的信息时myuser

$ chage -l myuser
chage: user 'myuser' does not exist in /etc/passwd

总而言之 :

  • su确实找到用户,并在所有情况下执行无密码登录(如果我是 root,否则系统会提示我输入密码,并获取令牌错误)。
  • chage找不到用户;它似乎是在搜索/etc/passwd而不是数据库。
  • passwd确实找到了用户,但是在尝试编辑它时返回了令牌错误。

以下是一些配置示例:

/etc/pam.d/通用帐户

account sufficient          pam_unix.so 
account required            pam_mysql.so config_file=/etc/pam-mysql.conf

/etc/pam.d/common-auth

auth    sufficient          pam_unix.so nullok_secure
auth    required            pam_mysql.so config_file=/etc/pam-mysql.conf

/etc/pam.d/common-session

session sufficient          pam_unix.so 
session required            pwam_mysql.so config_file=/etc/pam-mysql.conf

通用密码

password    sufficient      pam_unix.so obscure sha512
password    required        pam_mysql.so config_file=/etc/pam-mysql.conf

/etc/libnss-mysql.cfg

getpwnam    SELECT username,'x',(5000+id),5000,CONCAT(firstname, lastname),CONCAT('/home/members/', username),'/bin/bash' \
            FROM users \
            WHERE username='%1$s' \
            LIMIT 1
getpwuid    SELECT username,'x',(5000+id),5000,CONCAT(firstname, lastname),CONCAT('/home/members/', username),'/bin/bash' \
            FROM users \
            WHERE (5000+id)='%1$u' \
            LIMIT 1
getspnam    SELECT username,password,0,'0','99999','7','-1','-1','0' \
            FROM users \
            WHERE username='%1$s' \
            LIMIT 1
getpwent    SELECT username,'x',(5000+id),5000,CONCAT(firstname, lastname),CONCAT('/home/members/', username),'/bin/bash' \
            FROM users
getspent    SELECT username,password,0,'0','99999','7','-1','-1','0' \
            FROM users
getgrnam    SELECT '%1$s','members',5000
getgrgid    SELECT name,password,'%1$u'
getgrent    SELECT 'members','members',5000
memsbygid   SELECT username \
            FROM users
gidsbymem   SELECT 5000
  • 我的用户 ID 在数据库中从 1 开始,但对于系统来说必须从 5000 开始(5000+id)。
  • /bin/bash为了所有人。
  • $HOME的目录myuser/home/members/myuser
  • 每个人都属于该members组,其GID为5000。

/etc/pam-mysql.conf

users.host             = localhost
users.database         = mydatabase
users.db_user          = root
users.db_passwd        = root_password
users.table            = users
users.user_column      = username
users.password_column  = password
users.password_crypt   = 1

/etc/nsswitch.conf

passwd:         compat mysql
group:          compat
shadow:         compat mysql

我尝试过:

  • $6$...在数据库中为设置密码(SHA512 哈希, ) myuser
  • 首先删除密码(passwd -d):告诉我myuser无法在中找到/etc/passwd。如果我尝试锁定帐户或强制其密码过期,也会发生同样的情况。
  • passwd从根帐户调用,没有变化。
  • 从机器上的终端登录(而不是su):我收到身份验证令牌操作错误,并返回到登录提示。当我尝试使用 SSH 连接时也是如此(加上合乎逻辑的密码过期警告)。

对我来说,这似乎是用户管理部分(帐户/会话?)已正确链接到 MySQL,但密码管理部分似乎部分依赖于/etc/passwd。我在配置中遗漏了什么吗?

答案1

好的,我找到了解决方案。首先:我强烈建议任何想了解这个的人都去学习PAM 模块基础知识。 这真的有助于理解整个事情。现在,让我们看看我的common-*文件。它们都具有相同的结构:

facility    required    pam_unix.so [...]
facility    sufficient  pam_mysql.so [...]

现在,在阅读了有关 PAM 模块的更多信息后,我觉得这很荒谬。以下是有关 PAM 控制标志的一些文档:

必需的:如果模块成功,则执行链的其余部分,除非其他模块失败,否则请求将被批准。如果模块失败,则还会执行链的其余部分,但最终请求将被拒绝。

充足的:如果模块成功,且链中之前的模块均未失败,则链将立即终止并准许请求。如果模块失败,则将忽略该模块并执行链的其余部分。

基本上,我的配置使 PAM 的行为如下:UNIX 身份验证通过,/etc/passwd并且/etc/shadow必须在所有情况下都成功。还将执行 MySQL 查找,但如果 UNIX 身份验证失败,则不会考虑其结果。

使用此设置,MySQL 身份验证机制在所有情况下都无效。正确的配置如下:

facility    sufficient  pam_mysql.so [...]
facility    required    pam_unix.so [...]

其中告诉我们:MySQL 身份验证机制已足够。如果成功,则无需测试其他机制。但如果失败,则 UNIX 身份验证必须成功。因为我的 MySQL 用户比 UNIX 用户多,所以首先针对 MySQL 进行身份验证更为合乎逻辑。

还要注意 PAM 和 NSS 角色之间的差异。在我的设置中,验证由于 NSS 配置正确,因此功能正常。NSS 处理基本的 UNIX 身份验证,但不是帐户/会话管理,以及服务特定的(SSH/FTP/...)连接。所有这些都由 PAM 处理。这种分离是能够以rootMySQL 用户身份连接的原因:NSS 确实找到了条目,并且由于root不需要针对任何内容进行身份验证即可获取用户身份,因此从未调用过 PAM 模块。

相关内容