D-Bus, quick recap

d-bus-quick-recap

Sven Vermeulen Sun 29 June 2014

I've never fully investigated the what and how of D-Bus. I know it is some sort of IPC, but higher level than the POSIX IPC methods. After some reading, I think I start to understand how it works and how administrators can work with it. So a quick write-down is in place so I don't forget in the future.

There is one system bus and, for each X session of a user, also a session bus.

A bus is governed by a dbus-daemon process. A bus itself has objects on it, which are represented through path-like constructs (like /org/freedesktop/ConsoleKit). These objects are provided by a service (application). Applications "own" such services, and identify these through a namespace-like value (such as org.freedesktop.ConsoleKit).
Applications can send signals to the bus, or messages through methods exposed by the service. If methods are invoked (i.e. messages send) then the application must specify the interface (such as org.freedesktop.ConsoleKit.Manager.Stop).

Administrators can monitor the bus through dbus-monitor, or send messages through dbus-send. For instance, the following command invokes the org.freedesktop.ConsoleKit.Manager.Stop method provided by the object at /org/freedesktop/ConsoleKit owned by the service/application at org.freedesktop.ConsoleKit:

~$ dbus-send --system --print-reply 
  --dest=org.freedesktop.ConsoleKit 
  /org/freedesktop/ConsoleKit/Manager 
  org.freedesktop.ConsoleKit.Manager.Stop

What I found most interesting however was to query the busses. You can do this with dbus-send although it is much easier to use tools such as d-feet or qdbus.

To list current services on the system bus:

~# qdbus --system
:1.1
 org.freedesktop.ConsoleKit
:1.10
:1.2
:1.3
 org.freedesktop.PolicyKit1
:1.36
 fi.epitest.hostap.WPASupplicant
 fi.w1.wpa_supplicant1
:1.4
:1.42
:1.5
:1.6
:1.7
 org.freedesktop.UPower
:1.8
:1.9
org.freedesktop.DBus

The numbers are generated by D-Bus itself, the namespace-like strings are taken by the objects. To see what is provided by a particular service:

~# qdbus --system org.freedesktop.PolicyKit1
/
/org
/org/freedesktop
/org/freedesktop/PolicyKit1
/org/freedesktop/PolicyKit1/Authority

The methods made available through one of these:

~# qdbus --system org.freedesktop.PolicyKit1 /org/freedesktop/PolicyKit1/Authority
method QDBusVariant org.freedesktop.DBus.Properties.Get(QString interface_name, QString property_name)
method QVariantMap org.freedesktop.DBus.Properties.GetAll(QString interface_name)
...
property read uint org.freedesktop.PolicyKit1.Authority.BackendFeatures
property read QString org.freedesktop.PolicyKit1.Authority.BackendName
property read QString org.freedesktop.PolicyKit1.Authority.BackendVersion
method void org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse(QString cookie, QDBusRawType::(sa{sv} identity)
method void org.freedesktop.PolicyKit1.Authority.CancelCheckAuthorization(QString cancellation_id)
signal void org.freedesktop.PolicyKit1.Authority.Changed()
...

Access to methods and interfaces is governed through XML files in /etc/dbus-1/system.d (or session.d depending on the bus). Let's look at /etc/dbus-1/system.d/dnsmasq.conf as an example:

<busconfig>
        <policy user="root">
                <allow own="uk.org.thekelleys.dnsmasq"/>
                <allow send_destination="uk.org.thekelleys.dnsmasq"/>
        </policy>
        <policy user="dnsmasq">
                <allow own="uk.org.thekelleys.dnsmasq"/>
                <allow send_destination="uk.org.thekelleys.dnsmasq"/>
        </policy>
        <policy context="default">
                <deny own="uk.org.thekelleys.dnsmasq"/>
                <deny send_destination="uk.org.thekelleys.dnsmasq"/>
        </policy>
</busconfig>

The configuration mentions that only the root Linux user can 'assign' a service/application to the uk.org.thekelleys.dnsmasq name, and root can send messages to this same service/application name. The default is that no-one can own and send to this service/application name. As a result, only the Linux root user can interact with this object.

D-Bus also supports starting of services when a method is invoked (instead of running this service immediately). This is configured through *.service files inside /usr/share/dbus-1/system-services/.