<commit_before>/*
 * DBus Driver
 */

#include <c-dvar.h>
#include <c-dvar-type.h>
#include <c-macro.h>
#include <c-string.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include "activation.h"
#include "bus.h"
#include "dbus/address.h"
#include "dbus/message.h"
#include "dbus/protocol.h"
#include "dbus/socket.h"
#include "driver.h"
#include "match.h"
#include "peer.h"
#include "util/error.h"

typedef struct DriverMethod DriverMethod;
typedef int (*DriverMethodFn) (Peer *peer, CDVar *var_in, uint32_t serial, CDVar *var_out);

struct DriverMethod {
        const char *name;
        const char *path;
        DriverMethodFn fn;
        const CDVarType *in;
        const CDVarType *out;
};

/*
 * This macro defines a c-dvar type for DBus Messages. It evaluates to:
 *
 *         ((yyyyuua(yv))X)
 *
 * ..where 'X' is provided via @_body. That is, it evaluates to the combination
 * of DBus Header and DBus Body for a given body-type.
 */
#define DRIVER_T_MESSAGE(_body) \
        C_DVAR_T_TUPLE2(                                \
                C_DVAR_T_TUPLE7(                        \
                        C_DVAR_T_y,                     \
                        C_DVAR_T_y,                     \
                        C_DVAR_T_y,                     \
                        C_DVAR_T_y,                     \
                        C_DVAR_T_u,                     \
                        C_DVAR_T_u,                     \
                        C_DVAR_T_ARRAY(                 \
                                C_DVAR_T_TUPLE2(        \
                                        C_DVAR_T_y,     \
                                        C_DVAR_T_v      \
                                )                       \
                        )                               \
                ),                                      \
                _body                                   \
        )

static const CDVarType driver_type_in_s[] = {
        C_DVAR_T_INIT(
                C_DVAR_T_TUPLE1(
                        C_DVAR_T_s
                )
        )
};
static const CDVarType driver_type_in_su[] = {
        C_DVAR_T_INIT(
                C_DVAR_T_TUPLE2(
                        C_DVAR_T_s,
                        C_DVAR_T_u
                )
        )
};
static const CDVarType driver_type_in_apss[] = {
        C_DVAR_T_INIT(
                C_DVAR_T_TUPLE1(
                        C_DVAR_T_ARRAY(
                                C_DVAR_T_PAIR(
                                        C_DVAR_T_s,
                                        C_DVAR_T_s
                                )
                        )
                )
        )
};
static const CDVarType driver_type_in_asu[] = {
        C_DVAR_T_INIT(
                C_DVAR_T_TUPLE2(
                        C_DVAR_T_ARRAY(
                                C_DVAR_T_s
                        ),
                        C_DVAR_T_u
                )
        )
};
static const CDVarType driver_type_out_unit[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE0
                )
        )
};
static const CDVarType driver_type_out_s[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_s
                        )
                )
        )
};
static const CDVarType driver_type_out_b[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_b
                        )
                )
        )
};
static const CDVarType driver_type_out_u[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_u
                        )
                )
        )
};
static const CDVarType driver_type_out_as[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_ARRAY(
                                        C_DVAR_T_s
                                )
                        )
                )
        )
};
static const CDVarType driver_type_out_ay[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_ARRAY(
                                        C_DVAR_T_y
                                )
                        )
                )
        )
};
static const CDVarType driver_type_out_apsv[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_ARRAY(
                                        C_DVAR_T_PAIR(
                                                C_DVAR_T_s,
                                                C_DVAR_T_v
                                        )
                                )
                        )
                )
        )
};

static void driver_write_bytes(CDVar *var, char *bytes, size_t n_bytes) {
        c_dvar_write(var, "[");
        for (size_t i = 0; i < n_bytes; ++i)
                c_dvar_write(var, "y", bytes[i]);
        c_dvar_write(var, "]");
}

static void driver_dvar_write_unique_name(CDVar *var, Peer *peer) {
        c_dvar_write(var, "s", address_to_string(&(Address)ADDRESS_INIT_ID(peer->id)));
}

static void driver_dvar_write_signature_out(CDVar *var, const CDVarType *type) {
        char signature[C_DVAR_TYPE_LENGTH_MAX + 1];

        assert(type->length < sizeof(signature) + strlen("((yyyyuua(yv))())"));
        assert(type[0].element == '(');
        assert(type[1].element == '(');
        assert(type[2].element == 'y');
        assert(type[3].element == 'y');
        assert(type[4].element == 'y');
        assert(type[5].element == 'y');
        assert(type[6].element == 'u');
        assert(type[7].element == 'u');
        assert(type[8].element == 'a');
        assert(type[9].element == '(');
        assert(type[10].element == 'y');
        assert(type[11].element == 'v');
        assert(type[12].element == ')');
        assert(type[13].element == ')');
        assert(type[14].element == '(');
        assert(type[type->length - 2].element == ')');
        assert(type[type->length - 1].element == ')');

        for (unsigned int i = strlen("((yyyyuua(yv))("), j = 0; i < type->length - strlen("))"); i++, j++)
                signature[j] = type[i].element;

        signature[type->length - strlen("((yyyyuua(yv))())")] = '\0';

        c_dvar_write(var, "g", signature);
}

static int driver_dvar_verify_signature_in(const CDVarType *type, const char *signature) {
        if (type->length != strlen(signature) + 2)
                return DRIVER_E_UNEXPECTED_SIGNATURE;

        assert(type[0].element == '(');
        assert(type[type->length - 1].element == ')');

        for (unsigned int i = 1; i + 1 < type->length; i++)
                if (signature[i - 1] != type[i].element)
                        return DRIVER_E_UNEXPECTED_SIGNATURE;

        return 0;
}

