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