[MDEV-27341] Use SET PASSWORD to change PAM service Created: 2021-12-21  Updated: 2022-03-09  Resolved: 2022-01-17

Status: Closed
Project: MariaDB Server
Component/s: Authentication and Privilege System, Plugin - pam
Affects Version/s: 10.2, 10.3, 10.4, 10.5, 10.6
Fix Version/s: 10.4.23, 10.5.14, 10.6.6

Type: Bug Priority: Major
Reporter: Edward Stoever Assignee: Sergei Golubchik
Resolution: Fixed Votes: 0
Labels: None


 Description   

Set up:

$ useradd -m testy
$ passwd testy
New password:
Retype new password:
passwd: password updated successfully

On MariaDB:

MariaDB [(none)]> INSTALL SONAME 'auth_pam';
Query OK, 0 rows affected (0.000 sec)
 
MariaDB [(none)]> create user `testy`@`%` identified via PAM using 'm1';
Query OK, 0 rows affected (0.005 sec)

Create files for PAM scripts called M1:
/etc/pam.d/m1

auth required pam_unix.so audit
account required pam_unix.so audit
account required pam_exec.so /etc/pam_scripts/m1.sh

/etc/pam_scripts/m1.sh

#!/bin/sh
echo "m1" >> /var/log/mariadb-auth
exit 0

Create files for PAM scripts called M2:
/etc/pam.d/m2

auth required pam_unix.so audit
account required pam_unix.so audit
account required pam_exec.so /etc/pam_scripts/m2.sh

/etc/pam_scripts/m2.sh

#!/bin/sh
echo "m2" >> /var/log/mariadb-auth
exit 0

Example of changing PAM scripts from m1 to m2 with set password command:

$ mariadb -u testy -s
[mariadb] Password:
MariaDB [(none)]> set password='m2';
MariaDB [(none)]> exit
$ mariadb -u testy -s
[mariadb] Password:
MariaDB [(none)]> exit

Now check the log, and you will see that both M1 and M2 have been used for this:

$ cat /var/log/mariadb-auth
m1
m2

A user can bypass PAM scripts and still login by setting password to something that does not exist.

Query to review before and after SET PASSWORD command:

select * from mysql.global_priv where user = 'testy';



 Comments   
Comment by Sergei Golubchik [ 2022-01-04 ]

We need to change the auth api to support plugins that have the concept of "auth info" which isn't a password and should not be changed by the user in SET PASSWORD.

Options:

how api compatible abi compatible usbsn plugin 2)
hash_password==NULL && preprocess_hash==NULL bug reappears no changes needs memcpy preprocess_hash
hash_password==NULL && preprocess_hash returns an error CREATE USER breaks no changes just works
hash_password==NULL && preprocess_hash returns a special value (e.g. 2) CREATE USER breaks no changes just works
hash_password==NULL && preprocess_hash has a special value (e.g. 1) crash no changes just works
hash_password==NULL && preprocess_hash has a special value (func in the server) won't load no changes just works
hash_password==NULL 1) any of the above no changes not supported
new "flags" field no compatible change just works

1) Note that "hash_password=NULL" approach is consistent with password validation — validation is only used when hash_password is not NULL, otherwise the string is not considered a password.

2) usbsn auth plugin is a plugin (from the plugin book) where auth_str is not a password, but should be settable by a user.

Comment by Sergei Golubchik [ 2022-01-04 ]

or may be it shouldn't be a plugin property, but a server setting? or per-account setting?

Comment by Sergei Golubchik [ 2022-01-04 ]

another option would be to introduce a new concept of "auth info, not user password" in addition to (not instead of) the password. So that hypothetically a plugin could have both. Could be specified like

create user identified via "plugin:auth" using "password"

the first "auth" will not be considered a password and a user won't be able to change it.

It needs no sql parser changes and no auth api changes unless a plugin wants to support both (none does at the moment). It's SQL syntax for users though, need to migrate scripts, etc.

Comment by Sergei Golubchik [ 2022-01-04 ]

"plugin:auth" isn't very SQL-ish, so could be config "auth" or may be even arbitrary key-value pairs like in CREATE TABLE.

Comment by Sergei Golubchik [ 2022-01-04 ]

simple solution: sysvar @@pam_service. If set, it overrides auth string

Comment by Sergei Golubchik [ 2022-01-04 ]

Multi-step approach:

1. sysvar @@pam_service. This is done in 10.2

2. Later, as needed, key=value pairs, CREATE TABLE style. In the parser

--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -17253,6 +17253,10 @@ opt_auth_str:
             MYSQL_YYABORT;
           $$->pwtext= $4;
         }
+      | using_or_as IDENT_sys '=' TEXT_STRING_sys { }
+      | using_or_as IDENT_sys '=' ident { }
+      | using_or_as IDENT_sys '=' real_ulonglong_num { }
+      | using_or_as IDENT_sys '=' DEFAULT { } /* may be? */
       ;
 
  opt_require_clause:

They're defined similar to https://mariadb.com/kb/en/engine-defined-new-tablefieldindex-attributes/ including the "SYSVAR" type. Array of declarations is stored in the info structure. Every option declares whether it's user or DBA settable. PASSWORD option uses hash_password() and preprocess_hash() and its values are validated.

It would allow something like

create user foo@bar identified by pam using service='mysql' use_cleartext_plugin=0 winbind_workaround=true
                               or unix_socket
                               or gssapi using group='Administrator' mech_name=negotiate
                               or ed25519 using auth='Y5fV74JAVRMOK2cdnUsYS+WW9sXaaL/o+6WGKOgqnzc'

Old auth_string from USING ... and AS ... are treated as a password. In particular pam plugin will use service= value from the CREATE USER if specified, otherwise the sysvar if specified, otherwise the old auth_string.

Comment by Sergei Golubchik [ 2022-03-09 ]

Implemented solution: disallow

SET PASSWORD = 'string'

for plugins that don't support

SET PASSWORD = PASSWORD('string')

That is, if the plugin doesn't provide a password hashing function PASSWORD(), then SET PASSWORD won't work.

Generated at Thu Feb 08 09:52:11 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.