static void driver_write_reply_header(CDVar *var, Peer *peer, uint32_t serial, const CDVarType *type) {
        c_dvar_write(var, "(yyyyuu[(y<u>)(y<s>)(y<",
                     c_dvar_is_big_endian(var) ? 'B' : 'l', DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_HEADER_FLAG_NO_REPLY_EXPECTED, 1, 0, (uint32_t)-1,
                     DBUS_MESSAGE_FIELD_REPLY_SERIAL, c_dvar_type_u, serial,
                     DBUS_MESSAGE_FIELD_SENDER, c_dvar_type_s, "org.freedesktop.DBus",
                     DBUS_MESSAGE_FIELD_DESTINATION, c_dvar_type_s);
        driver_dvar_write_unique_name(var, peer);
        c_dvar_write(var, ">)(y<",
                     DBUS_MESSAGE_FIELD_SIGNATURE, c_dvar_type_g);
        driver_dvar_write_signature_out(var, type);
        c_dvar_write(var, ">)])");
}

static void driver_write_signal_header(CDVar *var, Peer *peer, const char *member, const char *signature) {
        c_dvar_write(var, "(yyyyuu[(y<s>)",
                     c_dvar_is_big_endian(var) ? 'B' : 'l', DBUS_MESSAGE_TYPE_SIGNAL, DBUS_HEADER_FLAG_NO_REPLY_EXPECTED, 1, 0, (uint32_t)-1,
                     DBUS_MESSAGE_FIELD_SENDER, c_dvar_type_s, "org.freedesktop.DBus");

        if (peer) {
                c_dvar_write(var, "(y<", DBUS_MESSAGE_FIELD_DESTINATION, c_dvar_type_s);
                driver_dvar_write_unique_name(var, peer);
                c_dvar_write(var, ">)");
        }

        c_dvar_write(var, "(y<o>)(y<s>)(y<s>)(y<g>)])",
                     DBUS_MESSAGE_FIELD_PATH, c_dvar_type_o, "/org/freedesktop/DBus",
                     DBUS_MESSAGE_FIELD_INTERFACE, c_dvar_type_s, "org.freedesktop.DBus",
                     DBUS_MESSAGE_FIELD_MEMBER, c_dvar_type_s, member,
                     DBUS_MESSAGE_FIELD_SIGNATURE, c_dvar_type_g, signature);
}

static const char *driver_error_to_string(int r) {
        static const char *error_strings[_DRIVER_E_MAX] = {
                [DRIVER_E_INVALID_MESSAGE]                      = "Invalid message body",
                [DRIVER_E_PEER_NOT_REGISTERED]                  = "Hello() was not the first method called",
                [DRIVER_E_PEER_ALREADY_REGISTERED]              = "Hello() already called",
                [DRIVER_E_PEER_IS_MONITOR]                      = "Monitors cannot send messages",
                [DRIVER_E_PEER_NOT_PRIVILEGED]                  = "The caller does not have the necessary privileged to call this method",
                [DRIVER_E_UNEXPECTED_MESSAGE_TYPE]              = "Unexpected message type",
                [DRIVER_E_UNEXPECTED_PATH]                      = "Invalid object path",
                [DRIVER_E_UNEXPECTED_INTERFACE]                 = "Invalid interface",
                [DRIVER_E_UNEXPECTED_METHOD]                    = "Invalid method call",
                [DRIVER_E_UNEXPECTED_SIGNATURE]                 = "Invalid signature for method",
                [DRIVER_E_UNEXPECTED_REPLY]                     = "No pending reply with that serial",
                [DRIVER_E_QUOTA]                                = "Sending user's quota exceeded",
                [DRIVER_E_UNEXPECTED_FLAGS]                     = "Invalid flags",
                [DRIVER_E_UNEXPECTED_ENVIRONMENT_UPDATE]        = "User is not authorized to update environment variables",
                [DRIVER_E_SEND_DENIED]                          = "Sender is not authorized to send message",
                [DRIVER_E_RECEIVE_DENIED]                       = "Receiver is not authorized to receive message",
                [DRIVER_E_EXPECTED_REPLY_EXISTS]                = "Pending reply with that serial already exists",
                [DRIVER_E_NAME_RESERVED]                        = "org.freedesktop.DBus is a reserved name",
                [DRIVER_E_NAME_UNIQUE]                          = "The name is a unique name",
                [DRIVER_E_NAME_INVALID]                         = "The name is not a valid well-known name",
                [DRIVER_E_NAME_REFUSED]                         = "Request to own name refused by policy",
                [DRIVER_E_NAME_NOT_FOUND]                       = "The name does not exist",
                [DRIVER_E_NAME_NOT_ACTIVATABLE]                 = "The name is not activatable",
                [DRIVER_E_NAME_OWNER_NOT_FOUND]                 = "The name does not have an owner",
                [DRIVER_E_PEER_NOT_FOUND]                       = "The connection does not exist",
                [DRIVER_E_DESTINATION_NOT_FOUND]                = "Destination does not exist",
                [DRIVER_E_MATCH_INVALID]                        = "Invalid match rule",
                [DRIVER_E_MATCH_NOT_FOUND]                      = "The match does not exist",
                [DRIVER_E_ADT_NOT_SUPPORTED]                    = "Solaris ADT is not supported",
                [DRIVER_E_SELINUX_NOT_SUPPORTED]                = "SELinux is not supported",
        };
        assert(r >= 0 && r < _DRIVER_E_MAX && error_strings[r]);

        return error_strings[r];
}

static int driver_send_unicast(Peer *receiver, MatchFilter *filter, Message *message) {
        int r;

        /* XXX: handle quota */
        r = connection_queue(&receiver->connection, NULL, 0, message);
        if (r)
                return error_fold(r);

        /* for eavesdropping */
        r = peer_broadcast(NULL, NULL, NULL, ADDRESS_ID_INVALID, receiver, receiver->bus, filter, message);
        if (r)
                return error_fold(r);

        return 0;
}

