示例#1
0
    def _continue_run(self, graphs):
        deferred_list = []
        now = int(self._create_time())

        for graph_id, filename, user in graphs:
            if os.path.isfile(filename):
                script_hash = self._get_script_hash(filename)
            else:
                script_hash = b""
            if graph_id not in self._data:
                self._data[graph_id] = {
                    "values": [], "error": u"", "script-hash": script_hash}
            else:
                self._data[graph_id]["script-hash"] = script_hash
            try:
                uid, gid, path = get_user_info(user)
            except UnknownUserError as e:
                d = fail(e)
                d.addErrback(self._handle_error, graph_id)
                deferred_list.append(d)
                continue
            if not self.is_user_allowed(user):
                d = fail(ProhibitedUserError(user))
                d.addErrback(self._handle_error, graph_id)
                deferred_list.append(d)
                continue
            if not os.path.isfile(filename):
                continue
            result = self._run_script(
                filename, uid, gid, path, {}, self.time_limit)
            result.addCallback(self._handle_data, graph_id, now)
            result.addErrback(self._handle_error, graph_id)
            deferred_list.append(result)
        return DeferredList(deferred_list)
    def test_user(self):
        """A user can be specified in the message."""
        username = pwd.getpwuid(os.getuid())[0]
        uid, gid, home = get_user_info(username)

        def spawnProcess(protocol, filename, args, env, path, uid, gid):
            protocol.childDataReceived(1, "hi!\n")
            protocol.processEnded(Failure(ProcessDone(0)))
            self._verify_script(filename, sys.executable, "print 'hi'")

        process_factory = mock.Mock()
        process_factory.spawnProcess = mock.Mock(side_effect=spawnProcess)
        self.manager.add(
            ScriptExecutionPlugin(process_factory=process_factory))

        result = self._send_script(sys.executable, "print 'hi'", user=username)

        def check(_):
            process_factory.spawnProcess.assert_called_with(
                mock.ANY,
                mock.ANY,
                args=mock.ANY,
                uid=None,
                gid=None,
                path=mock.ANY,
                env=get_default_environment())

        return result.addCallback(check)
示例#3
0
    def _handle_custom_graph_add(self, message):
        """
        Handle add custom-graph operation, which can also update an existing
        custom graph script.
        """
        user = message["username"]
        shell = message["interpreter"]
        code = message["code"]
        graph_id = int(message["graph-id"])

        data_path = self.registry.config.data_path
        scripts_directory = os.path.join(data_path, "custom-graph-scripts")
        filename = os.path.join(
            scripts_directory, "graph-%d" % (graph_id,))

        if os.path.exists(filename):
            os.unlink(filename)

        try:
            uid, gid = get_user_info(user)[:2]
        except UnknownUserError:
            logging.error(u"Attempt to add graph with unknown user %s" %
                          user)
        else:
            script_file = open(filename, "wb")
            # file is closed in write_script_file
            self.write_script_file(
                script_file, filename, shell, code, uid, gid)
            if graph_id in self._data:
                del self._data[graph_id]
        self.registry.store.add_graph(graph_id, filename, user)
    def run_script(self,
                   shell,
                   code,
                   user=None,
                   time_limit=None,
                   attachments=None,
                   server_supplied_env=None):
        """
        Run a script based on a shell and the code.

        A file will be written with #!<shell> as the first line, as executable,
        and run as the given user.

        XXX: Handle the 'reboot' and 'killall landscape-client' commands
        gracefully.

        @param shell: The interpreter to use.
        @param code: The code to run.
        @param user: The username to run the process as.
        @param time_limit: The number of seconds to allow the process to run
            before killing it and failing the returned Deferred with a
            L{ProcessTimeLimitReachedError}.
        @param attachments: C{dict} of filename/data attached to the script.

        @return: A deferred that will fire with the data printed by the process
            or fail with a L{ProcessTimeLimitReachedError}.
        """
        if not os.path.exists(shell.split()[0]):
            return fail(UnknownInterpreterError(shell))

        uid, gid, path = get_user_info(user)

        fd, filename = tempfile.mkstemp()
        script_file = os.fdopen(fd, "wb")
        self.write_script_file(script_file, filename, shell, code, uid, gid)

        env = {"PATH": UBUNTU_PATH, "USER": user or "", "HOME": path or ""}
        if server_supplied_env:
            env.update(server_supplied_env)
        old_umask = os.umask(0o022)

        if attachments:
            persist = Persist(filename=os.path.join(
                self.registry.config.data_path, "broker.bpickle"))
            persist = persist.root_at("registration")
            computer_id = persist.get("secure-id")
            d = self._save_attachments(attachments, uid, gid, computer_id, env)
        else:
            d = succeed(None)

        def prepare_script(attachment_dir):

            return self._run_script(filename, uid, gid, path, env, time_limit)

        d.addCallback(prepare_script)
        return d.addBoth(self._cleanup, filename, env, old_umask)
    def test_script_is_owned_by_user(self, mock_fdopen, mock_mkstemp,
                                     mock_chmod, mock_chown):
        """
        This is a very white-box test. When a script is generated, it must be
        created such that data NEVER gets into it before the file has the
        correct permissions. Therefore os.chmod and os.chown must be called
        before data is written.
        """
        username = pwd.getpwuid(os.getuid())[0]
        uid, gid, home = get_user_info(username)

        called_mocks = []

        mock_chown.side_effect = lambda *_: called_mocks.append(mock_chown)
        mock_chmod.side_effect = lambda *_: called_mocks.append(mock_chmod)

        def mock_mkstemp_side_effect(*_):
            called_mocks.append(mock_mkstemp)
            return (99, "tempo!")

        mock_mkstemp.side_effect = mock_mkstemp_side_effect

        script_file = mock.Mock()

        def mock_fdopen_side_effect(*_):
            called_mocks.append(mock_fdopen)
            return script_file

        mock_fdopen.side_effect = mock_fdopen_side_effect

        def spawnProcess(protocol, filename, args, env, path, uid, gid):
            self.assertIsNone(uid)
            self.assertIsNone(gid)
            self.assertEqual(get_default_environment(), env)
            protocol.result_deferred.callback(None)

        process_factory = mock.Mock()
        process_factory.spawnProcess = spawnProcess
        self.plugin.process_factory = process_factory

        result = self.plugin.run_script("/bin/sh",
                                        "code",
                                        user=pwd.getpwuid(uid)[0])

        def check(_):
            mock_fdopen.assert_called_with(99, "wb")
            mock_chmod.assert_called_with("tempo!", 0o700)
            mock_chown.assert_called_with("tempo!", uid, gid)
            script_file.write.assert_called_with(b"#!/bin/sh\ncode")
            script_file.close.assert_called_with()
            self.assertEqual(
                [mock_mkstemp, mock_fdopen, mock_chmod, mock_chown],
                called_mocks)

        return result.addCallback(check)
示例#6
0
def get_default_environment():
    username = pwd.getpwuid(os.getuid())[0]
    uid, gid, home = get_user_info(username)
    env = {
        "PATH": UBUNTU_PATH,
        "USER": username,
        "HOME": home,
    }
    for var in {"LANG", "LC_ALL", "LC_CTYPE"}:
        if var in os.environ:
            env[var] = os.environ[var]
    return env
def get_default_environment():
    username = pwd.getpwuid(os.getuid())[0]
    uid, gid, home = get_user_info(username)
    return {"PATH": UBUNTU_PATH, "USER": username, "HOME": home}