Actions

FreedomBox’s web front does not directly change any aspect of the underlying operating system. Instead, it calls upon actions, as shell commands. Actions live in /usr/share/plinth/actions directory. They require no interaction beyond passing command line arguments or taking sensitive arguments via stdin. They change the operation of the services and apps of the FreedomBox and nothing else. These actions are also directly usable by a skilled administrator.

The following documentation for the actions module.

Run specified actions.

Actions run commands with this contract (version 1.1):

  1. (promise) Super-user actions run as root. Normal actions do not.

  2. (promise) The actions directory can’t be changed at run time.

    This guarantees that we can only select from the correct set of actions.

  3. (restriction) Only whitelisted actions can run.

    1. Scripts in a directory above the actions directory can’t be run.

      Arguments (and options) can’t coerce the system to run actions in directories above the actions directory.

      Arguments that fail this validation will raise a ValueError.

    2. Scripts in a directory beneath the actions directory can’t be run.

      Arguments (and options) can’t coerce the system to run actions in sub-directories of the actions directory.

      (An important side-effect of this is that the system will not try to

      follow symlinks to other action directories.)

      Arguments that fail this validation will raise a ValueError.

    3. Only one action can be called at a time.

      This prevents us from appending multiple (unexpected) actions to the call. Any special shell characters in the action name will simply be treated as the action itself when trying to search for an action. The action will then not be found.

      $ action=”echo ‘$options’; echo ‘oops’” $ options=”hi” $ $action # oops, the file system is gone!

      Arguments that fail this validation will raise a ValueError.

    4. Options can’t be used to run other actions:

      $ action=”echo ‘$options’” $ options=”hi’; rm -rf /;’” $ $action # oops, the file system is gone!

      Any option that tries to include special shell characters will simply be treated as an option with special characters and will not be interpreted by the shell.

      Any call wishing to include special shell characters in options list does not need to escape them. They are taken care of. The option string is passed to the action exactly as it is passed in.

    5. Actions must exist in the actions directory.

  4. (promise) Options are passed as arguments to the action.

    Options can be provided as a list or as a tuple.

  5. (promise) Output is returned from the command. In case of an error, ActionError is raised with action, output and error strings as arguments.

  6. (limitation) Providing the process with input is not possible.

    Don’t expect to give the process additional input after it’s started. Any interaction with the spawned process must be carried out through some other method (maybe the process opens a socket, or something).

  7. Option

plinth.actions.run(action, options=None, input=None, run_in_background=False)[source]

Safely run a specific action as the current user.

See actions._run for more information.

plinth.actions.superuser_run(action, options=None, input=None, run_in_background=False, log_error=True)[source]

Safely run a specific action as root.

See actions._run for more information.

plinth.actions.run_as_user(action, options=None, input=None, run_in_background=False, become_user=None)[source]

Run a command as a different user.

If become_user is None, run as current user.

plinth.actions._run(action, options=None, input=None, run_in_background=False, run_as_root=False, become_user=None, log_error=True)[source]

Safely run a specific action as a normal user or root.

Actions are pulled from the actions directory.

  • options are added to the action command.

  • input: data (as bytes) that will be sent to the action command’s stdin.

  • run_in_background: run asynchronously or wait for the command to complete.

  • run_as_root: execute the command through sudo.