+ struct kdbus_cmd_match __attribute__ ((__aligned__(8))) cmd;
+ DBusTransportSocket* transportS = (DBusTransportSocket*) transport;
+
+ cmd.cookie = id;
+ cmd.id = id;
+ cmd.size = sizeof(struct kdbus_cmd_match);
+
+ if(ioctl(transportS->fd, KDBUS_CMD_MATCH_REMOVE, &cmd))
+ {
+ _dbus_verbose("Failed removing match rule for id: %llu; error: %d, %m\n", (unsigned long long)id, errno);
+ return FALSE;
+ }
+ else
+ {
+ _dbus_verbose("Match rule removed correctly.\n");
+ return TRUE;
+ }
+}
+
+/**
+ * Handles messages sent to bus daemon - "org.freedesktop.DBus" and translates them to appropriate
+ * kdbus ioctl commands. Than translate kdbus reply into dbus message and put it into recived messages queue.
+ *
+ * !!! Not all methods are handled !!! Doubt if it is even possible.
+ * If method is not handled, returns error reply org.freedesktop.DBus.Error.UnknownMethod
+ *
+ * Handled methods:
+ * - GetNameOwner
+ * - NameHasOwner
+ * - ListNames
+ *
+ * Not handled methods:
+ * - ListActivatableNames
+ * - StartServiceByName
+ * - UpdateActivationEnvironment
+ * - GetConnectionUnixUser
+ * - GetId
+ */
+static int emulateOrgFreedesktopDBus(DBusTransport *transport, DBusMessage *message)
+{
+#ifdef DBUS_SERVICES_IN_LIB
+ int inter_ret;
+ struct nameInfo info;
+#endif
+ int ret_value = -1;
+
+ if(!strcmp(dbus_message_get_member(message), "Hello"))
+ {
+ char* sender = NULL;
+ char* name = NULL;
+
+ name = malloc(snprintf(name, 0, "%llu", ULLONG_MAX) + 1);
+ if(name == NULL)
+ return -1;
+ if(!bus_register_kdbus(name, (DBusTransportSocket*)transport))
+ goto outH1;
+ if(!register_kdbus_policy(name, ((DBusTransportSocket*)transport)->fd))
+ goto outH1;
+
+ sender = malloc (strlen(name) + 4);
+ if(!sender)
+ goto outH1;
+ sprintf(sender, ":1.%s", name);
+ ((DBusTransportSocket*)transport)->sender = sender;
+
+ if(!reply_1_data(message, DBUS_TYPE_STRING, &name, transport->connection))
+ return 0; //todo why we cannot free name after sending reply, shouldn't we?
+ else
+ free(sender);
+
+ outH1:
+ free(name);
+ }
+#ifdef DBUS_SERVICES_IN_LIB
+ else if(!strcmp(dbus_message_get_member(message), "RequestName"))
+ {
+ char* name;
+ int flags;
+ int result;
+
+ if(!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID))
+ return -1;
+
+ if(!register_kdbus_policy(name, ((DBusTransportSocket*)transport)->fd))
+ return -1;
+
+ result = request_kdbus_name(((DBusTransportSocket*)transport)->fd, name, flags, 0);
+ if(result == -EPERM)
+ return reply_with_error(DBUS_ERROR_ACCESS_DENIED,
+ "Connection is not allowed to own the service \"%s\" due to security policies in the configuration file",
+ name, message, transport->connection);
+ else if(result < 0)
+ return reply_with_error(DBUS_ERROR_FAILED , "Name \"%s\" could not be acquired", name, message, transport->connection);
+ else
+ return reply_1_data(message, DBUS_TYPE_UINT32, &result, transport->connection);
+ }
+ else if(!strcmp(dbus_message_get_member(message), "AddMatch"))
+ {
+ char* rule;
+
+ if(!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &rule, DBUS_TYPE_INVALID))
+ return -1;
+
+ if(!add_match_kdbus(transport, 0, rule))
+ return -1;
+
+ return reply_ack(message,transport->connection);
+ }
+ else if(!strcmp(dbus_message_get_member(message), "RemoveMatch"))
+ {
+ if(!remove_match_kdbus(transport, 0))
+ return -1;
+ return reply_ack(message, transport->connection);
+ }
+ else if(!strcmp(dbus_message_get_member(message), "GetNameOwner")) //returns id of the well known name
+ {
+ char* name = NULL;
+
+ dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
+ inter_ret = kdbus_NameQuery(name, transport, &info);
+ if(inter_ret == 0) //unique id of the name
+ {
+ char unique_name[(unsigned int)(snprintf(name, 0, "%llu", ULLONG_MAX) + sizeof(":1."))];
+ const char* pString = unique_name;
+
+ sprintf(unique_name, ":1.%llu", (unsigned long long int)info.uniqueId);
+ _dbus_verbose("Unique name discovered:%s\n", unique_name);
+ ret_value = reply_1_data(message, DBUS_TYPE_STRING, &pString, transport->connection);
+ }
+ else if(inter_ret == -ENOENT) //name has no owner
+ return reply_with_error(DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get owner of name '%s': no such name", name, message, transport->connection);
+ else
+ {
+ _dbus_verbose("kdbus error sending name query: err %d (%m)\n", errno);
+ ret_value = reply_with_error(DBUS_ERROR_FAILED, "Could not determine unique name for '%s'", name, message, transport->connection);
+ }
+ }
+ else if(!strcmp(dbus_message_get_member(message), "NameHasOwner")) //returns if name is currently registered on the bus
+ {
+ char* name = NULL;
+ dbus_bool_t result;
+
+ dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
+ inter_ret = kdbus_NameQuery(name, transport, &info);
+ if((inter_ret == 0) || (inter_ret == -ENOENT))
+ {
+ result = (inter_ret == 0) ? TRUE : FALSE;
+ ret_value = reply_1_data(message, DBUS_TYPE_BOOLEAN, &result, transport->connection);
+ }
+ else
+ {
+ _dbus_verbose("kdbus error checking if name exists: err %d (%m)\n", errno);
+ ret_value = reply_with_error(DBUS_ERROR_FAILED, "Could not determine whether name '%s' exists", name, message, transport->connection);
+ }
+ }
+ else if(!strcmp(dbus_message_get_member(message), "GetConnectionUnixUser"))
+ {
+ char* name = NULL;
+
+ dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
+ inter_ret = kdbus_NameQuery(name, transport, &info);
+ if(inter_ret == 0) //name found
+ {
+ _dbus_verbose("User id:%llu\n", (unsigned long long) info.userId);
+ ret_value = reply_1_data(message, DBUS_TYPE_UINT32, &info.userId, transport->connection);
+ }
+ else if(inter_ret == -ENOENT) //name has no owner
+ return reply_with_error(DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get UID of name '%s': no such name", name, message, transport->connection);
+ else
+ {
+ _dbus_verbose("kdbus error determining UID: err %d (%m)\n", errno);
+ ret_value = reply_with_error(DBUS_ERROR_FAILED, "Could not determine UID for '%s'", name, message, transport->connection);
+ }
+ }
+ else if(!strcmp(dbus_message_get_member(message), "GetConnectionUnixProcessID"))
+ {
+ char* name = NULL;
+
+ dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
+ inter_ret = kdbus_NameQuery(name, transport, &info);
+ if(inter_ret == 0) //name found
+ ret_value = reply_1_data(message, DBUS_TYPE_UINT32, &info.processId, transport->connection);
+ else if(inter_ret == -ENOENT) //name has no owner
+ return reply_with_error(DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get PID of name '%s': no such name", name, message, transport->connection);
+ else
+ {
+ _dbus_verbose("kdbus error determining PID: err %d (%m)\n", errno);
+ ret_value = reply_with_error(DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN,"Could not determine PID for '%s'", name, message, transport->connection);
+ }
+ }
+ else if(!strcmp(dbus_message_get_member(message), "ListNames")) //return all well known names on he bus
+ {
+ struct kdbus_cmd_names* pCmd;
+ uint64_t cmd_size;
+
+ cmd_size = sizeof(struct kdbus_cmd_names) + KDBUS_ITEM_SIZE(1);
+ pCmd = malloc(cmd_size);
+ if(pCmd == NULL)
+ goto out;
+ pCmd->size = cmd_size;
+
+ again:
+ cmd_size = 0;
+ if(ioctl(((DBusTransportSocket*)transport)->fd, KDBUS_CMD_NAME_LIST, pCmd))
+ {
+ if(errno == EINTR)
+ goto again;
+ if(errno == ENOBUFS) //buffer to small to put all names into it
+ cmd_size = pCmd->size; //here kernel tells how much memory it needs
+ else
+ {
+ _dbus_verbose("kdbus error asking for name list: err %d (%m)\n",errno);
+ goto out;
+ }
+ }
+ if(cmd_size) //kernel needs more memory
+ {
+ pCmd = realloc(pCmd, cmd_size); //prepare memory
+ if(pCmd == NULL)
+ return -1;
+ goto again; //and try again
+ }
+ else
+ {
+ DBusMessage *reply;
+ DBusMessageIter iter, sub;
+ struct kdbus_cmd_name* pCmd_name;
+ char* pName;
+
+ reply = dbus_message_new_method_return(message);
+ if(reply == NULL)
+ goto out;
+ dbus_message_set_sender(reply, DBUS_SERVICE_DBUS);
+ dbus_message_iter_init_append(reply, &iter);
+ if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING_AS_STRING, &sub))
+ {
+ dbus_message_unref(reply);
+ goto out;
+ }
+ for (pCmd_name = pCmd->names; (uint8_t *)(pCmd_name) < (uint8_t *)(pCmd) + pCmd->size; pCmd_name = KDBUS_PART_NEXT(pCmd_name))
+ {
+ pName = pCmd_name->name;
+ if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &pName))
+ {
+ dbus_message_unref(reply);
+ goto out;
+ }
+ }
+
+ if (!dbus_message_iter_close_container (&iter, &sub))
+ {
+ dbus_message_unref (reply);
+ goto out;
+ }
+
+ if(add_message_to_received(reply, transport->connection))
+ ret_value = 0;
+ }
+out:
+ if(pCmd)
+ free(pCmd);
+ return ret_value;
+ }
+ else if(!strcmp(dbus_message_get_member(message), "GetId"))
+ {
+ char* path;
+ char uuid[DBUS_UUID_LENGTH_BYTES];
+ struct stat stats;
+ MD5_CTX md5;
+ DBusString binary, encoded;
+
+ path = &transport->address[11]; //start of kdbus bus path
+ if(stat(path, &stats) < -1)
+ {
+ _dbus_verbose("kdbus error reading stats of bus: err %d (%m)\n", errno);
+ return reply_with_error(DBUS_ERROR_FAILED, "Could not determine bus '%s' uuid", path, message, transport->connection);
+ }
+
+ MD5_Init(&md5);
+ MD5_Update(&md5, path, strlen(path));
+ MD5_Update(&md5, &stats.st_ctim.tv_sec, sizeof(stats.st_ctim.tv_sec));
+ MD5_Final(uuid, &md5);
+
+ if(!_dbus_string_init (&encoded))
+ goto outgid;
+ _dbus_string_init_const_len (&binary, uuid, DBUS_UUID_LENGTH_BYTES);
+ if(!_dbus_string_hex_encode (&binary, 0, &encoded, _dbus_string_get_length (&encoded)))
+ goto outb;
+ path = (char*)_dbus_string_get_const_data (&encoded);
+ ret_value = reply_1_data(message, DBUS_TYPE_STRING, &path, transport->connection);
+
+ outb:
+ _dbus_string_free(&binary);
+ _dbus_string_free(&encoded);
+ outgid:
+ return ret_value;
+ }
+#endif
+/* else if(!strcmp(dbus_message_get_member(message), "GetAdtAuditSessionData")) //todo to be implemented if needed and possible
+ {
+ char* name = NULL;
+
+ dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
+ return reply_with_error(DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN, "Could not determine audit session data for '%s'", name, message, transport->connection);
+ }*/
+#ifdef DBUS_SERVICES_IN_LIB
+ else if(!strcmp(dbus_message_get_member(message), "GetConnectionSELinuxSecurityContext"))
+ {
+ char* name = NULL;
+
+ dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID);
+ inter_ret = kdbus_NameQuery(name, transport, &info);
+ if(inter_ret == -ENOENT) //name has no owner
+ return reply_with_error(DBUS_ERROR_NAME_HAS_NO_OWNER, "Could not get security context of name '%s': no such name", name, message, transport->connection);
+ else if(inter_ret < 0)
+ return reply_with_error(DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN, "Could not determine security context for '%s'", name, message, transport->connection);
+ else
+ {
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(message);
+ if(reply != NULL)
+ {
+ dbus_message_set_sender(reply, DBUS_SERVICE_DBUS);
+ if (!dbus_message_append_args (reply, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &info.sec_label, info.sec_label_len, DBUS_TYPE_INVALID))
+ dbus_message_unref(reply);
+ else if(add_message_to_received(reply, transport->connection))
+ ret_value = 0;
+ }
+ }
+ }
+#endif
+ else
+ return 1; //send to daemon
+
+#ifdef DBUS_SERVICES_IN_LIB
+ if(info.sec_label)
+ free(info.sec_label);
+#endif
+ return ret_value;
+}
+
+#if KDBUS_MSG_DECODE_DEBUG == 1
+static char *msg_id(uint64_t id, char *buf)
+{
+ if (id == 0)
+ return "KERNEL";