libink — brokerless D-Bus for Finit =================================== libink is a small C library implementing the [D-Bus wire protocol][spec], both the server and the client side, without a broker and without any dependency on `libdbus`, `sd-bus`, or GIO. It was born inside Finit to let PID 1 be a bus of its own: clients connect straight to the listening socket, authenticate with the standard SASL EXTERNAL handshake, and get kernel-authenticated credentials via `SO_PEERCRED`. For what the bus exposes and how to talk to it, see the User Guide, [D-Bus Integration](../doc/dbus.md). This file covers the library itself. Status ------ libink is an internal implementation detail of Finit: built as a libtool convenience library, linked statically into `finit` and `initctl`, nothing installed. There is deliberately no ABI promise yet — that comes if/when libink is extracted into a project of its own. External D-Bus clients need none of this; the wire protocol is the compatibility surface, any standard D-Bus library works. Layout ------ | File | Contents | |-----------------|-------------------------------------------------------| | `server.c` | Listening socket, accept, peer credential capture | | `auth.c` | SASL EXTERNAL handshake, uid verification | | `connection.c` | Per-peer state machine, message framing | | `proto.c` | Wire header parse/build | | `marshal.c` | Body (de)marshalling: basic types, arrays, variants | | `dispatch.c` | Object tree, vtable registration, method dispatch | | `builtin.c` | `org.freedesktop.DBus.*` stock interfaces | | `match.c` | AddMatch/RemoveMatch rule parsing and signal filter | | `path.c` | systemd-style `_HH` object path encoding | | `client.c` | Outgoing connections, method calls, reply/signal wait | | `io.c` | Shared EINTR-resilient read/write loops | Public API symbols carry the `link_*` prefix (`link.h`), internal ones `__*` (`internal.h`). Method handlers are registered as vtables of `link_method_t`/`link_property_t`; the framework emits variant signatures from the property table so the declared type is the single source of truth. The boundary to Finit is deliberate: nothing under `libink/` includes a Finit header. All glue lives in `src/dbus.c` — object registration, signal emission from the service/condition/runlevel hook points, and the uev event loop bridge. `initctl` uses the client half of the same library, so one wire-format implementation serves both ends. If libink is ever spun out, that file is the cut line. Future work ----------- Privileged methods over the *system* bus are root-only. Finit learns the caller's uid from the broker with `GetConnectionUnixUser`, but that reply carries no group list, so it cannot honour `--with-group` membership there the way it does on the local bus (where the kernel hands over the group set via `SO_PEERGROUPS`). Closing the gap means asking the broker `GetConnectionCredentials` and reading its `UnixGroupIDs`, which is a variant holding an `au` array — the reader (`marshal.c`) only decodes single-character variant signatures today, so it needs extending first. Finit's own direct users reach it over the local bus, so this has not been pressing. Testing ------- The `test/dbus-*.sh` suite exercises the library end to end against a live Finit in a namespace, driven by `test/src/dbus-auth-client.c`. Wire-format conformance against third-party tools (`dbus-send`, `dbus-monitor`) and fuzzing of the parsers are tracked as pre-merge work — this is PID 1's attack surface. [spec]: https://dbus.freedesktop.org/doc/dbus-specification.html