Revision 7ebd876f
b/lib/utils/__init__.py | ||
---|---|---|
73 | 73 |
UUID_RE = re.compile('^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-' |
74 | 74 |
'[a-f0-9]{4}-[a-f0-9]{12}$') |
75 | 75 |
|
76 |
#: Shell param checker regexp |
|
77 |
_SHELLPARAM_REGEX = re.compile(r"^[-a-zA-Z0-9._+/:%@]+$") |
|
78 |
|
|
79 | 76 |
|
80 | 77 |
def ForceDictType(target, key_types, allowed_values=None): |
81 | 78 |
"""Force the values of a dict to have certain types. |
... | ... | |
232 | 229 |
return nv |
233 | 230 |
|
234 | 231 |
|
235 |
def IsValidShellParam(word): |
|
236 |
"""Verifies is the given word is safe from the shell's p.o.v. |
|
237 |
|
|
238 |
This means that we can pass this to a command via the shell and be |
|
239 |
sure that it doesn't alter the command line and is passed as such to |
|
240 |
the actual command. |
|
241 |
|
|
242 |
Note that we are overly restrictive here, in order to be on the safe |
|
243 |
side. |
|
244 |
|
|
245 |
@type word: str |
|
246 |
@param word: the word to check |
|
247 |
@rtype: boolean |
|
248 |
@return: True if the word is 'safe' |
|
249 |
|
|
250 |
""" |
|
251 |
return bool(_SHELLPARAM_REGEX.match(word)) |
|
252 |
|
|
253 |
|
|
254 |
def BuildShellCmd(template, *args): |
|
255 |
"""Build a safe shell command line from the given arguments. |
|
256 |
|
|
257 |
This function will check all arguments in the args list so that they |
|
258 |
are valid shell parameters (i.e. they don't contain shell |
|
259 |
metacharacters). If everything is ok, it will return the result of |
|
260 |
template % args. |
|
261 |
|
|
262 |
@type template: str |
|
263 |
@param template: the string holding the template for the |
|
264 |
string formatting |
|
265 |
@rtype: str |
|
266 |
@return: the expanded command line |
|
267 |
|
|
268 |
""" |
|
269 |
for word in args: |
|
270 |
if not IsValidShellParam(word): |
|
271 |
raise errors.ProgrammerError("Shell argument '%s' contains" |
|
272 |
" invalid characters" % word) |
|
273 |
return template % args |
|
274 |
|
|
275 |
|
|
276 | 232 |
def ParseCpuMask(cpu_mask): |
277 | 233 |
"""Parse a CPU mask definition and return the list of CPU IDs. |
278 | 234 |
|
b/lib/utils/text.py | ||
---|---|---|
40 | 40 |
#: MAC checker regexp |
41 | 41 |
_MAC_CHECK_RE = re.compile("^([0-9a-f]{2}:){5}[0-9a-f]{2}$", re.I) |
42 | 42 |
|
43 |
#: Shell param checker regexp |
|
44 |
_SHELLPARAM_REGEX = re.compile(r"^[-a-zA-Z0-9._+/:%@]+$") |
|
45 |
|
|
43 | 46 |
|
44 | 47 |
def MatchNameComponent(key, name_list, case_sensitive=True): |
45 | 48 |
"""Try to match a name against a list. |
... | ... | |
442 | 445 |
self.flush() |
443 | 446 |
if self._buffer: |
444 | 447 |
self._line_fn(self._buffer) |
448 |
|
|
449 |
|
|
450 |
def IsValidShellParam(word): |
|
451 |
"""Verifies is the given word is safe from the shell's p.o.v. |
|
452 |
|
|
453 |
This means that we can pass this to a command via the shell and be |
|
454 |
sure that it doesn't alter the command line and is passed as such to |
|
455 |
the actual command. |
|
456 |
|
|
457 |
Note that we are overly restrictive here, in order to be on the safe |
|
458 |
side. |
|
459 |
|
|
460 |
@type word: str |
|
461 |
@param word: the word to check |
|
462 |
@rtype: boolean |
|
463 |
@return: True if the word is 'safe' |
|
464 |
|
|
465 |
""" |
|
466 |
return bool(_SHELLPARAM_REGEX.match(word)) |
|
467 |
|
|
468 |
|
|
469 |
def BuildShellCmd(template, *args): |
|
470 |
"""Build a safe shell command line from the given arguments. |
|
471 |
|
|
472 |
This function will check all arguments in the args list so that they |
|
473 |
are valid shell parameters (i.e. they don't contain shell |
|
474 |
metacharacters). If everything is ok, it will return the result of |
|
475 |
template % args. |
|
476 |
|
|
477 |
@type template: str |
|
478 |
@param template: the string holding the template for the |
|
479 |
string formatting |
|
480 |
@rtype: str |
|
481 |
@return: the expanded command line |
|
482 |
|
|
483 |
""" |
|
484 |
for word in args: |
|
485 |
if not IsValidShellParam(word): |
|
486 |
raise errors.ProgrammerError("Shell argument '%s' contains" |
|
487 |
" invalid characters" % word) |
|
488 |
return template % args |
b/test/ganeti.utils.text_unittest.py | ||
---|---|---|
422 | 422 |
"", "x"]) |
423 | 423 |
|
424 | 424 |
|
425 |
class TestIsValidShellParam(unittest.TestCase): |
|
426 |
def test(self): |
|
427 |
for val, result in [ |
|
428 |
("abc", True), |
|
429 |
("ab;cd", False), |
|
430 |
]: |
|
431 |
self.assertEqual(utils.IsValidShellParam(val), result) |
|
432 |
|
|
433 |
|
|
434 |
class TestBuildShellCmd(unittest.TestCase): |
|
435 |
def test(self): |
|
436 |
self.assertRaises(errors.ProgrammerError, utils.BuildShellCmd, |
|
437 |
"ls %s", "ab;cd") |
|
438 |
self.assertEqual(utils.BuildShellCmd("ls %s", "ab"), "ls ab") |
|
439 |
|
|
440 |
|
|
425 | 441 |
if __name__ == "__main__": |
426 | 442 |
testutils.GanetiTestProgram() |
b/test/ganeti.utils_unittest.py | ||
---|---|---|
305 | 305 |
self.assertEqual(utils.TryConvert(fn, src), result) |
306 | 306 |
|
307 | 307 |
|
308 |
class TestIsValidShellParam(unittest.TestCase): |
|
309 |
def test(self): |
|
310 |
for val, result in [ |
|
311 |
("abc", True), |
|
312 |
("ab;cd", False), |
|
313 |
]: |
|
314 |
self.assertEqual(utils.IsValidShellParam(val), result) |
|
315 |
|
|
316 |
|
|
317 |
class TestBuildShellCmd(unittest.TestCase): |
|
318 |
def test(self): |
|
319 |
self.assertRaises(errors.ProgrammerError, utils.BuildShellCmd, |
|
320 |
"ls %s", "ab;cd") |
|
321 |
self.assertEqual(utils.BuildShellCmd("ls %s", "ab"), "ls ab") |
|
322 |
|
|
323 |
|
|
324 | 308 |
if __name__ == '__main__': |
325 | 309 |
testutils.GanetiTestProgram() |
Also available in: Unified diff