DBus System Bus third party service configuration

Hello, I’m currently trying to package my own software which runs a system service (as root).
It doesn’t necessarly need to run as root but it’s kind of the default for all system services. At some point I should consider running it as a special system user with fewer privileges. It only needs to access specific data directory on the system and a single internet port.

The first configuration mechanism I used was environment variables set by the Nix Module and accessed by module options. This works but I would need to rebuild my config each time I want the config to change which is not flexible enough for my needs.

So I decided to do it with dbus. I implemented a dbus server with sdbusplus, here are the specifications.

The interface is very simple:

  • Only one object: /org/scotthamilton/rpifanserver
  • Only one interface: org.scotthamilton.RpiFanServe with only one property: CacheLifeExpectancy
  • Only one connection name (bus name): org.scotthamilton.RpiFanServe

Last and not least, every user of the rpi-fan-serve group should be able to write to CacheLifeExpectancy.

That’s it.

Here is my take on trying to make a system bus config that implements those requirements:

<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->

<!DOCTYPE busconfig PUBLIC
 "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
  <policy user="root">

    <!-- Only root can own the service -->
    <allow own="org.scotthamilton.RpiFanServe"/>

  </policy>
  <policy group="rpi-fan-serve">
    
    <!-- Dbus defaults -->
    <allow send_destination="org.scotthamilton.RpiFanServe"
           send_interface="org.scotthamilton.RpiFanServe"/>
    <allow send_destination="org.scotthamilton.RpiFanServe"
           send_interface="org.freedesktop.DBus.Introspectable"/>
    <allow send_destination="org.scotthamilton.RpiFanServe"
           send_interface="org.freedesktop.DBus.Peer"/>
    <allow send_destination="org.scotthamilton.RpiFanServe"
           send_interface="org.freedesktop.DBus.Properties"/>
    <allow send_destination="org.scotthamilton.RpiFanServe"
           send_interface="org.freedesktop.DBus.ObjectManager"/>

  </policy>
</busconfig>

I also added my package to services.dbus.packages and verified that I could find it in /etc/dbus-1/system.conf after rebuilding my config.

I took the assumption from reading the doc that this config would mean that every message coming from senders that belong to the rpi-fan-serve group would be allowed to call methods from the org.freedesktop.DBus.Properties interface on the org.scotthamilton.RpiFanServe destination bus.

And this works fine. My dbus server can acquire the bus name, I can send messages to it and they get received perfectly. But I can only set CacheLifeExpectancy with root.

Or in other words,
this works:

sudo busctl set-property org.scotthamilton.RpiFanServe /org/scotthamilton/rpifanserver org.scotthamilton.RpiFanServe CacheLifeExpectancy x 3600

but this doesn’t work (same but without sudo)

busctl set-property org.scotthamilton.RpiFanServe /org/scotthamilton/rpifanserver org.scotthamilton.RpiFanServe CacheLifeExpectancy x 3600

Output: Failed to set property CacheLifeExpectancy on interface org.scotthamilton.RpiFanServe: Access denied

I ran a bus monitor to figure out what was going on:

sudo busctl monitor org.scotthamilton.RpiFanServe

Output on error

Monitoring bus message stream.
‣ Type=method_call  Endian=l  Flags=0  Version=1 Cookie=2
  Sender=:1.87  Destination=org.scotthamilton.RpiFanServe  Path=/org/scotthamilton/rpifanserver  Interface=org.freedesktop.DBus.Properties  Member=Set
  UniqueName=:1.87
  MESSAGE "ssv" {
          STRING "org.scotthamilton.RpiFanServe";
          STRING "CacheLifeExpectancy";
          VARIANT "x" {
                  INT64 8080;
          };
  };

‣ Type=method_call  Endian=l  Flags=0  Version=1 Cookie=4
  Sender=:1.85  Destination=org.freedesktop.DBus  Path=/org/freedesktop/DBus  Interface=org.freedesktop.DBus  Member=GetConnectionUnixUser
  UniqueName=:1.85
  MESSAGE "s" {
          STRING ":1.87";
  };

‣ Type=method_return  Endian=l  Flags=1  Version=1 Cookie=5  ReplyCookie=4
  Sender=org.freedesktop.DBus  Destination=:1.85
  MESSAGE "u" {
          UINT32 1001;
  };

‣ Type=error  Endian=l  Flags=1  Version=1 Cookie=5  ReplyCookie=2
  Sender=:1.85  Destination=:1.87
  ErrorName=org.freedesktop.DBus.Error.AccessDenied  ErrorMessage="Access to org.scotthamilton.RpiFanServe.CacheLifeExpectancy() not permitted."
  UniqueName=:1.85
  MESSAGE "s" {
          STRING "Access to org.scotthamilton.RpiFanServe.CacheLifeExpectancy() not permitted.";
  };

So it seems like it’s not even the org.freedesktop.DBus.Properties.Set method call that was denied but the org.scotthamilton.RpiFanServe.CacheLifeExpectancy(). I don’t know what to do because I already allowed the rpi-fan-serve group to access to the org.scotthamilton.RpiFanServe interface.

For clarity, here is the output of id command to show that I’m indeed belonging to the rpi-fan-serve group.

uid=1001(scott) gid=100(users) groupes=100(users),1(wheel),57(networkmanager),131(docker),995(rpi-fan-serve)

Maybe I would have better chance to find a solution on a dbus dedicated forum but such a thing doesn’t exist and I don’t exclude the possiblity of this being Nix’s fault.