Commit eb76397c authored by Martín Ferrari's avatar Martín Ferrari

Don't use uid and gid to run programs, ask for an user/uid and then use

initgroups to set up the groups. Changes in the protocol to allow this.
parent e84afa8c
...@@ -34,9 +34,9 @@ PROC KILL <pid> <signal> 200/500 kill(pid, signal) ...@@ -34,9 +34,9 @@ PROC KILL <pid> <signal> 200/500 kill(pid, signal)
(1) valid arguments: mtu <n>, state <up|down>, name <name>, lladdr <addr> (1) valid arguments: mtu <n>, state <up|down>, name <name>, lladdr <addr>
(2) After PROC CRTE, only secondary PROC cmds are accepted until finished. (2) After PROC CRTE, only secondary PROC cmds are accepted until finished.
Arguments are: uid gid argv[0] argv[1] ... Arguments are: user argv[0] argv[1] ...
The argv parameters are parsed as base64-encoded strings if they start with a The parameters are parsed as base64-encoded strings if they start with a '='
'=' character. character.
(3) Secondary PROC commands, only valid after PROC CRTE. All parameters parsed (3) Secondary PROC commands, only valid after PROC CRTE. All parameters parsed
as base64-encoded strings. Arguments for PROC ENV are pairs of key-value to as base64-encoded strings. Arguments for PROC ENV are pairs of key-value to
...@@ -66,7 +66,7 @@ protocol exchanges occur through the socket. ...@@ -66,7 +66,7 @@ protocol exchanges occur through the socket.
<S> 200 Ok. <S> 200 Ok.
<C> ADDR DEL 10 192.168.1.1 24 <C> ADDR DEL 10 192.168.1.1 24
<S> 500 Address does not exist. <S> 500 Address does not exist.
<C> PROC CRTE 100 100 /bin/sh sh -c sleep 10 <C> PROC CRTE root /bin/sh sh -c sleep 10
<S> 200 Entering PROC mode. <S> 200 Entering PROC mode.
<C> PROC CWD / <C> PROC CWD /
<S> 200 CWD set to /. <S> 200 CWD set to /.
......
...@@ -6,22 +6,35 @@ from netns.node import Node ...@@ -6,22 +6,35 @@ from netns.node import Node
class __Config(object): class __Config(object):
def __init__(self): def __init__(self):
self._run_as = 65535 self._run_as = 65534
try: try:
self._run_as = pwd.getpwnam('nobody')[2] pwd.getpwnam('nobody')
self._run_as = 'nobody'
except: except:
pass pass
def _set_run_as(self, uid): def _set_run_as(self, user):
if type(uid) != int: if str(user).isdigit():
uid = pwd.getpwnam(uid)[2] uid = int(user)
try:
_user = pwd.getpwuid(uid)[0]
except:
raise AttributeError("UID %d does not exist" % int(user))
run_as = int(user)
else:
try:
uid = pwd.getpwnam(str(user))[2]
except:
raise AttributeError("User %s does not exist" % str(user))
run_as = str(user)
if uid == 0: if uid == 0:
raise AttributeError("Cannot run as root by default") raise AttributeError("Cannot run as root by default")
self._run_as = uid self._run_as = run_as
return run_as
def _get_run_as(self): def _get_run_as(self):
return self._run_as return self._run_as
run_as = property(_get_run_as, _set_run_as, None, run_as = property(_get_run_as, _set_run_as, None,
"Default uid to run applications as") "Default user to run applications as")
config = __Config() config = __Config()
get_nodes = Node.get_nodes get_nodes = Node.get_nodes
......
...@@ -39,7 +39,7 @@ _proto_commands = { ...@@ -39,7 +39,7 @@ _proto_commands = {
"DEL": ("sisi", "") "DEL": ("sisi", "")
}, },
"PROC": { "PROC": {
"CRTE": ("iib", "b*"), "CRTE": ("bb", "b*"),
"POLL": ("i", ""), "POLL": ("i", ""),
"WAIT": ("i", ""), "WAIT": ("i", ""),
"KILL": ("i", "i") "KILL": ("i", "i")
...@@ -246,8 +246,8 @@ class Server(object): ...@@ -246,8 +246,8 @@ class Server(object):
self.reply(221, "Sayounara."); self.reply(221, "Sayounara.");
self.closed = True self.closed = True
def do_PROC_CRTE(self, cmdname, uid, gid, file, *argv): def do_PROC_CRTE(self, cmdname, user, file, *argv):
self._proc = { 'uid': uid, 'gid': gid, 'file': file, 'argv': argv } self._proc = { 'user': user, 'file': file, 'argv': argv }
self.commands = _proc_commands self.commands = _proc_commands
self.reply(200, "Entering PROC mode.") self.reply(200, "Entering PROC mode.")
...@@ -416,13 +416,14 @@ class Client(object): ...@@ -416,13 +416,14 @@ class Client(object):
passfd.sendfd(self._fd, fd, "PROC " + type) passfd.sendfd(self._fd, fd, "PROC " + type)
self._read_and_check_reply() self._read_and_check_reply()
def popen(self, uid, gid, file, argv = None, cwd = None, env = None, def popen(self, user, file, argv = None, cwd = None, env = None,
stdin = None, stdout = None, stderr = None): stdin = None, stdout = None, stderr = None):
"""Start a subprocess in the slave; the interface resembles """Start a subprocess in the slave; the interface resembles
subprocess.Popen, but with less functionality. In particular subprocess.Popen, but with less functionality. In particular
stdin/stdout/stderr can only be None or a open file descriptor.""" stdin/stdout/stderr can only be None or a open file descriptor."""
params = ["PROC", "CRTE", uid, gid, base64.b64encode(file)] params = ["PROC", "CRTE", base64.b64encode(user),
base64.b64encode(file)]
if argv != None: if argv != None:
for i in argv: for i in argv:
params.append(base64.b64encode(i)) params.append(base64.b64encode(i))
......
#!/usr/bin/env python #!/usr/bin/env python
# vim:ts=4:sw=4:et:ai:sts=4 # vim:ts=4:sw=4:et:ai:sts=4
import unittest import grp, pwd, unittest
import netns import netns
class TestConfigure(unittest.TestCase): class TestConfigure(unittest.TestCase):
def setUp(self):
# Default == nobody || (uid_t) -1
import pwd
try:
self.nobodyid = pwd.getpwnam('nobody')[2]
except:
self.nobodyid = None
def test_config_run_as_static(self): def test_config_run_as_static(self):
# Not allow root as default user # Don't allow root as default user
self.assertRaises(AttributeError, setattr, netns.config, self.assertRaises(AttributeError, setattr, netns.config,
'run_as', 'root') 'run_as', 'root')
self.assertRaises(AttributeError, setattr, netns.config, self.assertRaises(AttributeError, setattr, netns.config,
'run_as', 0) 'run_as', 0)
self.assertEquals(netns.config.run_as, self.nobodyid or 65535) # Don't allow invalid users
self.assertRaises(AttributeError, setattr, netns.config,
'run_as', 'foobarbaz') # hope nobody has this user!
self.assertRaises(AttributeError, setattr, netns.config,
'run_as', -1)
def test_config_run_as_runtime(self): def test_config_run_as_runtime(self):
netns.config.run_as = (self.nobodyid or 65535) user = netns.config.run_as = 'nobody'
uid = pwd.getpwnam(user)[2]
gid = pwd.getpwnam(user)[3]
groups = [x[2] for x in grp.getgrall() if user in x[3]]
node = netns.Node() node = netns.Node()
app = node.start_process(["sleep", "1000"]) app = node.start_process(["sleep", "1000"])
pid = app.pid pid = app.pid
...@@ -30,12 +31,14 @@ class TestConfigure(unittest.TestCase): ...@@ -30,12 +31,14 @@ class TestConfigure(unittest.TestCase):
while True: while True:
data = stat.readline() data = stat.readline()
fields = data.split() fields = data.split()
if fields[0] != 'Uid:': if fields[0] == 'Uid:':
continue self.assertEquals(fields[1:4], (uid,) * 4)
uid = fields[1] if fields[0] == 'Gid:':
self.assertEquals(fields[1:4], (gid,) * 4)
if fields[0] == 'Groups:':
self.assertEquals(set(fields[1:]), set(groups))
break break
stat.close() stat.close()
self.assertEquals(uid, (self.nobodyid or 65535))
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -74,19 +74,19 @@ class TestServer(unittest.TestCase): ...@@ -74,19 +74,19 @@ class TestServer(unittest.TestCase):
check_error(self, "proc poll 1 2") # too many args check_error(self, "proc poll 1 2") # too many args
check_error(self, "proc poll a") # invalid type check_error(self, "proc poll a") # invalid type
check_ok(self, "proc crte 0 0 /bin/sh", srv.do_PROC_CRTE, check_ok(self, "proc crte 0 /bin/sh", srv.do_PROC_CRTE,
[0, 0, '/bin/sh']) [0, 0, '/bin/sh'])
# Commands that would fail, but the parsing is correct # Commands that would fail, but the parsing is correct
check_ok(self, "proc poll 0", None, [0]) check_ok(self, "proc poll 0", None, [0])
check_ok(self, "proc wait 0", None, [0]) check_ok(self, "proc wait 0", None, [0])
check_ok(self, "proc kill 0", None, [0]) check_ok(self, "proc kill 0", None, [0])
check_error(self, "proc crte 0 0 =") # empty b64 check_error(self, "proc crte 0 =") # empty b64
check_error(self, "proc crte 0 0 =a") # invalid b64 check_error(self, "proc crte 0 =a") # invalid b64
# simulate proc mode # simulate proc mode
srv.commands = netns.protocol._proc_commands srv.commands = netns.protocol._proc_commands
check_error(self, "proc crte 0 0 foo") check_error(self, "proc crte 0 foo")
check_error(self, "proc poll 0") check_error(self, "proc poll 0")
check_error(self, "proc wait 0") check_error(self, "proc wait 0")
check_error(self, "proc kill 0") check_error(self, "proc kill 0")
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment