diff --git a/NEWS b/NEWS index 5897df34..73b6af0d 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,8 @@ * Add the NEWS changelog file to release tarball (#1298). * Enable reply by email on projects.torsion.org, so replies to notification emails get posted as comments on tickets. + * For the MariaDB and MySQL database hooks, escape quotes in passwords when the + "password_transport" option is "pipe". 2.1.5 * #1229: Document the permissions needed for the PostgreSQL database hook: diff --git a/borgmatic/hooks/data_source/mariadb.py b/borgmatic/hooks/data_source/mariadb.py index a6f744b9..352afdde 100644 --- a/borgmatic/hooks/data_source/mariadb.py +++ b/borgmatic/hooks/data_source/mariadb.py @@ -67,7 +67,9 @@ def make_defaults_file_options(username=None, password=None, defaults_extra_file Do not use the returned value for multiple different command invocations. That will not work because each pipe is "used up" once read. ''' - escaped_password = None if password is None else password.replace('\\', '\\\\') + escaped_password = ( + None if password is None else password.replace('\\', '\\\\').replace('"', '\\"') + ) values = '\n'.join( ( diff --git a/tests/unit/hooks/data_source/test_mariadb.py b/tests/unit/hooks/data_source/test_mariadb.py index 3054006c..04d4498f 100644 --- a/tests/unit/hooks/data_source/test_mariadb.py +++ b/tests/unit/hooks/data_source/test_mariadb.py @@ -64,6 +64,23 @@ def test_make_defaults_file_escapes_password_containing_backslash(): ) +def test_make_defaults_file_escapes_password_containing_quote(): + read_descriptor = 99 + write_descriptor = flexmock() + + flexmock(module.os).should_receive('pipe').and_return(read_descriptor, write_descriptor) + flexmock(module.os).should_receive('write').with_args( + write_descriptor, + b'[client]\nuser=root\n' + rb'password="trust\"some1"', + ).once() + flexmock(module.os).should_receive('close') + flexmock(module.os).should_receive('set_inheritable') + + assert module.make_defaults_file_options(username='root', password=r'trust"some1') == ( + '--defaults-extra-file=/dev/fd/99', + ) + + def test_make_defaults_file_pipe_with_only_username_writes_it_to_file_descriptor(): read_descriptor = 99 write_descriptor = flexmock()