From a4859d1692f18b04fbf680ee463d5dac284c86fa Mon Sep 17 00:00:00 2001 From: Evloev Sayfuddin Date: Tue, 7 Jan 2025 16:00:57 +0300 Subject: [PATCH] fix: escape dollar sign from args IPMI commands get executed in a separate shell where the combination "status" has its own behavior. In our case, Popen starts a new shell, for example by running /bin/bash, and when the BMC password contains the combination above it gets replaced to "bin/bash" (in this case the combination holds the last executed command as a string). I have added a method to Session class that will escape the dollar sign and test function. Such behavior is expected with other signs (like combination "^_") but I didn't find it critical for them. Signed-off-by: Evloev Sayfuddin --- pyipmi/session.py | 11 +++++++++-- tests/test_session.py | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 tests/test_session.py diff --git a/pyipmi/session.py b/pyipmi/session.py index 6d9d200..bcdd51b 100644 --- a/pyipmi/session.py +++ b/pyipmi/session.py @@ -107,11 +107,18 @@ def set_auth_type_user(self, username, password): @property def auth_username(self): - return self._auth_username + return self._escape_dollar_sign(self._auth_username) @property def auth_password(self): - return self._auth_password + return self._escape_dollar_sign(self._auth_password) + + def _escape_dollar_sign(self, password): + """Escape string with dollar sign in ipmitool.""" + # The IPMI command is built and executed in a shell using Popen. + # The '$_' combination has its own behavior in shell and it gets + # replaced in the string. + return password.replace('$', '\\$') def establish(self): if hasattr(self.interface, 'establish_session'): diff --git a/tests/test_session.py b/tests/test_session.py new file mode 100644 index 0000000..04d7304 --- /dev/null +++ b/tests/test_session.py @@ -0,0 +1,22 @@ +from pyipmi.session import Session +from subprocess import Popen, PIPE + + +def test_auth_username(): + username = 'ad$_min' + password = 'password' + session = Session() + session.set_auth_type_user(username, password) + child = Popen(f"echo {session.auth_username}", shell=True, stdout=PIPE) + output = child.communicate()[0].decode('utf-8').strip() + assert output == username + + +def test_auth_password(): + username = 'admin' + password = 'pass$_word' + session = Session() + session.set_auth_type_user(username, password) + child = Popen(f"echo {session.auth_password}", shell=True, stdout=PIPE) + output = child.communicate()[0].decode('utf-8').strip() + assert output == password