Skip to content

Commit a4859d1

Browse files
committed
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 <[email protected]>
1 parent f0df31e commit a4859d1

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

pyipmi/session.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,18 @@ def set_auth_type_user(self, username, password):
107107

108108
@property
109109
def auth_username(self):
110-
return self._auth_username
110+
return self._escape_dollar_sign(self._auth_username)
111111

112112
@property
113113
def auth_password(self):
114-
return self._auth_password
114+
return self._escape_dollar_sign(self._auth_password)
115+
116+
def _escape_dollar_sign(self, password):
117+
"""Escape string with dollar sign in ipmitool."""
118+
# The IPMI command is built and executed in a shell using Popen.
119+
# The '$_' combination has its own behavior in shell and it gets
120+
# replaced in the string.
121+
return password.replace('$', '\\$')
115122

116123
def establish(self):
117124
if hasattr(self.interface, 'establish_session'):

tests/test_session.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from pyipmi.session import Session
2+
from subprocess import Popen, PIPE
3+
4+
5+
def test_auth_username():
6+
username = 'ad$_min'
7+
password = 'password'
8+
session = Session()
9+
session.set_auth_type_user(username, password)
10+
child = Popen(f"echo {session.auth_username}", shell=True, stdout=PIPE)
11+
output = child.communicate()[0].decode('utf-8').strip()
12+
assert output == username
13+
14+
15+
def test_auth_password():
16+
username = 'admin'
17+
password = 'pass$_word'
18+
session = Session()
19+
session.set_auth_type_user(username, password)
20+
child = Popen(f"echo {session.auth_password}", shell=True, stdout=PIPE)
21+
output = child.communicate()[0].decode('utf-8').strip()
22+
assert output == password

0 commit comments

Comments
 (0)