Allows nova to read files as root
* Adds a rootwrap filter to limit readable files * Adds a utils method to read a file as root * adds tests to verify the additions work Change-Id: Ic1ffb6f72f9b73795d5f39fac719842e6bdf16dd
This commit is contained in:
		@@ -123,3 +123,20 @@ class KillFilter(CommandFilter):
 | 
			
		||||
            # Incorrect PID
 | 
			
		||||
            return False
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ReadFileFilter(CommandFilter):
 | 
			
		||||
    """Specific filter for the utils.read_file_as_root call"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, file_path, *args):
 | 
			
		||||
        self.file_path = file_path
 | 
			
		||||
        super(ReadFileFilter, self).__init__("/bin/cat", "root", *args)
 | 
			
		||||
 | 
			
		||||
    def match(self, userargs):
 | 
			
		||||
        if userargs[0] != 'cat':
 | 
			
		||||
            return False
 | 
			
		||||
        if userargs[1] != self.file_path:
 | 
			
		||||
            return False
 | 
			
		||||
        if len(userargs) != 2:
 | 
			
		||||
            return False
 | 
			
		||||
        return True
 | 
			
		||||
 
 | 
			
		||||
@@ -93,6 +93,15 @@ class RootwrapTestCase(test.TestCase):
 | 
			
		||||
        # Providing -9 signal should work
 | 
			
		||||
        self.assertTrue(f.match(usercmd))
 | 
			
		||||
 | 
			
		||||
    def test_ReadFileFilter(self):
 | 
			
		||||
        goodfn = '/good/file.name'
 | 
			
		||||
        f = filters.ReadFileFilter(goodfn)
 | 
			
		||||
        usercmd = ['cat', '/bad/file']
 | 
			
		||||
        self.assertFalse(f.match(['cat', '/bad/file']))
 | 
			
		||||
        usercmd = ['cat', goodfn]
 | 
			
		||||
        self.assertEqual(f.get_command(usercmd), ['/bin/cat', goodfn])
 | 
			
		||||
        self.assertTrue(f.match(usercmd))
 | 
			
		||||
 | 
			
		||||
    def test_skips(self):
 | 
			
		||||
        # Check that all filters are skipped and that the last matches
 | 
			
		||||
        usercmd = ["cat", "/"]
 | 
			
		||||
 
 | 
			
		||||
@@ -382,6 +382,18 @@ class GenericUtilsTestCase(test.TestCase):
 | 
			
		||||
        self.assertTrue([c for c in password
 | 
			
		||||
                         if c in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'])
 | 
			
		||||
 | 
			
		||||
    def test_read_file_as_root(self):
 | 
			
		||||
        def fake_execute(*args, **kwargs):
 | 
			
		||||
            if args[1] == 'bad':
 | 
			
		||||
                raise exception.ProcessExecutionError
 | 
			
		||||
            return 'fakecontents', None
 | 
			
		||||
 | 
			
		||||
        self.stubs.Set(utils, 'execute', fake_execute)
 | 
			
		||||
        contents = utils.read_file_as_root('good')
 | 
			
		||||
        self.assertEqual(contents, 'fakecontents')
 | 
			
		||||
        self.assertRaises(exception.FileNotFound,
 | 
			
		||||
                          utils.read_file_as_root, 'bad')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class IsUUIDLikeTestCase(test.TestCase):
 | 
			
		||||
    def assertUUIDLike(self, val, expected):
 | 
			
		||||
 
 | 
			
		||||
@@ -1412,3 +1412,12 @@ def generate_mac_address():
 | 
			
		||||
           random.randint(0x00, 0xff),
 | 
			
		||||
           random.randint(0x00, 0xff)]
 | 
			
		||||
    return ':'.join(map(lambda x: "%02x" % x, mac))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def read_file_as_root(file_path):
 | 
			
		||||
    """Secure helper to read file as root."""
 | 
			
		||||
    try:
 | 
			
		||||
        out, _err = execute('cat', file_path, run_as_root=True)
 | 
			
		||||
        return out
 | 
			
		||||
    except exception.ProcessExecutionError:
 | 
			
		||||
        raise exception.FileNotFound(file_path=file_path)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user