static int driver_send_error(Peer *receiver, uint32_t serial, const char *error, const char *error_message) {
        MatchFilter filter = {
                .type = DBUS_MESSAGE_TYPE_ERROR,
                .destination = receiver->id,
                .args[0] = error_message,
                .argpaths[0] = error_message,
        };
        static const CDVarType type[] = {
                C_DVAR_T_INIT(
                        DRIVER_T_MESSAGE(
                                C_DVAR_T_TUPLE1(
                                        C_DVAR_T_s
                                )
                        )
                )
        };
        _c_cleanup_(c_dvar_deinitp) CDVar var = C_DVAR_INIT;
        _c_cleanup_(message_unrefp) Message *message = NULL;
        void *data;
        size_t n_data;
        int r;

        c_dvar_begin_write(&var, type, 1);
        c_dvar_write(&var, "((yyyyuu[(y<u>)(y<s>)(y<s>)(y<g>)(y<",
                     c_dvar_is_big_endian(&var) ? 'B' : 'l', DBUS_MESSAGE_TYPE_ERROR, DBUS_HEADER_FLAG_NO_REPLY_EXPECTED, 1, 0, (uint32_t)-1,
                     DBUS_MESSAGE_FIELD_REPLY_SERIAL, c_dvar_type_u, serial,
                     DBUS_MESSAGE_FIELD_SENDER, c_dvar_type_s, "org.freedesktop.DBus",
                     DBUS_MESSAGE_FIELD_ERROR_NAME, c_dvar_type_s, error,
                     DBUS_MESSAGE_FIELD_SIGNATURE, c_dvar_type_g, "s",
                     DBUS_MESSAGE_FIELD_DESTINATION, c_dvar_type_s);
        driver_dvar_write_unique_name(&var, receiver);
        c_dvar_write(&var, ">)])(s))", error_message);

        r = c_dvar_end_write(&var, &data, &n_data);
        if (r)
                return error_origin(r);

        r = message_new_outgoing(&message, data, n_data);
        if (r)
                return error_fold(r);

        r = driver_send_unicast(receiver, &filter, message);
        if (r)
                return error_trace(r);

        return 0;
}

static int driver_send_reply(Peer *peer, CDVar *var, const char *arg0) {
        MatchFilter filter = {
                .type = DBUS_MESSAGE_TYPE_METHOD_RETURN,
                .destination = peer->id,
                .args[0] = arg0,
                .argpaths[0] = arg0,
        };
        _c_cleanup_(message_unrefp) Message *message = NULL;
        void *data;
        size_t n_data;
        int r;

        /*
         * The message was correctly handled and the reply is serialized in
         * @var. Lets finish it up and queue the reply on the destination.
         * Note that any failure in doing so must be a fatal error, so there is
         * no point in reverting the operation on failure.
         */

        c_dvar_write(var, ")");

        r = c_dvar_end_write(var, &data, &n_data);
        if (r)
                return error_origin(r);

        r = message_new_outgoing(&message, data, n_data);
        if (r)
                return error_fold(r);

        r = driver_send_unicast(peer, &filter, message);
        if (r)
                return error_trace(r);

        return 0;
}

static int driver_notify_name_acquired(Peer *peer, const char *name) {
        MatchFilter filter = {
                .type = DBUS_MESSAGE_TYPE_SIGNAL,
                .destination = peer->id,
                .interface = "org.freedesktop.DBus",
                .member = "NameAcquired",
                .path = "/org/freedesktop/DBus",
                .args[0] = name,
                .argpaths[0] = name,
        };
        static const CDVarType type[] = {
                C_DVAR_T_INIT(
                        DRIVER_T_MESSAGE(
                                C_DVAR_T_TUPLE1(
                                        C_DVAR_T_s
                                )
                        )
                )
        };
        _c_cleanup_(c_dvar_deinitp) CDVar var = C_DVAR_INIT;
        _c_cleanup_(message_unrefp) Message *message = NULL;
        void *data;
        size_t n_data;
        int r;

        c_dvar_begin_write(&var, type, 1);
        c_dvar_write(&var, "(");
        driver_write_signal_header(&var, peer, "NameAcquired", "s");
        c_dvar_write(&var, "(s)", name);
        c_dvar_write(&var, ")");
        r = c_dvar_end_write(&var, &data, &n_data);
        if (r)
                return error_origin(r);

        r = message_new_outgoing(&message, data, n_data);
        if (r)
                return error_fold(r);

        r = driver_send_unicast(peer, &filter, message);
        if (r)
                return error_trace(r);

        return 0;
}

static int driver_notify_name_lost(Peer *peer, const char *name) {
        MatchFilter filter = {
                .type = DBUS_MESSAGE_TYPE_SIGNAL,
                .destination = peer->id,
                .interface = "org.freedesktop.DBus",
                .member = "NameLost",
                .path = "/org/freedesktop/DBus",
                .args[0] = name,
                .argpaths[0] = name,
        };
        static const CDVarType type[] = {
                C_DVAR_T_INIT(
                        DRIVER_T_MESSAGE(
                                C_DVAR_T_TUPLE1(
                                        C_DVAR_T_s
                                )
                        )
                )
        };
        _c_cleanup_(c_dvar_deinitp) CDVar var = C_DVAR_INIT;
        _c_cleanup_(message_unrefp) Message *message = NULL;
        void *data;
        size_t n_data;
        int r;

        c_dvar_begin_write(&var, type, 1);
        c_dvar_write(&var, "(");
        driver_write_signal_header(&var, peer, "NameLost", "s");
        c_dvar_write(&var, "(s)", name);
        c_dvar_write(&var, ")");
        r = c_dvar_end_write(&var, &data, &n_data);
        if (r)
                return error_origin(r);

        r = message_new_outgoing(&message, data, n_data);
        if (r)
                return error_fold(r);

        r = driver_send_unicast(peer, &filter, message);
        if (r)
                return error_trace(r);

        return 0;
}

