# oslo_privsep package

## Subpackages

- oslo_privsep.test package
  - Submodules
  - oslo_privsep.test.fixture module
    - `UnprivilegedPrivsepFixture`
      - `UnprivilegedPrivsepFixture.setUp()`
  - Module contents

## Submodules

## oslo_privsep.capabilities module

class oslo_privsep.capabilities.Capabilities(*values)

  Bases: `IntEnum`

  CAP_AUDIT_CONTROL = 30
  CAP_AUDIT_READ = 37
  CAP_AUDIT_WRITE = 29
  CAP_BLOCK_SUSPEND = 36
  CAP_BPF = 39
  CAP_CHECKPOINT_RESTORE = 40
  CAP_CHOWN = 0
  CAP_DAC_OVERRIDE = 1
  CAP_DAC_READ_SEARCH = 2
  CAP_FOWNER = 3
  CAP_FSETID = 4
  CAP_IPC_LOCK = 14
  CAP_IPC_OWNER = 15
  CAP_KILL = 5
  CAP_LEASE = 28
  CAP_LINUX_IMMUTABLE = 9
  CAP_MAC_ADMIN = 33
  CAP_MAC_OVERRIDE = 32
  CAP_MKNOD = 27
  CAP_NET_ADMIN = 12
  CAP_NET_BIND_SERVICE = 10
  CAP_NET_BROADCAST = 11
  CAP_NET_RAW = 13
  CAP_PERFMON = 38
  CAP_SETFCAP = 31
  CAP_SETGID = 6
  CAP_SETPCAP = 8
  CAP_SETUID = 7
  CAP_SYSLOG = 34
  CAP_SYS_ADMIN = 21
  CAP_SYS_BOOT = 22
  CAP_SYS_CHROOT = 18
  CAP_SYS_MODULE = 16
  CAP_SYS_NICE = 23
  CAP_SYS_PACCT = 20
  CAP_SYS_PTRACE = 19
  CAP_SYS_RAWIO = 17
  CAP_SYS_RESOURCE = 24
  CAP_SYS_TIME = 25
  CAP_SYS_TTY_CONFIG = 26
  CAP_WAKE_ALARM = 35

oslo_privsep.capabilities.drop_all_caps_except(effective: Iterable[int], permitted: Iterable[int], inheritable: Iterable[int]) → None

  Set (effective, permitted, inheritable) to provided list of caps

oslo_privsep.capabilities.get_caps() → tuple[list[int], list[int], list[int]]

  Return (effective, permitted, inheritable) as lists of caps

oslo_privsep.capabilities.set_keepcaps(enable: bool) → None

  Set/unset thread’s “keep capabilities” flag - see prctl(2)

## oslo_privsep.comm module

Serialization/Deserialization for privsep.

The wire format is a stream of msgpack objects encoding primitive python datatypes. Msgpack ‘raw’ is assumed to be a valid utf8 string (msgpack 2.0 ‘bin’ type is used for bytes). Python lists are converted to tuples during serialization/deserialization.

class oslo_privsep.comm.ClientChannel(sock: socket)

  Bases: `object`

  close() → None
  out_of_band(msg: Any) → None

    Received OOB message. Subclasses might want to override this.

  send_recv(msg: Any, timeout: float | None = None) → Any

class oslo_privsep.comm.Deserializer(readsock: socket)

  Bases: `object`

class oslo_privsep.comm.Future(lock: lock, timeout: float | None = None)

  Bases: `object`

  A very simple object to track the return of a function call

  result() → Any

    Must already be holding lock used in constructor

  set_exception(exc: BaseException) → None

    Must already be holding lock used in constructor

  set_result(data: Any) → None

    Must already be holding lock used in constructor

class oslo_privsep.comm.Message(*values)

  Bases: `IntEnum`

  Types of messages sent across the communication channel

  CALL = 3
  ERR = 5
  LOG = 6
  PING = 1
  PONG = 2
  RET = 4

exception oslo_privsep.comm.PrivsepTimeout

  Bases: `Exception`

class oslo_privsep.comm.Serializer(writesock: socket)

  Bases: `object`

  close() → None
  send(msg: Any) → None

class oslo_privsep.comm.ServerChannel(sock: socket)

  Bases: `object`

  Server-side twin to ClientChannel

  send(msg: Any) → None

## oslo_privsep.daemon module

Privilege separation (“privsep”) daemon.

To ease transition this supports 2 alternative methods of starting the daemon, all resulting in a helper process running with elevated privileges and open socket(s) to the original process:

