Skip to content

Commit 9d98acd

Browse files
authored
fix: Quote CL cmd in iCmd5250 for shell escaping (#50)
iCmd5250 is just a fancy wrapper around iSh, using the PASE system command. It did not do any shell escaping/quoting, so it basically only allowed calling CL commands without parameters or with only positional parameters because the parentheses would cause the shell to gack. eg. iCmd5250('wrkactjob', 'WRKACTJOB SBS(QBATCH)') basically became iSh('wrkactjob', '/QOpenSys/usr/bin/system WRKACTJOB SBS(QBATCH)') When executed, an error would be given from the shell: sh: syntax error at line 1 : `(' unexpected The proper fix is to quote the string, but that can be tricky to get right. Luckily, Python has shlex.quote to do the hard work for us. https://docs.python.org/3/library/shlex.html#shlex.quote For Python 2, we have to add our own shlex.quote equivalent. Fixes #49
1 parent 0afda17 commit 9d98acd

File tree

2 files changed

+49
-10
lines changed

2 files changed

+49
-10
lines changed

src/itoolkit/itoolkit.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,18 @@ class iXml(iBase): IBM i XMLSERVICE raw xml input
113113
import re
114114
import time
115115

116+
try:
117+
from shlex import quote
118+
except ImportError:
119+
# python2 has shlex, but not shlex.quote
120+
# Implement a crude equivalent. We don't care about Python 2 that much
121+
def quote(s):
122+
if ' ' not in s:
123+
return s
124+
125+
# remove first and last space to be less confusing
126+
quote_replacement = """ '"'"' """[1:-1]
127+
return "'" + s.replace("'", quote_replacement) + "'"
116128

117129
class iBase(object): # noqa N801
118130
"""
@@ -329,7 +341,7 @@ class iCmd5250(iSh): # noqa N801
329341
"""
330342

331343
def __init__(self, ikey, icmd, iopt={}):
332-
cmd = "/QOpenSys/usr/bin/system " + icmd
344+
cmd = "/QOpenSys/usr/bin/system " + quote(icmd)
333345
super(iCmd5250, self).__init__(ikey, cmd, iopt)
334346

335347

tests/test_unit_cmd5250.py

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@
33
from itoolkit import iCmd5250
44

55

6-
def to5250(cmd):
7-
return "/QOpenSys/usr/bin/system {}".format(cmd)
8-
9-
106
def test_5250():
117
cmd = 'WRKACTJOB'
128
key = 'lljqezl'
@@ -20,7 +16,7 @@ def test_5250():
2016
assert('var' in element.attrib)
2117
assert(element.attrib['var'] == key)
2218

23-
assert(element.text == to5250(cmd))
19+
assert(element.text == "/QOpenSys/usr/bin/system WRKACTJOB")
2420

2521

2622
def test_5250_error_on():
@@ -37,7 +33,7 @@ def test_5250_error_on():
3733
assert('var' in element.attrib)
3834
assert(element.attrib['var'] == key)
3935

40-
assert(element.text == to5250(cmd))
36+
assert(element.text == "/QOpenSys/usr/bin/system WRKACTJOB")
4137

4238

4339
def test_5250_error_off():
@@ -54,7 +50,7 @@ def test_5250_error_off():
5450
assert('var' in element.attrib)
5551
assert(element.attrib['var'] == key)
5652

57-
assert(element.text == to5250(cmd))
53+
assert(element.text == "/QOpenSys/usr/bin/system WRKACTJOB")
5854

5955

6056
def test_5250_row_on():
@@ -71,7 +67,7 @@ def test_5250_row_on():
7167
assert('var' in element.attrib)
7268
assert(element.attrib['var'] == key)
7369

74-
assert(element.text == to5250(cmd))
70+
assert(element.text == "/QOpenSys/usr/bin/system WRKACTJOB")
7571

7672

7773
def test_5250_row_off():
@@ -88,4 +84,35 @@ def test_5250_row_off():
8884
assert('var' in element.attrib)
8985
assert(element.attrib['var'] == key)
9086

91-
assert(element.text == to5250(cmd))
87+
assert(element.text == "/QOpenSys/usr/bin/system WRKACTJOB")
88+
89+
def test_5250_space():
90+
cmd = 'WRKACTJOB SBS(*QINTER)'
91+
key = 'lknwqekrn'
92+
93+
element = ET.fromstring(iCmd5250(key, cmd).xml_in())
94+
assert(element.tag == 'sh')
95+
96+
assert('error' in element.attrib)
97+
assert(element.attrib['error'] == 'fast')
98+
99+
assert('var' in element.attrib)
100+
assert(element.attrib['var'] == key)
101+
102+
assert(element.text == "/QOpenSys/usr/bin/system 'WRKACTJOB SBS(*QINTER)'")
103+
104+
105+
def test_5250_inner_string():
106+
cmd = "wrklnk '/test/file'"
107+
key = 'znxvlkja'
108+
109+
element = ET.fromstring(iCmd5250(key, cmd).xml_in())
110+
assert(element.tag == 'sh')
111+
112+
assert('error' in element.attrib)
113+
assert(element.attrib['error'] == 'fast')
114+
115+
assert('var' in element.attrib)
116+
assert(element.attrib['var'] == key)
117+
118+
assert(element.text == """/QOpenSys/usr/bin/system 'wrklnk '"'"'/test/file'"'"''""")

0 commit comments

Comments
 (0)