static int driver_notify_name_owner_changed(Bus *bus, const char *name, const char *old_owner, const char *new_owner) {
        MatchFilter filter = {
                .type = DBUS_MESSAGE_TYPE_SIGNAL,
                .destination = ADDRESS_ID_INVALID,
                .interface = "org.freedesktop.DBus",
                .member = "NameOwnerChanged",
                .path = "/org/freedesktop/DBus",
                .args[0] = name,
                .argpaths[0] = name,
                .args[1] = old_owner,
                .argpaths[1] = old_owner,
                .args[2] = new_owner,
                .argpaths[2] = new_owner,
        };
        static const CDVarType type[] = {
                C_DVAR_T_INIT(
                        DRIVER_T_MESSAGE(
                                C_DVAR_T_TUPLE3(
                                        C_DVAR_T_s,
                                        C_DVAR_T_s,
                                        C_DVAR_T_s
                                )
                        )
                )
        };
        _c_cleanup_(c_dvar_deinitp) CDVar var = C_DVAR_INIT;
        _c_cleanup_(message_unrefp) Message *message = NULL;
        void *data;
        size_t n_data;
        int r;

        c_dvar_begin_write(&var, type, 1);
        c_dvar_write(&var, "(");
        driver_write_signal_header(&var, NULL, "NameOwnerChanged", "sss");
        c_dvar_write(&var, "(sss)", name, old_owner, new_owner);
        c_dvar_write(&var, ")");
        r = c_dvar_end_write(&var, &data, &n_data);
        if (r)
                return error_origin(r);

        r = message_new_outgoing(&message, data, n_data);
        if (r)
                return error_fold(r);

        r = peer_broadcast(NULL, NULL, NULL, ADDRESS_ID_INVALID, NULL, bus, &filter, message);
        if (r)
                return error_fold(r);

        return 0;
}

static int driver_name_owner_changed(Bus *bus, const char *name, Peer *old_owner, Peer *new_owner) {
        const char *old_owner_str, *new_owner_str;
        int r;

        assert(old_owner || new_owner);
        assert(name || !old_owner || !new_owner);

        old_owner_str = old_owner ? address_to_string(&(Address)ADDRESS_INIT_ID(old_owner->id)) : "";
        new_owner_str = new_owner ? address_to_string(&(Address)ADDRESS_INIT_ID(new_owner->id)) : "";
        name = name ?: (old_owner ? old_owner_str : new_owner_str);

        if (old_owner) {
                r = driver_notify_name_lost(old_owner, name);
                if (r)
                        return error_trace(r);
        }

        r = driver_notify_name_owner_changed(bus, name, old_owner_str, new_owner_str);
        if (r)
                return error_trace(r);

        if (new_owner) {
                r = driver_notify_name_acquired(new_owner, name);
                if (r)
                        return error_trace(r);
        }

        return 0;
}

