[MDEV-19880] pam v1: pam password authentication doesn't work at all in MariaDB 10.4 Created: 2019-06-27  Updated: 2020-08-25  Resolved: 2019-07-02

Status: Closed
Project: MariaDB Server
Component/s: Plugin - pam
Affects Version/s: 10.4.6
Fix Version/s: 10.4.7

Type: Bug Priority: Major
Reporter: Geoff Montee (Inactive) Assignee: Sergei Golubchik
Resolution: Fixed Votes: 0
Labels: None

Issue Links:
Problem/Incident
is caused by MDEV-7032 new pam plugin with a suid wrapper Closed
is caused by MDEV-15473 Isolate/sandbox PAM modules, so that ... Closed
Relates
relates to MDEV-19881 pam plugin from MariaDB 10.3 doesn't ... Open
relates to MDEV-19876 pam v2: auth_pam_tool_dir and auth_pa... Closed
relates to MDEV-19877 pam v2: auth_pam_tool input format is... Open
relates to MDEV-19878 pam v2: pam password authentication d... Closed
relates to MDEV-19879 server can send empty error message t... Closed
relates to MDEV-19882 pam v2: auth_pam_tool truncates passw... Closed
relates to MDEV-19898 PAM plugin testing Stalled

 Description   

In MariaDB 10.4, version 2 of the pam plugin is provided. Unfortunately, password authentication seems to be completely broken in version 2. See MDEV-19878 about that.

Luckily, version 1 of the pam plugin is also included. It is possible to install that version by doing the following:

UNINSTALL SONAME 'auth_pam';
INSTALL SONAME 'auth_pam_v1';

Unfortunately, password authentication also seems to be completely broken in version 2 in MariaDB 10.4.

To reproduce, simply do the following:

Create a Unix user account and set a password for the user:

sudo useradd alice
sudo passwd alice

Create the PAM service configuration:

sudo tee /etc/pam.d/mariadb <<EOF
auth required pam_unix.so audit
account required pam_unix.so audit
EOF

Then in MariaDB, install the plugin:

INSTALL SONAME 'auth_pam_v1';

And then create the user account:

CREATE USER 'alice'@'localhost' IDENTIFIED VIA pam USING 'mariadb';

And then you need to do the /etc/shadow workaround for pam_unix:

sudo groupadd shadow
sudo usermod -a -G shadow mysql
sudo chown root:shadow /etc/shadow
sudo chmod g+r /etc/shadow

And then restart MariaDB:

sudo systemctl restart mariadb

And then, try to authenticate as the Unix account (while using the workaround for MDEV-19807):

$ mysql -u alice --plugin-dir=/usr/lib64/mysql/plugin
ERROR 1045 (28000): Access denied for user 'alice'@'localhost' (using password: NO)

The client does not even seem to be prompting for a password.

The pam v1 plugin should properly pass the password to pam_unix, but the syslog shows that the password doesn't work, even though it is correct:

Jun 28 01:58:14 ip-172-30-0-123 unix_chkpwd[7504]: password check failed for user (alice)
Jun 28 01:58:14 ip-172-30-0-123 mysqld: pam_unix(mariadb:auth): authentication failure; logname= uid=997 euid=997 tty= ruser= rhost=  user=alice

The strace output of the client connection/PAM plugin thread seems to show that the plugin is passing an empty string to the unix_chkpwd process:

pipe([48, 49])                          = 0
rt_sigaction(SIGCHLD, {SIG_DFL, [], SA_RESTORER, 0x7f523423e5d0}, {SIG_DFL, [], 0}, 8) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f521c0d29d0) = 7504
write(49, "", 0)                        = 0
write(49, "\0", 1)                      = 1
close(48)                               = 0
close(49)                               = 0
wait4(7504, [{WIFEXITED(s) && WEXITSTATUS(s) == 7}], 0, NULL) = 7504
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=7504, si_uid=997, si_status=7, si_utime=1, si_stime=1} ---
rt_sigaction(SIGCHLD, {SIG_DFL, [], SA_RESTORER, 0x7f523423e5d0}, NULL, 8) = 0
ioctl(0, TCGETS, 0x7f521c0cddb0)        = -1 ENOTTY (Inappropriate ioctl for device)
getuid()                                = 997
geteuid()                               = 997
socket(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 48
connect(48, {sa_family=AF_LOCAL, sun_path="/dev/log"}, 110) = 0
sendto(48, "<85>Jun 28 01:58:14 mysqld: pam_unix(mariadb:auth): authentication failure; logname= uid=997 euid=997 tty= ruser= rhost=  user=alice", 132, MSG_NOSIGNAL, NULL, 0) = 132

The strace output of the unix_chkpwd process confirms that it received the empty string as the password from stdin:

getuid()                                = 997
setuid(997)                             = 0
read(0, "\0", 513)                      = 1
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3

I wanted to try testing how it worked if I provided the password on the command line. Even that fails:

$ mysql -u alice --plugin-dir=/usr/lib64/mysql/plugin -palicemariadb
ERROR 1045 (28000): Access denied for user 'alice'@'localhost' (using password: NO)

And the strace output for that does show that the client connection received the proper password:

recvfrom(47, "\270\0\0\1", 4, MSG_DONTWAIT, NULL, NULL) = 4
recvfrom(47, "\204\246\337 \0\0\0\1!\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\7\0\0\0alice\0\24\206\212\215\1*\252\262H\27K\256,\201\376\236B{\3279pmysql_native_password\0f\3_os\5Linux\f_client_name\nlibmariadb\4_pid\0047576\17_client_version\0053.1.2\t_platform\6x86_64\fprogram_name\5mysql", 184, MSG_DONTWAIT, NULL, NULL) = 184
sendto(47, "\10\0\0\2\376dialog\0", 12, MSG_DONTWAIT, NULL, 0) = 12
recvfrom(47, "\r\0\0\3", 4, MSG_DONTWAIT, NULL, NULL) = 4
recvfrom(47, "alicemariadb\0", 13, MSG_DONTWAIT, NULL, NULL) = 13

But it looks to me like it's still passing the empty string as the password to the unix_chkpwd process:

pipe([48, 49])                          = 0
rt_sigaction(SIGCHLD, {SIG_DFL, [], SA_RESTORER, 0x7fbd8d65b5d0}, {SIG_DFL, [], 0}, 8) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fbd740c29d0) = 7578
write(49, "", 0)                        = 0
write(49, "\0", 1)                      = 1
close(48)                               = 0
close(49)                               = 0
wait4(7578, [{WIFEXITED(s) && WEXITSTATUS(s) == 7}], 0, NULL) = 7578
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=7578, si_uid=997, si_status=7, si_utime=1, si_stime=2} ---
rt_sigaction(SIGCHLD, {SIG_DFL, [], SA_RESTORER, 0x7fbd8d65b5d0}, NULL, 8) = 0
ioctl(0, TCGETS, 0x7fbd740bddb0)        = -1 ENOTTY (Inappropriate ioctl for device)
getuid()                                = 997
geteuid()                               = 997
socket(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0) = 48
connect(48, {sa_family=AF_LOCAL, sun_path="/dev/log"}, 110) = 0
sendto(48, "<85>Jun 28 02:13:59 mysqld: pam_unix(mariadb:auth): authentication failure; logname= uid=997 euid=997 tty= ruser= rhost=  user=alice", 132, MSG_NOSIGNAL, NULL, 0) = 132

And the strace output of the unix_chkpwd process seems to confirm that it is still reading the empty string from stdin:

getuid()                                = 997
setuid(997)                             = 0
read(0, "\0", 513)                      = 1
open("/etc/passwd", O_RDONLY|O_CLOEXEC) = 3


Generated at Thu Feb 08 08:55:04 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.