1. Start via fork()

   Assumes process currently has all required privileges and is about to drop them (perhaps by setuid to an unprivileged user). If the the initial environment is secure and PrivContext.start(Method.FORK) is called early in main(), then this is the most secure and simplest. In particular, if the initial process is already running as non-root (but with sufficient capabilities, via eg suitable systemd service files), then no part needs to involve uid=0 or sudo.

2. Start via sudo/rootwrap

   This starts the privsep helper on first use via sudo and rootwrap, and communicates via a temporary Unix socket passed on the command line. The communication channel is briefly exposed in the filesystem, but is protected with file permissions and connecting to it only grants access to the unprivileged process. Requires a suitable entry in sudoers or rootwrap.conf filters.

The privsep daemon exits when the communication channel is closed, (which usually occurs when the unprivileged process exits).

class oslo_privsep.daemon.Daemon(channel: comm.ServerChannel, context: priv_context.PrivContext)

  Bases: `object`

  NB: This doesn’t fork() - do that yourself before calling run()

  loop() → None

    Main body of daemon request loop

  run() → None

    Run request loop. Sets up environment, then calls loop()

exception oslo_privsep.daemon.FailedToDropPrivileges

  Bases: `Exception`

class oslo_privsep.daemon.ForkingClientChannel(context: priv_context.PrivContext)

  Bases: `_ClientChannel`

class oslo_privsep.daemon.PrivsepLogHandler(channel: ServerChannel, processName: str | None = None)

  Bases: `Handler`

  emit(record: LogRecord) → None

    Do whatever it takes to actually log the specified logging record.

    This version is intended to be implemented by subclasses and so raises a NotImplementedError.

exception oslo_privsep.daemon.ProtocolError

  Bases: `Exception`

class oslo_privsep.daemon.RootwrapClientChannel(context: priv_context.PrivContext)

  Bases: `_ClientChannel`

class oslo_privsep.daemon.StdioFd(*values)

  Bases: `IntEnum`

  STDERR = 2
  STDIN = 0
  STDOUT = 1

oslo_privsep.daemon.fdopen(fd: int, *args: Any, **kwargs: Any) → Any

oslo_privsep.daemon.helper_main() → None

  Start privileged process, serving requests over a Unix socket.

oslo_privsep.daemon.replace_logging(handler: Handler, log_root: Logger | None = None) → None

oslo_privsep.daemon.set_cloexec(fd: int | socket) → None

oslo_privsep.daemon.setgid(group_id_or_name: str | int) → None

oslo_privsep.daemon.setuid(user_id_or_name: str | int) → None

oslo_privsep.daemon.un_monkey_patch() → None

## oslo_privsep.priv_context module

oslo_privsep.priv_context.CapNameOrInt(value: str | int) → int

class oslo_privsep.priv_context.Method(*values)

  Bases: `Enum`

  FORK = 1
  ROOTWRAP = 2

class oslo_privsep.priv_context.PrivContext(prefix: str, cfg_section: str = 'privsep', pypath: str | None = None, capabilities: Iterable[int] | None = None, logger_name: str = 'oslo_privsep.daemon', timeout: float | None = None)

  Bases: `object`

  property conf: Any

    Return the oslo.config section object as lazily as possible.

  entrypoint(func: Callable[[...], Any]) → partial[Any]

    This is intended to be used as a decorator.

  entrypoint_with_timeout(timeout: float) → Callable[[Callable[[...], Any]], Callable[[...], Any]]

    This is intended to be used as a decorator with timeout.

  helper_command(sockpath: str) → list[str]
  is_entrypoint(func: Callable[[...], Any]) → bool
  set_client_mode(enabled: bool) → None
  start(method: Method = Method.ROOTWRAP) → None
  stop() → None

oslo_privsep.priv_context.init(root_helper: list[str] | None = None) → None

  Initialise oslo.privsep library.

  This function should be called at the top of main(), after the command line is parsed, oslo.config is initialised and logging is set up, but before calling any privileged entrypoint, changing user id, forking, or anything else “odd”.

  Parameters:

    root_helper – List of command and arguments to prefix privsep-helper with, in order to run helper as root. Note, ignored if context’s helper_command config option is set.

## oslo_privsep.version module

## Module contents

this page last updated: 2026-03-26 20:22:05

Except where otherwise noted, this document is licensed under Creative Commons Attribution 3.0 License. See all OpenStack Legal Documents.

found an error? report a bug