static int driver_name_activated(Activation *activation, Peer *receiver) {
        ActivationRequest *request, *request_safe;
        ActivationMessage *message, *message_safe;
        int r;

        if (!activation)
                return 0;

        /* in case the name is dropped again in the future, we should request it again */
        activation->requested = false;

        c_list_for_each_entry_safe(request, request_safe, &activation->activation_requests, link) {
                Peer *sender;

                sender = peer_registry_find_peer(&receiver->bus->peers, request->sender_id);
                if (sender) {
                        _c_cleanup_(c_dvar_deinitp) CDVar var = C_DVAR_INIT;

                        c_dvar_begin_write(&var, driver_type_out_u, 1);
                        c_dvar_write(&var, "(");
                        driver_write_reply_header(&var, sender, request->serial, driver_type_out_u);
                        c_dvar_write(&var, "(u)", DBUS_START_REPLY_SUCCESS);

                        r = driver_send_reply(sender, &var, NULL);
                        if (r)
                                return error_trace(r);
                }

                activation_request_free(request);
        }

        c_list_for_each_entry_safe(message, message_safe, &activation->activation_messages, link) {
                Peer *sender;

                /* XXX: use sender's policy and names as captured at send */
                sender = peer_registry_find_peer(&receiver->bus->peers, message->message->sender_id);
                if (sender) {
                        NameSet sender_names = NAME_SET_INIT_FROM_OWNER(&sender->owned_names);

                        r = peer_queue_call(&sender->policy, &sender_names, &sender->matches, &sender->owned_replies, sender->user, sender->id, receiver, message->message);
                        if (r) {
                                switch (r) {
                                case PEER_E_QUOTA:
                                        r = driver_send_error(sender, message_read_serial(message->message),
                                                              "org.freedesktop.DBus.Error.LimitsExceeded",
                                                              driver_error_to_string(DRIVER_E_QUOTA));
                                        break;
                                case PEER_E_EXPECTED_REPLY_EXISTS:
                                        r = driver_send_error(sender, message_read_serial(message->message),
                                                              "org.freedesktop.DBus.Error.AccessDenied",
                                                              driver_error_to_string(DRIVER_E_EXPECTED_REPLY_EXISTS));
                                        break;
                                case PEER_E_RECEIVE_DENIED:
                                        r = driver_send_error(sender, message_read_serial(message->message),
                                                              "org.freedesktop.DBus.Error.AccessDenied",
                                                              driver_error_to_string(DRIVER_E_RECEIVE_DENIED));
                                        break;
                                case PEER_E_SEND_DENIED:
                                        r = driver_send_error(sender, message_read_serial(message->message),
                                                              "org.freedesktop.DBus.Error.AccessDenied",
                                                              driver_error_to_string(DRIVER_E_SEND_DENIED));
                                        break;
                                }

                                if (r)
                                        return error_fold(r);
                        }
                }

                activation_message_free(message);
        }<commit_msg>driver/activation: forward activation messages using state of sender at send time<commit_after>/*
 * DBus Driver
 */

#include <c-dvar.h>
#include <c-dvar-type.h>
#include <c-macro.h>
#include <c-string.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include "activation.h"
#include "bus.h"
#include "dbus/address.h"
#include "dbus/message.h"
#include "dbus/protocol.h"
#include "dbus/socket.h"
#include "driver.h"
#include "match.h"
#include "peer.h"
#include "util/error.h"

typedef struct DriverMethod DriverMethod;
typedef int (*DriverMethodFn) (Peer *peer, CDVar *var_in, uint32_t serial, CDVar *var_out);

struct DriverMethod {
        const char *name;
        const char *path;
        DriverMethodFn fn;
        const CDVarType *in;
        const CDVarType *out;
};

/*
 * This macro defines a c-dvar type for DBus Messages. It evaluates to:
 *
 *         ((yyyyuua(yv))X)
 *
 * ..where 'X' is provided via @_body. That is, it evaluates to the combination
 * of DBus Header and DBus Body for a given body-type.
 */
#define DRIVER_T_MESSAGE(_body) \
        C_DVAR_T_TUPLE2(                                \
                C_DVAR_T_TUPLE7(                        \
                        C_DVAR_T_y,                     \
                        C_DVAR_T_y,                     \
                        C_DVAR_T_y,                     \
                        C_DVAR_T_y,                     \
                        C_DVAR_T_u,                     \
                        C_DVAR_T_u,                     \
                        C_DVAR_T_ARRAY(                 \
                                C_DVAR_T_TUPLE2(        \
                                        C_DVAR_T_y,     \
                                        C_DVAR_T_v      \
                                )                       \
                        )                               \
                ),                                      \
                _body                                   \
        )

static const CDVarType driver_type_in_s[] = {
        C_DVAR_T_INIT(
                C_DVAR_T_TUPLE1(
                        C_DVAR_T_s
                )
        )
};
static const CDVarType driver_type_in_su[] = {
        C_DVAR_T_INIT(
                C_DVAR_T_TUPLE2(
                        C_DVAR_T_s,
                        C_DVAR_T_u
                )
        )
};
static const CDVarType driver_type_in_apss[] = {
        C_DVAR_T_INIT(
                C_DVAR_T_TUPLE1(
                        C_DVAR_T_ARRAY(
                                C_DVAR_T_PAIR(
                                        C_DVAR_T_s,
                                        C_DVAR_T_s
                                )
                        )
                )
        )
};
static const CDVarType driver_type_in_asu[] = {
        C_DVAR_T_INIT(
                C_DVAR_T_TUPLE2(
                        C_DVAR_T_ARRAY(
                                C_DVAR_T_s
                        ),
                        C_DVAR_T_u
                )
        )
};
static const CDVarType driver_type_out_unit[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE0
                )
        )
};
static const CDVarType driver_type_out_s[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_s
                        )
                )
        )
};
static const CDVarType driver_type_out_b[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_b
                        )
                )
        )
};
static const CDVarType driver_type_out_u[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_u
                        )
                )
        )
};
static const CDVarType driver_type_out_as[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_ARRAY(
                                        C_DVAR_T_s
                                )
                        )
                )
        )
};
static const CDVarType driver_type_out_ay[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_ARRAY(
                                        C_DVAR_T_y
                                )
                        )
                )
        )
};
static const CDVarType driver_type_out_apsv[] = {
        C_DVAR_T_INIT(
                DRIVER_T_MESSAGE(
                        C_DVAR_T_TUPLE1(
                                C_DVAR_T_ARRAY(
                                        C_DVAR_T_PAIR(
                                                C_DVAR_T_s,
                                                C_DVAR_T_v
                                        )
                                )
                        )
                )
        )
};

static void driver_write_bytes(CDVar *var, char *bytes, size_t n_bytes) {
        c_dvar_write(var, "[");
        for (size_t i = 0; i < n_bytes; ++i)
                c_dvar_write(var, "y", bytes[i]);
        c_dvar_write(var, "]");
}

static void driver_dvar_write_unique_name(CDVar *var, Peer *peer) {
        c_dvar_write(var, "s", address_to_string(&(Address)ADDRESS_INIT_ID(peer->id)));
}

static void driver_dvar_write_signature_out(CDVar *var, const CDVarType *type) {
        char signature[C_DVAR_TYPE_LENGTH_MAX + 1];

        assert(type->length < sizeof(signature) + strlen("((yyyyuua(yv))())"));
        assert(type[0].element == '(');
        assert(type[1].element == '(');
        assert(type[2].element == 'y');
        assert(type[3].element == 'y');
        assert(type[4].element == 'y');
        assert(type[5].element == 'y');
        assert(type[6].element == 'u');
        assert(type[7].element == 'u');
        assert(type[8].element == 'a');
        assert(type[9].element == '(');
        assert(type[10].element == 'y');
        assert(type[11].element == 'v');
        assert(type[12].element == ')');
        assert(type[13].element == ')');
        assert(type[14].element == '(');
        assert(type[type->length - 2].element == ')');
        assert(type[type->length - 1].element == ')');

        for (unsigned int i = strlen("((yyyyuua(yv))("), j = 0; i < type->length - strlen("))"); i++, j++)
                signature[j] = type[i].element;

        signature[type->length - strlen("((yyyyuua(yv))())")] = '\0';

        c_dvar_write(var, "g", signature);
}

static int driver_dvar_verify_signature_in(const CDVarType *type, const char *signature) {
        if (type->length != strlen(signature) + 2)
                return DRIVER_E_UNEXPECTED_SIGNATURE;

        assert(type[0].element == '(');
        assert(type[type->length - 1].element == ')');

        for (unsigned int i = 1; i + 1 < type->length; i++)
                if (signature[i - 1] != type[i].element)
                        return DRIVER_E_UNEXPECTED_SIGNATURE;

        return 0;
}

