From dd93028dae22f00a6b23ff27d348ff1a4722ee88 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 30 Jun 2019 20:41:26 +0200 Subject: MDEV-19878 pam v2: pam password authentication doesn't work at all * wait() for the child process to die, let it rest in peace * fix incorrect parentheses * if there was no password on the command line or in .cnf file, pkt will be "", and we need to request the user to enter the password * make sure that auth->salt is always allocated on a permanent memroot. when called from set_user_salt_if_needed(), user_copy and its auth_str are on the thd memroot, but auth_copy->salt is then copied to auth->salt * adjust service files so that systemd wouldn't interfere with our setuid executables also * print the pam error message in debug mode --- mysql-test/suite/plugins/r/pam.result | 33 +++++++++++++++++++++++---------- mysql-test/suite/plugins/t/pam.test | 20 +++++++++++++++++++- plugin/auth_pam/auth_pam.c | 7 +++++-- plugin/auth_pam/auth_pam_base.c | 3 ++- plugin/auth_pam/auth_pam_tool.c | 2 ++ sql/sql_acl.cc | 2 +- support-files/mariadb.service.in | 15 ++++++++++++--- support-files/mariadb@.service.in | 15 ++++++++++++--- 8 files changed, 76 insertions(+), 21 deletions(-) diff --git a/mysql-test/suite/plugins/r/pam.result b/mysql-test/suite/plugins/r/pam.result index 1d70f530969..40075245d0c 100644 --- a/mysql-test/suite/plugins/r/pam.result +++ b/mysql-test/suite/plugins/r/pam.result @@ -7,9 +7,9 @@ grant proxy on pam_test to test_pam; # note that current_user() differs from user() # Challenge input first. -Enter: not very secret challenge +Enter: ************************* Now, the magic number! -PIN: **** +PIN: 9225 select user(), current_user(), database(); user() current_user() database() test_pam@localhost pam_test@% test @@ -17,16 +17,29 @@ test_pam@localhost pam_test@% test # athentication is unsuccessful # Challenge input first. -Enter: not very secret challenge +Enter: ************************* Now, the magic number! -PIN: **** +PIN: 9224 # # athentication is unsuccessful # Challenge input first. -Enter: crash pam module +Enter: **************** Now, the magic number! -PIN: *** +PIN: 616 +# +# athentication is successful +# +Now, the magic number! +PIN: 9212 +select user(), current_user(), database(); +user() current_user() database() +test_pam@localhost pam_test@% test +# +# athentication is unsuccessful +# +Now, the magic number! +PIN: 9212 drop user test_pam; drop user pam_test; create user PAM_TEST identified via pam using 'mariadb_mtr'; @@ -34,17 +47,17 @@ create user PAM_TEST identified via pam using 'mariadb_mtr'; # athentication is unsuccessful # Challenge input first. -Enter: not very secret challenge +Enter: ************************* Now, the magic number! -PIN: **** +PIN: 9225 set global pam_winbind_workaround=1; # # athentication is successful # Challenge input first. -Enter: not very secret challenge +Enter: ************************* Now, the magic number! -PIN: **** +PIN: 9225 select user(), current_user(), database(); user() current_user() database() PAM_TEST@localhost PAM_TEST@% test diff --git a/mysql-test/suite/plugins/t/pam.test b/mysql-test/suite/plugins/t/pam.test index 040b26ef8b8..1bb1fa2c230 100644 --- a/mysql-test/suite/plugins/t/pam.test +++ b/mysql-test/suite/plugins/t/pam.test @@ -15,7 +15,12 @@ EOF --write_file $MYSQLTEST_VARDIR/tmp/pam_ugly.txt crash pam module -666 +616 +select user(), current_user(), database(); +EOF + +--write_file $MYSQLTEST_VARDIR/tmp/pam_good2.txt +9212 select user(), current_user(), database(); EOF @@ -37,6 +42,18 @@ EOF --error 1 --exec $MYSQL_TEST -u test_pam --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/pam_ugly.txt +--echo # +--echo # athentication is successful +--echo # +--error 0 +--exec $MYSQL_TEST -u test_pam -pgoodpassword --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/pam_good2.txt + +--echo # +--echo # athentication is unsuccessful +--echo # +--error 1 +--exec $MYSQL_TEST -u test_pam -pbadpassword --plugin-dir=$plugindir < $MYSQLTEST_VARDIR/tmp/pam_good2.txt + drop user test_pam; drop user pam_test; create user PAM_TEST identified via pam using 'mariadb_mtr'; @@ -54,6 +71,7 @@ set global pam_winbind_workaround=1; --exec $MYSQL_TEST -u PAM_TEST < $MYSQLTEST_VARDIR/tmp/pam_good.txt --remove_file $MYSQLTEST_VARDIR/tmp/pam_good.txt +--remove_file $MYSQLTEST_VARDIR/tmp/pam_good2.txt --remove_file $MYSQLTEST_VARDIR/tmp/pam_bad.txt --remove_file $MYSQLTEST_VARDIR/tmp/pam_ugly.txt drop user PAM_TEST; diff --git a/plugin/auth_pam/auth_pam.c b/plugin/auth_pam/auth_pam.c index 45a5028429f..ec0096609ba 100644 --- a/plugin/auth_pam/auth_pam.c +++ b/plugin/auth_pam/auth_pam.c @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include "auth_pam_tool.h" #include @@ -101,7 +103,7 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) /* no user name yet ? read the client handshake packet with the user name */ if (info->user_name == 0) { - if ((pkt_len= vio->read_packet(vio, &pkt) < 0)) + if ((pkt_len= vio->read_packet(vio, &pkt)) < 0) return CR_ERROR; } else @@ -157,7 +159,7 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) if ((buf_len= read_string(c_to_p[0], (char *) buf, sizeof(buf))) < 0) goto error_ret; - if (!pkt || (buf[0] >> 1) != 2) + if (!pkt || !*pkt || (buf[0] >> 1) != 2) { PAM_DEBUG((stderr, "PAM: sending CONV string.\n")); if (vio->write_packet(vio, buf, buf_len)) @@ -186,6 +188,7 @@ static int pam_auth(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info) error_ret: close(p_to_c[1]); close(c_to_p[0]); + waitpid(proc_id, NULL, WNOHANG); PAM_DEBUG((stderr, "PAM: auth result %d.\n", result)); return result; diff --git a/plugin/auth_pam/auth_pam_base.c b/plugin/auth_pam/auth_pam_base.c index a23cfcbfd65..cdaafa58b98 100644 --- a/plugin/auth_pam/auth_pam_base.c +++ b/plugin/auth_pam/auth_pam_base.c @@ -170,8 +170,9 @@ static int pam_auth_base(struct param *param, MYSQL_SERVER_AUTH_INFO *info) info->authenticated_as[sizeof(info->authenticated_as)-1]= 0; end: + PAM_DEBUG((stderr, "PAM: status = %d (%s) user = %s\n", + status, pam_strerror(pamh, status), info->authenticated_as)); pam_end(pamh, status); - PAM_DEBUG((stderr, "PAM: status = %d user = %s\n", status, info->authenticated_as)); return status == PAM_SUCCESS ? CR_OK : CR_ERROR; } diff --git a/plugin/auth_pam/auth_pam_tool.c b/plugin/auth_pam/auth_pam_tool.c index 6fd30b457ee..3ab2e00c142 100644 --- a/plugin/auth_pam/auth_pam_tool.c +++ b/plugin/auth_pam/auth_pam_tool.c @@ -70,6 +70,8 @@ int main(int argc, char **argv) int res; char a_buf[MYSQL_USERNAME_LENGTH + 1 + 1024]; + setreuid(0, 0); + if (read(0, &field, 1) < 1) return -1; #ifndef DBUG_OFF diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 076b2e2994d..382275320e5 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2072,7 +2072,7 @@ static int set_user_salt(ACL_USER::AUTH *auth, plugin_ref plugin) auth->salt.length= len; } else - auth->salt= auth->auth_string; + auth->salt= safe_lexcstrdup_root(&acl_memroot, auth->auth_string); return 0; } diff --git a/support-files/mariadb.service.in b/support-files/mariadb.service.in index 8d43b6db428..c31e883000d 100644 --- a/support-files/mariadb.service.in +++ b/support-files/mariadb.service.in @@ -43,7 +43,7 @@ PrivateNetwork=false User=mysql Group=mysql -# To allow memlock to be used as non-root user if set in configuration +# CAP_IPC_LOCK To allow memlock to be used as non-root user CapabilityBoundingSet=CAP_IPC_LOCK # Prevent writes to /usr, /boot, and /etc @@ -52,8 +52,6 @@ ProtectSystem=full # Doesn't yet work properly with SELinux enabled # NoNewPrivileges=true -PrivateDevices=true - # Prevent accessing /home, /root and /run/user ProtectHome=true @@ -98,6 +96,17 @@ RestartSec=5s UMask=007 +############################################################################## +## PAM plugin section +# +# CAP_DAC_OVERRIDE To allow auth_pam_tool (which is SUID root) to read /etc/shadow when it's chmod 0 +# does nothing for non-root, not needed if /etc/shadow is u+r +# CAP_AUDIT_WRITE Needed on Debian for whatever reason +CapabilityBoundingSet=CAP_DAC_OVERRIDE CAP_AUDIT_WRITE + +# PrivateDevices=true implies NoNewPrivileges=true and SUID doesn't work at all +PrivateDevices=false + ############################################################################## ## USERs can override ## diff --git a/support-files/mariadb@.service.in b/support-files/mariadb@.service.in index f0e82860aa0..fc87742e705 100644 --- a/support-files/mariadb@.service.in +++ b/support-files/mariadb@.service.in @@ -164,7 +164,7 @@ PrivateNetwork=false ## Package maintainers ## -# To allow memlock to be used as non-root user if set in configuration +# CAP_IPC_LOCK To allow memlock to be used as non-root user CapabilityBoundingSet=CAP_IPC_LOCK # Prevent writes to /usr, /boot, and /etc @@ -174,8 +174,6 @@ ProtectSystem=full # (https://github.com/systemd/systemd/issues/3845) # NoNewPrivileges=true -PrivateDevices=true - # Prevent accessing /home, /root and /run/user ProtectHome=true @@ -202,6 +200,17 @@ RestartSec=5s UMask=007 +############################################################################## +## PAM plugin section +# +# CAP_DAC_OVERRIDE To allow auth_pam_tool (which is SUID root) to read /etc/shadow when it's chmod 0 +# does nothing for non-root, not needed if /etc/shadow is u+r +# CAP_AUDIT_WRITE Needed on Debian for whatever reason +CapabilityBoundingSet=CAP_DAC_OVERRIDE CAP_AUDIT_WRITE + +# PrivateDevices=true implies NoNewPrivileges=true and SUID doesn't work at all +PrivateDevices=false + ############################################################################## ## USERs can override ## -- cgit v1.2.1