#include <dlog/dlog.h>
#include <linux/kdbus.h>
-#include <errno.h>
+#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
-#include <stdbool.h>
#include <cassert>
+#include <cstddef>
+#include <memory>
#define CONNECTION_LABEL "libdbuspolicy1-kdbus"
#define ALIGN8(l) (((l) + 7) & ~7)
#define ALIGNDN8(l) ((l) & ~7)
-#define UID_INVALID ((uid_t) -1)
-#define GID_INVALID ((gid_t) -1)
#define MAX_DBUS_NAME_LEN 255
T *get() { return reinterpret_cast<T*>(buffer); }
};
-int kdbus_free_by_offset(kdbus_connection *conn, __u64 offset);
-
-static int kdbus_open_bus(kdbus_connection *conn, const char *path)
+int KdbusConnection::open_bus(const char *path)
{
- conn->fd = open(path, O_RDWR|O_NOCTTY|O_LARGEFILE|O_CLOEXEC);
- return conn->fd;
+ fd = open(path, O_RDWR|O_NOCTTY|O_LARGEFILE|O_CLOEXEC);
+ return fd;
}
static void set_item_str(kdbus_item *item, const char *str, __u64 str_length, __u64 type)
memcpy(item->str, str, str_length);
}
-static int kdbus_hello(kdbus_connection *conn,
- uint64_t hello_flags,
- uint64_t attach_flags_send,
- uint64_t attach_flags_recv)
+int KdbusConnection::hello(uint64_t hello_flags,
+ uint64_t attach_flags_send,
+ uint64_t attach_flags_recv)
{
kdbus_command<kdbus_cmd_hello, KDBUS_ITEM_SIZE_ALIGN(sizeof(CONNECTION_LABEL))> command(hello_flags);
auto cmd = command.get();
set_item_str(cmd->items, CONNECTION_LABEL, sizeof(CONNECTION_LABEL), KDBUS_ITEM_CONN_DESCRIPTION);
- if (ioctl(conn->fd, KDBUS_CMD_HELLO, cmd) < 0)
+ if (ioctl(fd, KDBUS_CMD_HELLO, cmd) < 0)
return -errno;
- kdbus_free_by_offset(conn, cmd->offset);
+ free_by_offset(cmd->offset);
- conn->pool = static_cast<char *>(mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, conn->fd, 0));
- if (MAP_FAILED == conn->pool)
+ pool = static_cast<decltype(pool)>(mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0));
+ if (MAP_FAILED == pool)
return -errno;
return 0;
}
-void kdbus_shared_init_fd(kdbus_connection *conn, int fd)
-{
- conn->fd = fd;
-}
-
-void kdbus_shared_init_pool(kdbus_connection *conn, void *pool)
-{
- conn->pool = static_cast<char*>(pool);
-}
-
-int kdbus_connect(kdbus_connection *conn,
- const char *path,
- uint64_t hello_flags,
- uint64_t attach_flags_send,
- uint64_t attach_flags_recv)
+int KdbusConnection::connect(const char *path,
+ uint64_t hello_flags,
+ uint64_t attach_flags_send,
+ uint64_t attach_flags_recv)
{
- if ((conn->fd = kdbus_open_bus(conn, path)) < 0) {
+ if (open_bus(path) < 0) {
LOGE("Error opening bus: %s", path);
return -1;
}
- if (kdbus_hello(conn, hello_flags, attach_flags_send, attach_flags_recv) < 0) {
+ if (hello(hello_flags, attach_flags_send, attach_flags_recv) < 0) {
LOGE("Error: bus hello failed");
- close(conn->fd);
+ close(fd);
return -1;
}
return 0;
}
-static bool kdbus_is_unique_id(const char* name)
+constexpr bool kdbus_is_unique_id(const char* name)
{
return ':' == name[0];
}
return res;
}
-int kdbus_get_conn_info(kdbus_connection *conn,
- const char *destination,
- kdbus_cmd_param *info,
- conn_info_type conn_info_type)
+int KdbusConnection::get_conn_info(const char *bus_name,
+ conn_info_type conn_info_type,
+ KdbusConnectionInfo *info)
{
kdbus_command<kdbus_cmd_info, KDBUS_ITEM_SIZE_ALIGN(ALIGN8(MAX_DBUS_NAME_LEN+1))> command(0, 0);
auto cmd = command.get();
- char const *label = NULL;
- uid_t uid_n = UID_INVALID;
- gid_t gid_n = GID_INVALID;
-
- cmd->flags = 0;
if (conn_info_type == POLICY_CONN_INFO_ALL)
cmd->attach_flags = (KDBUS_ATTACH_CREDS | KDBUS_ATTACH_NAMES | KDBUS_ATTACH_SECLABEL);
else
cmd->attach_flags = KDBUS_ATTACH_NAMES;
- if (kdbus_is_unique_id(destination)) {
- cmd->id = kdbus_unique_id(destination);
+ if (kdbus_is_unique_id(bus_name)) {
+ cmd->id = kdbus_unique_id(bus_name);
} else {
- auto l = strlen(destination);
- cmd->size += KDBUS_ITEM_SIZE_ALIGN(ALIGN8(l+1));
+ auto l = strlen(bus_name);
+ cmd->size += KDBUS_ITEM_SIZE_ALIGN(l+1);
cmd->id = 0;
- set_item_str(cmd->items, destination, l+1, KDBUS_ITEM_NAME);
+
+ set_item_str(cmd->items, bus_name, l+1, KDBUS_ITEM_NAME);
}
- if (ioctl(conn->fd, KDBUS_CMD_CONN_INFO, cmd) < 0) {
+ if (ioctl(fd, KDBUS_CMD_CONN_INFO, cmd) < 0) {
if (errno == ENXIO || errno == ESRCH)
return DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE;
return DBUSPOLICY_RESULT_KDBUS_ERROR;
}
- info->free_offset = cmd->offset;
+ info->setNewData(cmd->offset);
- auto conn_info = reinterpret_cast<kdbus_info *>((uint8_t *) conn->pool + cmd->offset);
+ auto conn_info = reinterpret_cast<kdbus_info *>(pool + cmd->offset);
uintptr_t items_end = (uintptr_t)conn_info + (size_t)conn_info->size;
- info->names_num = 0;
for (auto item = conn_info->items;
(uintptr_t)item < items_end;
item = reinterpret_cast<decltype(item)>(ALIGN8((uintptr_t)item + (size_t)item->size))) {
switch (item->type) {
case KDBUS_ITEM_CREDS:
- uid_n = item->creds.euid;
- gid_n = item->creds.egid;
+ info->setCreds(item->creds.euid, item->creds.egid);
break;
case KDBUS_ITEM_SECLABEL:
- label = item->str;
+ info->setLabel(item->str);
break;
case KDBUS_ITEM_OWNED_NAME:
- info->k_names[info->names_num++] = item->name.name;
+ info->addName(item->name.name);
break;
}
}
- info->label = label;
- info->uid_n = uid_n;
- info->gid_n = gid_n;
-
return 0;
}
-int kdbus_free_by_offset(kdbus_connection *conn, __u64 offset)
+int KdbusConnection::free_by_offset(uint64_t offset)
{
kdbus_command<kdbus_cmd_free> command;
auto cmd = command.get();
cmd->offset = offset;
- if (ioctl(conn->fd, KDBUS_CMD_FREE, cmd) != 0) {
+ if (ioctl(fd, KDBUS_CMD_FREE, cmd) != 0) {
LOGE("failed KDBUS_CMD_FREE");
return errno;
}
return 0;
}
+
+void KdbusConnectionInfo::release_info()
+{
+ if (set) {
+ my_connection.free_by_offset(free_offset);
+ set = false;
+ }
+}
+
+void KdbusConnectionInfo::setNewData(uint64_t offset)
+{
+ release_info();
+
+ free_offset = offset;
+ set = true;
+
+ names_num = 0;
+ _label = nullptr;
+ uid_n = UID_INVALID;
+ gid_n = GID_INVALID;
+}
#define KDBUS_CONN_MAX_NAMES 256
-#ifdef __cplusplus
-extern "C" {
-#endif
+class KdbusConnectionInfo;
-struct kdbus_connection {
+class KdbusConnection {
int fd;
- char *pool;
-};
+ uint8_t *pool;
-typedef struct kdbus_connection kdbus_connection;
+ int open_bus(const char *path);
+ int hello(uint64_t hello_flags,
+ uint64_t attach_flags_send,
+ uint64_t attach_flags_recv);
+public:
+ typedef enum { POLICY_CONN_INFO_ALL, POLICY_CONN_INFO_NAME } conn_info_type;
-struct kdbus_cmd_param {
- char const *label;
- const char* k_names[KDBUS_CONN_MAX_NAMES];
- __u64 free_offset;
- uid_t uid_n;
- gid_t gid_n;
- uint16_t names_num;
+ void shared_init_fd(int fd_to_set) { fd = fd_to_set; }
+ void shared_init_pool(void *pool_to_set) { pool = static_cast<decltype(pool)>(pool_to_set); }
+ int connect(const char *path,
+ uint64_t hello_flags,
+ uint64_t attach_flags_send,
+ uint64_t attach_flags_recv);
+ int get_conn_info(const char *bus_name,
+ conn_info_type conn_info_type,
+ KdbusConnectionInfo *info);
+ int free_by_offset(uint64_t offset);
};
-void kdbus_shared_init_fd(kdbus_connection *conn, int fd);
-void kdbus_shared_init_pool(kdbus_connection *conn, void *pool);
+class KdbusConnectionInfo {
+ static const uid_t UID_INVALID = -1;
+ static const gid_t GID_INVALID = -1;
+
+ char const *_label{nullptr};
+ const char *k_names[KDBUS_CONN_MAX_NAMES]{};
+ uint64_t free_offset{0};
+ uid_t uid_n{UID_INVALID};
+ gid_t gid_n{GID_INVALID};
+ uint16_t names_num{0};
+ bool set{false};
+
+ KdbusConnection &my_connection;
-int kdbus_connect(kdbus_connection *conn,
- const char *path,
- uint64_t hello_flags,
- uint64_t attach_flags_send,
- uint64_t attach_flags_recv);
+public:
+ KdbusConnectionInfo(KdbusConnection &c) : my_connection{c} {}
+ ~KdbusConnectionInfo() { release_info(); }
-typedef enum { POLICY_CONN_INFO_ALL, POLICY_CONN_INFO_NAME } conn_info_type;
+ void release_info();
+ void setNewData(uint64_t offset);
-int kdbus_get_conn_info(kdbus_connection *conn,
- const char *destination,
- struct kdbus_cmd_param *info,
- conn_info_type conn_info_type);
+ void addName(const char *name) { k_names[names_num++] = name; }
-int kdbus_free_by_offset(kdbus_connection *conn, __u64 offset);
+ void setCreds(uid_t uid, gid_t gid) { uid_n = uid; gid_n = gid; }
-#ifdef __cplusplus
-} /* extern "C" */
-#endif
+ void setLabel(const char *label) { _label = label; }
+
+ int get(const char *destination, KdbusConnection::conn_info_type conn_info_type) {
+ return my_connection.get_conn_info(destination, conn_info_type, this);
+ }
+ const char **names() { return k_names; }
+ uint16_t numberOfNames() const { return names_num; }
+ uid_t uid() const { return uid_n; }
+ gid_t gid() const { return gid_n; }
+ const char *label() const { return _label; }
+};
#define KDBUS_SYSTEM_BUS_PATH KDBUS_PATH_PREFIX"0-system/bus"
struct kconn {
- kdbus_connection conn;
+ KdbusConnection conn;
BusType bus_type;
} g_conn[2];
struct kconn *kconn = &g_conn[bus_type];
kconn->bus_type = bus_type;
- if (kdbus_connect(&kconn->conn, resolved_path.get(), 0, _KDBUS_ATTACH_ALL, 0) < 0) {
+ if (kconn->conn.connect(resolved_path.get(), 0, _KDBUS_ATTACH_ALL, 0) < 0) {
assert(false && "failed kdbus_connect");
}
}
static kconn *init_shared_fd(BusType bus_type, int fd)
{
- kconn *result = static_cast<kconn*>(malloc(sizeof(*result)));
- if (NULL == result) {
+ kconn *result = new kconn;
+ if (nullptr == result) {
LOGE("Error: failed to allocate memory for policy configuration");
- return NULL;
+ return nullptr;
}
- kdbus_shared_init_fd(&result->conn, fd);
+ result->conn.shared_init_fd(fd);
result->bus_type = bus_type;
return result;
}
return nullptr;
}
- struct kconn *result = NULL;
+ struct kconn *result = nullptr;
if (can_open(bus_type, bus_owner)) {
if (-1 == fd) {
result = get_global_conn(bus_type, resolved_path);
return dbuspolicy1_init_shared(bus_path, -1);
}
+inline kconn *KCONN(void *config) { return static_cast<kconn *>(config); }
+inline KdbusConnection &KDBUS_CONN(void *config) { return KCONN(config)->conn; }
+
DBUSPOLICY1_EXPORT void dbuspolicy1_init_set_pool(void *configuration, void *pool)
{
- kdbus_shared_init_pool(static_cast<kdbus_connection *>(configuration), pool);
+ KDBUS_CONN(configuration).shared_init_pool(pool);
}
DBUSPOLICY1_EXPORT void dbuspolicy1_free(void* configuration)
if (configuration == &g_conn[i])
return;
- free(configuration);
+ delete KCONN(configuration);
}
DBUSPOLICY1_EXPORT int dbuspolicy1_check_out(void* configuration,
const char *interface,
const char *member,
int message_type,
- const char *error_name,
- int reply_serial,
- int requested_reply)
+ const char * /*error_name*/,
+ int /*reply_serial*/,
+ int /*requested_reply*/)
{
- (void)error_name;
- (void)reply_serial;
- (void)requested_reply;
-
- struct kconn *kconn = static_cast<struct kconn*>(configuration);
-
- int r;
- struct kdbus_cmd_param info = {};
- std::string dest_label;
- bool free_conn_info = false;
-
/* Broadcast signal has NULL destination */
/* Due to this sender can not check rule correctly */
if (message_type == DBUSPOLICY_MESSAGE_TYPE_SIGNAL && !destination)
__internal_enter();
auto internal_enter_guard = transaction_guard::makeGuard([] () { __internal_exit(); });
- uid_t dest_uid_n = 0;
- gid_t dest_gid_n = 0;
-
+ auto kconn = KCONN(configuration);
+ KdbusConnectionInfo destinationInfo(kconn->conn);
+ int r;
/* check can send */
/* if broadcasting, then pass - null destination */
if (destination && *destination) {
- r = kdbus_get_conn_info(&kconn->conn, destination, &info, POLICY_CONN_INFO_ALL);
+ r = destinationInfo.get(destination, KdbusConnection::POLICY_CONN_INFO_ALL);
if (r < 0)
return r;
- free_conn_info = true;
}
r = __internal_can_send(kconn->bus_type,
g_udesc.uid, g_udesc.gid, g_udesc.label,
- destination, info.k_names, info.names_num,
+ destination, destinationInfo.names(), destinationInfo.numberOfNames(),
path, interface, member, message_type);
if (r <= 0)
- goto end;
-
- /* copy & free */
- if (destination && *destination) {
- dest_uid_n = info.uid_n;
- dest_gid_n = info.gid_n;
-
- if (info.label)
- dest_label = info.label;
-
- if (free_conn_info) {
- kdbus_free_by_offset(&kconn->conn, info.free_offset);
- free_conn_info = false;
- }
- }
+ return r;
+ KdbusConnectionInfo senderInfo(kconn->conn);
/* check can recv */
/* get sender information from kdbus */
- r = kdbus_get_conn_info(&kconn->conn, sender, &info, POLICY_CONN_INFO_NAME);
+ r = senderInfo.get(sender, KdbusConnection::POLICY_CONN_INFO_NAME);
if (r < 0) {
fprintf(stderr, "failed to kdbus conn info:%d\n", r);
- goto end;
+ return r;
}
- free_conn_info = true;
- r = __internal_can_recv(kconn->bus_type,
- dest_uid_n, dest_gid_n, dest_label.c_str(),
- sender, info.k_names, info.names_num,
+ return __internal_can_recv(kconn->bus_type,
+ destinationInfo.uid(), destinationInfo.gid(), destinationInfo.label(),
+ sender, senderInfo.names(), senderInfo.numberOfNames(),
path, interface, member, message_type);
-
-end:
- if (free_conn_info)
- kdbus_free_by_offset(&kconn->conn, info.free_offset);
-
- return r;
}
DBUSPOLICY1_EXPORT int dbuspolicy1_check_in(void* configuration,
const char *interface,
const char *member,
int message_type,
- const char *error_name,
- int reply_serial,
- int requested_reply)
+ const char * /*error_name*/,
+ int /*reply_serial*/,
+ int /*requested_reply*/)
{
- (void)error_name;
- (void)reply_serial;
- (void)requested_reply;
-
- struct kconn *kconn = static_cast<struct kconn *>(configuration);
-
- int r;
- struct kdbus_cmd_param info;
-
__internal_enter();
+ auto internal_enter_guard = transaction_guard::makeGuard([] () { __internal_exit(); });
+ auto kconn = KCONN(configuration);
+ KdbusConnectionInfo info(kconn->conn);
+ int r;
if (destination && *destination) {
- r = kdbus_get_conn_info(&kconn->conn, destination, &info, POLICY_CONN_INFO_NAME);
+ r = info.get(destination, KdbusConnection::POLICY_CONN_INFO_NAME);
if (r < 0)
- goto end;
+ return r;
}
r = __internal_can_send(kconn->bus_type,
sender_uid, sender_gid, sender_label,
- destination, info.k_names, info.names_num,
+ destination, info.names(), info.numberOfNames(),
path, interface, member, message_type);
if (r <= 0)
- goto end;
+ return r;
- /* libdbus, gdbus pass multiple sender as parameter : eg. "name_A name_B name_C". */
- /* Because of '__internal_can_recv' can check rule against multiple names, */
- /* it is not needed to use __internal_can_recv_multi here. */
if (!sender)
sender = ":";
+
+ /* libdbus, gdbus pass multiple sender as parameter : eg. "name_A name_B name_C". */
r = __internal_can_recv(kconn->bus_type,
g_udesc.uid, g_udesc.gid, g_udesc.label,
sender, nullptr, 0,
path, interface, member, message_type);
if (r <= 0)
- goto end;
-end:
- if (info.free_offset)
- kdbus_free_by_offset(&kconn->conn, info.free_offset);
+ return r;
- __internal_exit();
return r;
}
DBUSPOLICY1_EXPORT int dbuspolicy1_can_own(void* configuration, const char* const service)
{
- int r;
- struct kconn *kconn = static_cast<struct kconn *>(configuration);
+ auto kconn = KCONN(configuration);
+
__internal_enter();
- r = __internal_can_own(kconn->bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, service);
- __internal_exit();
- return r;
+ auto internal_enter_guard = transaction_guard::makeGuard([] () { __internal_exit(); });
+
+ return __internal_can_own(kconn->bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, service);
}