static void driver_write_reply_header(CDVar *var, Peer *peer, uint32_t serial, const CDVarType *type) {
        c_dvar_write(var, "(yyyyuu[(y<u>)(y<s>)(y<",
                     c_dvar_is_big_endian(var) ? 'B' : 'l', DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_HEADER_FLAG_NO_REPLY_EXPECTED, 1, 0, (uint32_t)-1,
                     DBUS_MESSAGE_FIELD_REPLY_SERIAL, c_dvar_type_u, serial,
                     DBUS_MESSAGE_FIELD_SENDER, c_dvar_type_s, "org.freedesktop.DBus",
                     DBUS_MESSAGE_FIELD_DESTINATION, c_dvar_type_s);
        driver_dvar_write_unique_name(var, peer);
        c_dvar_write(var, ">)(y<",
                     DBUS_MESSAGE_FIELD_SIGNATURE, c_dvar_type_g);
        driver_dvar_write_signature_out(var, type);
        c_dvar_write(var, ">)])");
}

static void driver_write_signal_header(CDVar *var, Peer *peer, const char *member, const char *signature) {
        c_dvar_write(var, "(yyyyuu[(y<s>)",
                     c_dvar_is_big_endian(var) ? 'B' : 'l', DBUS_MESSAGE_TYPE_SIGNAL, DBUS_HEADER_FLAG_NO_REPLY_EXPECTED, 1, 0, (uint32_t)-1,
                     DBUS_MESSAGE_FIELD_SENDER, c_dvar_type_s, "org.freedesktop.DBus");

        if (peer) {
                c_dvar_write(var, "(y<", DBUS_MESSAGE_FIELD_DESTINATION, c_dvar_type_s);
                driver_dvar_write_unique_name(var, peer);
                c_dvar_write(var, ">)");
        }

        c_dvar_write(var, "(y<o>)(y<s>)(y<s>)(y<g>)])",
                     DBUS_MESSAGE_FIELD_PATH, c_dvar_type_o, "/org/freedesktop/DBus",
                     DBUS_MESSAGE_FIELD_INTERFACE, c_dvar_type_s, "org.freedesktop.DBus",
                     DBUS_MESSAGE_FIELD_MEMBER, c_dvar_type_s, member,
                     DBUS_MESSAGE_FIELD_SIGNATURE, c_dvar_type_g, signature);
}

static const char *driver_error_to_string(int r) {
        static const char *error_strings[_DRIVER_E_MAX] = {
                [DRIVER_E_INVALID_MESSAGE]                      = "Invalid message body",
                [DRIVER_E_PEER_NOT_REGISTERED]                  = "Hello() was not the first method called",
                [DRIVER_E_PEER_ALREADY_REGISTERED]              = "Hello() already called",
                [DRIVER_E_PEER_IS_MONITOR]                      = "Monitors cannot send messages",
                [DRIVER_E_PEER_NOT_PRIVILEGED]                  = "The caller does not have the necessary privileged to call this method",
                [DRIVER_E_UNEXPECTED_MESSAGE_TYPE]              = "Unexpected message type",
                [DRIVER_E_UNEXPECTED_PATH]                      = "Invalid object path",
                [DRIVER_E_UNEXPECTED_INTERFACE]                 = "Invalid interface",
                [DRIVER_E_UNEXPECTED_METHOD]                    = "Invalid method call",
                [DRIVER_E_UNEXPECTED_SIGNATURE]                 = "Invalid signature for method",
                [DRIVER_E_UNEXPECTED_REPLY]                     = "No pending reply with that serial",
                [DRIVER_E_QUOTA]                                = "Sending user's quota exceeded",
                [DRIVER_E_UNEXPECTED_FLAGS]                     = "Invalid flags",
                [DRIVER_E_UNEXPECTED_ENVIRONMENT_UPDATE]        = "User is not authorized to update environment variables",
                [DRIVER_E_SEND_DENIED]                          = "Sender is not authorized to send message",
                [DRIVER_E_RECEIVE_DENIED]                       = "Receiver is not authorized to receive message",
                [DRIVER_E_EXPECTED_REPLY_EXISTS]                = "Pending reply with that serial already exists",
                [DRIVER_E_NAME_RESERVED]                        = "org.freedesktop.DBus is a reserved name",
                [DRIVER_E_NAME_UNIQUE]                          = "The name is a unique name",
                [DRIVER_E_NAME_INVALID]                         = "The name is not a valid well-known name",
                [DRIVER_E_NAME_REFUSED]                         = "Request to own name refused by policy",
                [DRIVER_E_NAME_NOT_FOUND]                       = "The name does not exist",
                [DRIVER_E_NAME_NOT_ACTIVATABLE]                 = "The name is not activatable",
                [DRIVER_E_NAME_OWNER_NOT_FOUND]                 = "The name does not have an owner",
                [DRIVER_E_PEER_NOT_FOUND]                       = "The connection does not exist",
                [DRIVER_E_DESTINATION_NOT_FOUND]                = "Destination does not exist",
                [DRIVER_E_MATCH_INVALID]                        = "Invalid match rule",
                [DRIVER_E_MATCH_NOT_FOUND]                      = "The match does not exist",
                [DRIVER_E_ADT_NOT_SUPPORTED]                    = "Solaris ADT is not supported",
                [DRIVER_E_SELINUX_NOT_SUPPORTED]                = "SELinux is not supported",
        };
        assert(r >= 0 && r < _DRIVER_E_MAX && error_strings[r]);

        return error_strings[r];
}

static int driver_send_unicast(Peer *receiver, MatchFilter *filter, Message *message) {
        int r;

        /* XXX: handle quota */
        r = connection_queue(&receiver->connection, NULL, 0, message);
        if (r)
                return error_fold(r);

        /* for eavesdropping */
        r = peer_broadcast(NULL, NULL, NULL, ADDRESS_ID_INVALID, receiver, receiver->bus, filter, message);
        if (r)
                return error_fold(r);

        return 0;
}

