我目前正在为网络托管服务准备一台机器,我决定使用 MySQL 来存储我们所有的用户(因为我们的其他服务已经在使用它了)。为此,我使用libnss-mysql和pam-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 exist
。passwd
确实找到了一个用户,但无法修改其信息。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 passwd
和getent 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 处理。这种分离是能够以root
MySQL 用户身份连接的原因:NSS 确实找到了条目,并且由于root
不需要针对任何内容进行身份验证即可获取用户身份,因此从未调用过 PAM 模块。