static int driver_send_error(Peer *receiver, uint32_t serial, const char *error, const char *error_message) {
        MatchFilter filter = {
                .type = DBUS_MESSAGE_TYPE_ERROR,
                .destination = receiver->id,
                .args[0] = error_message,
                .argpaths[0] = error_message,
        };
        static const CDVarType type[] = {
                C_DVAR_T_INIT(
                        DRIVER_T_MESSAGE(
                                C_DVAR_T_TUPLE1(
                                        C_DVAR_T_s
                                )
                        )
                )
        };
        _c_cleanup_(c_dvar_deinitp) CDVar var = C_DVAR_INIT;
        _c_cleanup_(message_unrefp) Message *message = NULL;
        void *data;
        size_t n_data;
        int r;

        c_dvar_begin_write(&var, type, 1);
        c_dvar_write(&var, "((yyyyuu[(y<u>)(y<s>)(y<s>)(y<g>)(y<",
                     c_dvar_is_big_endian(&var) ? 'B' : 'l', DBUS_MESSAGE_TYPE_ERROR, DBUS_HEADER_FLAG_NO_REPLY_EXPECTED, 1, 0, (uint32_t)-1,
                     DBUS_MESSAGE_FIELD_REPLY_SERIAL, c_dvar_type_u, serial,
                     DBUS_MESSAGE_FIELD_SENDER, c_dvar_type_s, "org.freedesktop.DBus",
                     DBUS_MESSAGE_FIELD_ERROR_NAME, c_dvar_type_s, error,
                     DBUS_MESSAGE_FIELD_SIGNATURE, c_dvar_type_g, "s",
                     DBUS_MESSAGE_FIELD_DESTINATION, c_dvar_type_s);
        driver_dvar_write_unique_name(&var, receiver);
        c_dvar_write(&var, ">)])(s))", error_message);

        r = c_dvar_end_write(&var, &data, &n_data);
        if (r)
                return error_origin(r);

        r = message_new_outgoing(&message, data, n_data);
        if (r)
                return error_fold(r);

        r = driver_send_unicast(receiver, &filter, message);
        if (r)
                return error_trace(r);

        return 0;
}

static int driver_send_reply(Peer *peer, CDVar *var, const char *arg0) {
        MatchFilter filter = {
                .type = DBUS_MESSAGE_TYPE_METHOD_RETURN,
                .destination = peer->id,
                .args[0] = arg0,
                .argpaths[0] = arg0,
        };
        _c_cleanup_(message_unrefp) Message *message = NULL;
        void *data;
        size_t n_data;
        int r;

        /*
         * The message was correctly handled and the reply is serialized in
         * @var. Lets finish it up and queue the reply on the destination.
         * Note that any failure in doing so must be a fatal error, so there is
         * no point in reverting the operation on failure.
         */

        c_dvar_write(var, ")");

        r = c_dvar_end_write(var, &data, &n_data);
        if (r)
                return error_origin(r);

        r = message_new_outgoing(&message, data, n_data);
        if (r)
                return error_fold(r);

        r = driver_send_unicast(peer, &filter, message);
        if (r)
                return error_trace(r);

        return 0;
}

static int driver_notify_name_acquired(Peer *peer, const char *name) {
        MatchFilter filter = {
                .type = DBUS_MESSAGE_TYPE_SIGNAL,
                .destination = peer->id,
                .interface = "org.freedesktop.DBus",
                .member = "NameAcquired",
                .path = "/org/freedesktop/DBus",
                .args[0] = name,
                .argpaths[0] = name,
        };
        static const CDVarType type[] = {
                C_DVAR_T_INIT(
                        DRIVER_T_MESSAGE(
                                C_DVAR_T_TUPLE1(
                                        C_DVAR_T_s
                                )
                        )
                )
        };
        _c_cleanup_(c_dvar_deinitp) CDVar var = C_DVAR_INIT;
        _c_cleanup_(message_unrefp) Message *message = NULL;
        void *data;
        size_t n_data;
        int r;

        c_dvar_begin_write(&var, type, 1);
        c_dvar_write(&var, "(");
        driver_write_signal_header(&var, peer, "NameAcquired", "s");
        c_dvar_write(&var, "(s)", name);
        c_dvar_write(&var, ")");
        r = c_dvar_end_write(&var, &data, &n_data);
        if (r)
                return error_origin(r);

        r = message_new_outgoing(&message, data, n_data);
        if (r)
                return error_fold(r);

        r = driver_send_unicast(peer, &filter, message);
        if (r)
                return error_trace(r);

        return 0;
}

static int driver_notify_name_lost(Peer *peer, const char *name) {
        MatchFilter filter = {
                .type = DBUS_MESSAGE_TYPE_SIGNAL,
                .destination = peer->id,
                .interface = "org.freedesktop.DBus",
                .member = "NameLost",
                .path = "/org/freedesktop/DBus",
                .args[0] = name,
                .argpaths[0] = name,
        };
        static const CDVarType type[] = {
                C_DVAR_T_INIT(
                        DRIVER_T_MESSAGE(
                                C_DVAR_T_TUPLE1(
                                        C_DVAR_T_s
                                )
                        )
                )
        };
        _c_cleanup_(c_dvar_deinitp) CDVar var = C_DVAR_INIT;
        _c_cleanup_(message_unrefp) Message *message = NULL;
        void *data;
        size_t n_data;
        int r;

        c_dvar_begin_write(&var, type, 1);
        c_dvar_write(&var, "(");
        driver_write_signal_header(&var, peer, "NameLost", "s");
        c_dvar_write(&var, "(s)", name);
        c_dvar_write(&var, ")");
        r = c_dvar_end_write(&var, &data, &n_data);
        if (r)
                return error_origin(r);

        r = message_new_outgoing(&message, data, n_data);
        if (r)
                return error_fold(r);

        r = driver_send_unicast(peer, &filter, message);
        if (r)
                return error_trace(r);

        return 0;
}

static int driver_notify_name_owner_changed(Bus *bus, const char *name, const char *old_owner, const char *new_owner) {
        MatchFilter filter = {
                .type = DBUS_MESSAGE_TYPE_SIGNAL,
                .destination = ADDRESS_ID_INVALID,
                .interface = "org.freedesktop.DBus",
                .member = "NameOwnerChanged",
                .path = "/org/freedesktop/DBus",
                .args[0] = name,
                .argpaths[0] = name,
                .args[1] = old_owner,
                .argpaths[1] = old_owner,
                .args[2] = new_owner,
                .argpaths[2] = new_owner,
        };
        static const CDVarType type[] = {
                C_DVAR_T_INIT(
                        DRIVER_T_MESSAGE(
                                C_DVAR_T_TUPLE3(
                                        C_DVAR_T_s,
                                        C_DVAR_T_s,
                                        C_DVAR_T_s
                                )
                        )
                )
        };
        _c_cleanup_(c_dvar_deinitp) CDVar var = C_DVAR_INIT;
        _c_cleanup_(message_unrefp) Message *message = NULL;
        void *data;
        size_t n_data;
        int r;

        c_dvar_begin_write(&var, type, 1);
        c_dvar_write(&var, "(");
        driver_write_signal_header(&var, NULL, "NameOwnerChanged", "sss");
        c_dvar_write(&var, "(sss)", name, old_owner, new_owner);
        c_dvar_write(&var, ")");
        r = c_dvar_end_write(&var, &data, &n_data);
        if (r)
                return error_origin(r);

        r = message_new_outgoing(&message, data, n_data);
        if (r)
                return error_fold(r);

        r = peer_broadcast(NULL, NULL, NULL, ADDRESS_ID_INVALID, NULL, bus, &filter, message);
        if (r)
                return error_fold(r);

        return 0;
}

static int driver_name_owner_changed(Bus *bus, const char *name, Peer *old_owner, Peer *new_owner) {
        const char *old_owner_str, *new_owner_str;
        int r;

        assert(old_owner || new_owner);
        assert(name || !old_owner || !new_owner);

        old_owner_str = old_owner ? address_to_string(&(Address)ADDRESS_INIT_ID(old_owner->id)) : "";
        new_owner_str = new_owner ? address_to_string(&(Address)ADDRESS_INIT_ID(new_owner->id)) : "";
        name = name ?: (old_owner ? old_owner_str : new_owner_str);

        if (old_owner) {
                r = driver_notify_name_lost(old_owner, name);
                if (r)
                        return error_trace(r);
        }

        r = driver_notify_name_owner_changed(bus, name, old_owner_str, new_owner_str);
        if (r)
                return error_trace(r);

        if (new_owner) {
                r = driver_notify_name_acquired(new_owner, name);
                if (r)
                        return error_trace(r);
        }

        return 0;
}

static int driver_name_activated(Activation *activation, Peer *receiver) {
        ActivationRequest *request, *request_safe;
        ActivationMessage *message, *message_safe;
        int r;

        if (!activation)
                return 0;

        /* in case the name is dropped again in the future, we should request it again */
        activation->requested = false;

        c_list_for_each_entry_safe(request, request_safe, &activation->activation_requests, link) {
                Peer *sender;

                sender = peer_registry_find_peer(&receiver->bus->peers, request->sender_id);
                if (sender) {
                        _c_cleanup_(c_dvar_deinitp) CDVar var = C_DVAR_INIT;

                        c_dvar_begin_write(&var, driver_type_out_u, 1);
                        c_dvar_write(&var, "(");
                        driver_write_reply_header(&var, sender, request->serial, driver_type_out_u);
                        c_dvar_write(&var, "(u)", DBUS_START_REPLY_SUCCESS);

                        r = driver_send_reply(sender, &var, NULL);
                        if (r)
                                return error_trace(r);
                }

                activation_request_free(request);
        }

        c_list_for_each_entry_safe(message, message_safe, &activation->activation_messages, link) {
                NameSet sender_names = NAME_SET_INIT_FROM_SNAPSHOT(message->senders_names);
                Peer *sender;

                sender = peer_registry_find_peer(&receiver->bus->peers, message->message->sender_id);

                /* XXX: deal with sender matches on the unique name */
                r = peer_queue_call(&message->senders_policy, &sender_names, NULL, sender ? &sender->owned_replies : NULL, message->user, message->message->sender_id, receiver, message->message);
                if (r) {
                        switch (r) {
                        case PEER_E_QUOTA:
                                if (sender)
                                        r = driver_send_error(sender, message_read_serial(message->message),
                                                              "org.freedesktop.DBus.Error.LimitsExceeded",
                                                              driver_error_to_string(DRIVER_E_QUOTA));
                                break;
                        case PEER_E_EXPECTED_REPLY_EXISTS:
                                if (sender)
                                        r = driver_send_error(sender, message_read_serial(message->message),
                                                              "org.freedesktop.DBus.Error.AccessDenied",
                                                              driver_error_to_string(DRIVER_E_EXPECTED_REPLY_EXISTS));
                                break;
                        case PEER_E_RECEIVE_DENIED:
                                if (sender)
                                        r = driver_send_error(sender, message_read_serial(message->message),
                                                              "org.freedesktop.DBus.Error.AccessDenied",
                                                              driver_error_to_string(DRIVER_E_RECEIVE_DENIED));
                                break;
                        case PEER_E_SEND_DENIED:
                                if (sender)
                                        r = driver_send_error(sender, message_read_serial(message->message),
                                                              "org.freedesktop.DBus.Error.AccessDenied",
                                                              driver_error_to_string(DRIVER_E_SEND_DENIED));
                                break;
                        }

                        if (r)
                                return error_fold(r);
                }

                activation_message_free(message);
        }
{'fraction_non_alphanumeric': 0.09321667322060559, 'fraction_numerical': 0.004089657884388517, 'mean_word_length': 1.3419901459685961, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 125, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 112, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1010468', 'n_tokens_mistral': 15540, 'n_tokens_neox': 14699, 'n_words': 2703}