struct kconn {
int fd;
- uint64_t id;
char *pool;
+ BusType bus_type;
} g_conn[2] = {
{.pool = MAP_FAILED},
{.pool = MAP_FAILED}
char label[256];
} g_udesc;
+static bool init_once_done = false;
+static bool init_once_db[2] = {false, false};
+static bool init_once_conn[2] = {false, false};
+
void __dbuspolicy1_change_creds(uid_t uid, gid_t gid, const char* label)
{
g_udesc.uid = uid;
return open(path, O_RDWR|O_NOCTTY|O_LARGEFILE|O_CLOEXEC);
}
-static int kdbus_hello(BusType bus_type, uint64_t hello_flags, uint64_t attach_flags_send, uint64_t attach_flags_recv)
+static int kdbus_hello(struct kconn *kconn, uint64_t hello_flags, uint64_t attach_flags_send, uint64_t attach_flags_recv)
{
struct kdbus_cmd_hello* cmd;
struct kdbus_cmd_free cmd_free;
struct kdbus_item* item;
- int fd = g_conn[bus_type].fd;
int size = ALIGN8(sizeof(struct kdbus_cmd_hello)) + ALIGN8(offsetof(struct kdbus_item, data) + sizeof(CONNECTION_LABEL));
cmd = calloc(1, size);
item->size = offsetof(struct kdbus_item, data) + sizeof(CONNECTION_LABEL);
item->type = KDBUS_ITEM_CONN_DESCRIPTION;
memcpy(item->str, CONNECTION_LABEL, sizeof(CONNECTION_LABEL));
- if (ioctl(fd, KDBUS_CMD_HELLO, cmd) < 0)
+ if (ioctl(kconn->fd, KDBUS_CMD_HELLO, cmd) < 0)
goto err;
- g_conn[bus_type].id = cmd->id;
- if (MAP_FAILED == (g_conn[bus_type].pool = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, fd, 0)))
+ if (MAP_FAILED == (kconn->pool = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, kconn->fd, 0)))
goto err;
cmd_free.offset = cmd->offset;
cmd_free.size = sizeof(struct kdbus_cmd_free);
- ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &cmd_free);
+ ioctl(kconn->fd, KDBUS_CMD_FREE, &cmd_free);
free(cmd);
return 0;
return res;
}
-static bool dbuspolicy_init_once(void)
+static bool dbuspolicy_init_once_locked(void)
{
+ if (init_once_done)
+ return false;
+
char buf[1024];
int attr_fd;
int r;
attr_fd = open("/proc/self/attr/current", O_RDONLY);
if (attr_fd < 0)
- return -1;
+ return true;
r = read(attr_fd, buf, sizeof(buf));
close(attr_fd);
__internal_init_once();
+ init_once_done = true;
+
+ return false;
+}
+
+static bool bus_type_from_path(const char *bus_path, BusType *bus_type, char **pp)
+{
+ char *p = realpath(bus_path, NULL);
+ if (!p)
+ return false;
+
+ if (pp)
+ *pp = p;
+
+ if (0 == strcmp(p, KDBUS_SYSTEM_BUS_PATH)) {
+ *bus_type = SYSTEM_BUS;
+ return true;
+ }
+
+ if (0 == strncmp(p, KDBUS_PATH_PREFIX, strlen(KDBUS_PATH_PREFIX))) {
+ *bus_type = SESSION_BUS;
+ return true;
+ }
+
+ free(p);
return false;
}
static int bus_path_resolve(const char *bus_path, char *resolved_path, unsigned resolved_path_size, BusType *bus_type, uid_t *bus_owner)
{
- char *p;
const char user_suffix[] = "-user/bus";
int suffix_pos;
char* last_slash;
int ret = -1;
+ char *p;
- p = realpath(bus_path, NULL);
- if (!p)
+ if (!bus_type_from_path(bus_path, bus_type, &p))
return -1;
- if (0 != strncmp(p, KDBUS_PATH_PREFIX, strlen(KDBUS_PATH_PREFIX)))
- goto err;
-
- if (0 == strcmp(p, KDBUS_SYSTEM_BUS_PATH)) {
- *bus_type = SYSTEM_BUS;
- } else {
+ if (*bus_type == SESSION_BUS && NULL != bus_owner) {
suffix_pos = strlen(p) - strlen(user_suffix);
if (suffix_pos < 0)
goto err;
// so it's OK to assume that *bus_owner==0 always means error.
if (errno || (*bus_owner == 0))
goto err;
-
- *bus_type = SESSION_BUS;
}
- snprintf(resolved_path, resolved_path_size, "%s", p);
+ if (resolved_path)
+ snprintf(resolved_path, resolved_path_size, "%s", p);
+
ret = 0;
err:
free(p);
return ret;
}
-static bool init_once_done = false;
-static bool init_once[2] = {false, false};
+static bool init_common_locked(BusType bus_type)
+{
+ dbuspolicy_init_once_locked();
-DBUSPOLICY1_EXPORT void* dbuspolicy1_init(const char *bus_path)
+ if (init_once_db[bus_type])
+ return true;
+
+ int ret = __internal_init_auto_serialized(bus_type, (bus_type == SYSTEM_BUS) ? system_bus_conf_file_primary() : session_bus_conf_file_primary());
+ if (ret < 0)
+ ret = __internal_init(bus_type, (bus_type == SYSTEM_BUS) ? SYSTEM_BUS_CONF_FILE_SECONDARY : SESSION_BUS_CONF_FILE_SECONDARY);
+
+ if (ret >= 0) {
+ __internal_init_sup_group(bus_type, g_udesc.uid, g_udesc.gid);
+ init_once_db[bus_type] = true;
+ }
+ return ret >= 0;
+}
+
+static struct kconn *init_global_conn_locked(BusType bus_type, const char *resolved_path)
{
- BusType bus_type = SESSION_BUS;
- char resolved_path[PATH_MAX] = { 0 };
- int rp, rs;
- uid_t bus_owner = 0;
+ if (init_once_conn[bus_type])
+ return &g_conn[bus_type];
- _Static_assert(SYSTEM_BUS == 0, "SYSTEM_BUS not 0");
- _Static_assert(SESSION_BUS == 1, "SESSION_BUS not 1");
+ struct kconn *result = &g_conn[bus_type];
+ if ((result->fd = kdbus_open_bus(resolved_path)) < 0) {
+ LOGE("Error opening bus: %s", resolved_path);
+ return NULL;
+ }
- if (bus_path_resolve(bus_path, resolved_path, sizeof(resolved_path), &bus_type, &bus_owner) < 0) {
- LOGE("Error resolving bus path: %s", bus_path);
+ if (kdbus_hello(result, 0, _KDBUS_ATTACH_ALL, 0) < 0) {
+ LOGE("Error: bus hello failed");
+ close(result->fd);
return NULL;
}
+ result->bus_type = bus_type;
+ init_once_conn[bus_type] = true;
+ return result;
+}
+
+static struct kconn *get_global_conn(BusType bus_type, const char *resolved_path)
+{
pthread_mutex_lock(&g_mutex);
- if (!init_once_done) {
- init_once_done = true;
- dbuspolicy_init_once();
+ struct kconn *result = init_global_conn_locked(bus_type, resolved_path);
+ pthread_mutex_unlock(&g_mutex);
+ return result;
+}
+
+static struct kconn *init_shared_fd(BusType bus_type, int fd)
+{
+ struct kconn *result = malloc(sizeof(*result));
+ if (NULL == result) {
+ LOGE("Error: failed to allocate memory for policy configuration");
+ return NULL;
}
- if (!init_once[bus_type]) {
- rp = __internal_init_auto_serialized(bus_type, (bus_type == SYSTEM_BUS) ? system_bus_conf_file_primary() : session_bus_conf_file_primary());
- if (rp < 0)
- rs = __internal_init(bus_type, (bus_type == SYSTEM_BUS) ? SYSTEM_BUS_CONF_FILE_SECONDARY : SESSION_BUS_CONF_FILE_SECONDARY);
- else
- rs = 1;
+ result->fd = fd;
+ result->bus_type = bus_type;
+ return result;
+}
- if (rp < 0 && rs < 0) /* when both negative */
- goto err;
+static bool can_open(BusType bus_type, uid_t bus_owner)
+{
+ pthread_mutex_lock(&g_mutex);
+ bool ret = init_common_locked(bus_type);
+ pthread_mutex_unlock(&g_mutex);
- __internal_init_sup_group(bus_type, g_udesc.uid, g_udesc.gid);
+ if (ret)
+ return __internal_can_open(bus_type, bus_owner, g_udesc.uid, g_udesc.gid, g_udesc.label) > 0;
- if (__internal_can_open(bus_type, bus_owner, g_udesc.uid, g_udesc.gid, g_udesc.label) <= 0) {
- LOGE("Error: %lu isn't allowed", g_udesc.uid);
- goto err;
- }
+ return false;
+}
- if ((g_conn[bus_type].fd = kdbus_open_bus(resolved_path)) < 0) {
- LOGE("Error opening bus: %s", resolved_path);
- goto err;
- }
+DBUSPOLICY1_EXPORT void* dbuspolicy1_init_shared(const char *bus_path, int fd)
+{
+ _Static_assert(SYSTEM_BUS == 0, "SYSTEM_BUS not 0");
+ _Static_assert(SESSION_BUS == 1, "SESSION_BUS not 1");
- if (kdbus_hello(bus_type, 0, _KDBUS_ATTACH_ALL, 0) < 0) {
- LOGE("Error: bus hello failed");
- goto err_close;
- }
+ BusType bus_type = SESSION_BUS;
+ uid_t bus_owner = 0;
+ char resolved_path[PATH_MAX] = { 0 };
- init_once[bus_type] = true;
+ if (bus_path_resolve(bus_path, resolved_path, sizeof(resolved_path), &bus_type, &bus_owner) < 0) {
+ LOGE("Error resolving bus path: %s", bus_path);
+ return NULL;
+ }
+
+ struct kconn *result = NULL;
+ if (can_open(bus_type, bus_owner)) {
+ if (-1 == fd) {
+ result = get_global_conn(bus_type, resolved_path);
+ } else {
+ result = init_shared_fd(bus_type, fd);
+ }
}
- pthread_mutex_unlock(&g_mutex);
__internal_init_flush_logs();
- return &g_conn[bus_type];
+ return result;
+}
-err_close:
- if (g_conn[bus_type].pool != MAP_FAILED)
- munmap(g_conn[bus_type].pool, KDBUS_POOL_SIZE);
- close(g_conn[bus_type].fd);
-err:
- pthread_mutex_unlock(&g_mutex);
- return NULL;
+DBUSPOLICY1_EXPORT void* dbuspolicy1_init(const char *bus_path)
+{
+ return dbuspolicy1_init_shared(bus_path, -1);
}
-DBUSPOLICY1_EXPORT void dbuspolicy1_free(void* configuration)
+DBUSPOLICY1_EXPORT void dbuspolicy1_init_set_pool(void *configuration, void *pool)
{
- configuration = configuration;
+ struct kconn *conf = configuration;
+ conf->pool = pool;
}
-static BusType configuration_bus_type(struct kconn const *configuration) { return configuration == g_conn ? SYSTEM_BUS : SESSION_BUS; }
+DBUSPOLICY1_EXPORT void dbuspolicy1_free(void* configuration)
+{
+ for (size_t i = 0; i < sizeof(g_conn)/sizeof(g_conn[0]); i++)
+ if (configuration == &g_conn[i])
+ return;
+
+ free(configuration);
+}
union kdbus_cmd_union {
struct kdbus_cmd_info cmd_info;
union kdbus_cmd_union cmd;
};
-int kdbus_get_conn_info(BusType bus_type, const char *destination, struct kdbus_cmd_param *info, __u64 flags)
+int kdbus_get_conn_info(struct kconn *kconn, const char *destination, struct kdbus_cmd_param *info, __u64 flags)
{
char const *label = NULL;
const char** k_names = info->k_names;
*(uint64_t*)ALIGNDN8((uintptr_t)cmd->cmd_info.items->str + l) = 0; /* trailing zero + padding */
memcpy(cmd->cmd_info.items->str, destination, l + 1);
}
- r = ioctl(g_conn[bus_type].fd, KDBUS_CMD_CONN_INFO, &cmd->cmd_info);
+ r = ioctl(kconn->fd, KDBUS_CMD_CONN_INFO, &cmd->cmd_info);
if (r < 0) {
if (errno == ENXIO || errno == ESRCH)
r = DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE;
free_offset = true;
- conn_info = (struct kdbus_info *) ((uint8_t *) g_conn[bus_type].pool + cmd->cmd_info.offset);
+ conn_info = (struct kdbus_info *) ((uint8_t *) kconn->pool + cmd->cmd_info.offset);
items_end = (uintptr_t)conn_info + (unsigned)conn_info->size;
_Static_assert((unsigned)KDBUS_ITEM_CREDS == KDBUS_ITEM_CREDS, "KDBUS_ITEM_CREDS not preserved when cast to unsigned");
(void)reply_serial;
(void)requested_reply;
+ struct kconn *kconn = configuration;
+
int r;
- BusType bus_type = configuration_bus_type(configuration);
struct kdbus_cmd_param info = {
.free_offset = false,
.empty_names = true
/* check can send */
/* if broadcasting, then pass - null destination */
if (destination && *destination) {
- r = kdbus_get_conn_info(bus_type, destination, &info, POLICY_CONN_INFO_ALL);
+ r = kdbus_get_conn_info(kconn, destination, &info, POLICY_CONN_INFO_ALL);
if (r < 0)
goto end;
}
if (info.empty_names)
- r = __internal_can_send(bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, destination, path, interface, member, message_type);
+ r = __internal_can_send(kconn->bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, destination, path, interface, member, message_type);
else
- r = __internal_can_send_multi_dest(bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, info.k_names, path, interface, member, message_type);
+ r = __internal_can_send_multi_dest(kconn->bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, info.k_names, path, interface, member, message_type);
if (r <= 0)
goto end;
strncpy(dest_label, info.label, strlen(info.label) + 1);
}
if (info.free_offset)
- ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &cmd->cmd_free);
+ ioctl(kconn->fd, KDBUS_CMD_FREE, &cmd->cmd_free);
info.free_offset = false;
info.empty_names = true;
/* check can recv */
/* get sender information from kdbus */
- r = kdbus_get_conn_info(bus_type, sender, &info, POLICY_CONN_INFO_NAME);
+ r = kdbus_get_conn_info(kconn, sender, &info, POLICY_CONN_INFO_NAME);
if (r < 0) {
fprintf(stderr, "failed to kdbus conn info:%d\n", r);
goto end;
}
if (info.empty_names)
- r = __internal_can_recv(bus_type, dest_uid_n, dest_gid_n, dest_label, sender, path, interface, member, message_type);
+ r = __internal_can_recv(kconn->bus_type, dest_uid_n, dest_gid_n, dest_label, sender, path, interface, member, message_type);
else
- r = __internal_can_recv_multi(bus_type, dest_uid_n, dest_gid_n, dest_label, info.k_names, path, interface, member, message_type);
+ r = __internal_can_recv_multi(kconn->bus_type, dest_uid_n, dest_gid_n, dest_label, info.k_names, path, interface, member, message_type);
end:
if (info.free_offset)
- ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &cmd->cmd_free);
+ ioctl(kconn->fd, KDBUS_CMD_FREE, &cmd->cmd_free);
if (dest_label)
free(dest_label);
(void)reply_serial;
(void)requested_reply;
+ struct kconn *kconn = configuration;
+
int r;
- BusType bus_type = configuration_bus_type(configuration);
struct kdbus_cmd_param info = {
.free_offset = false,
.empty_names = true
__internal_enter();
if (destination && *destination) {
- r = kdbus_get_conn_info(bus_type, destination, &info, POLICY_CONN_INFO_NAME);
+ r = kdbus_get_conn_info(kconn, destination, &info, POLICY_CONN_INFO_NAME);
if (r < 0)
goto end;
}
if (info.empty_names)
- r = __internal_can_send(bus_type, sender_uid, sender_gid, sender_label, destination, path, interface, member, message_type);
+ r = __internal_can_send(kconn->bus_type, sender_uid, sender_gid, sender_label, destination, path, interface, member, message_type);
else
- r = __internal_can_send_multi_dest(bus_type, sender_uid, sender_gid, sender_label, info.k_names, path, interface, member, message_type);
+ r = __internal_can_send_multi_dest(kconn->bus_type, sender_uid, sender_gid, sender_label, info.k_names, path, interface, member, message_type);
if (r <= 0)
goto end;
/* it is not needed to use __internal_can_recv_multi here. */
if (!sender)
sender = ":";
- r = __internal_can_recv(bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, sender, path, interface, member, message_type);
+ r = __internal_can_recv(kconn->bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, sender, path, interface, member, message_type);
if (r <= 0)
goto end;
end:
if (info.free_offset)
- ioctl(g_conn[bus_type].fd, KDBUS_CMD_FREE, &info.cmd.cmd_free);
+ ioctl(kconn->fd, KDBUS_CMD_FREE, &info.cmd.cmd_free);
__internal_exit();
return r;
DBUSPOLICY1_EXPORT int dbuspolicy1_can_own(void* configuration, const char* const service)
{
int r;
- BusType bus_type = configuration_bus_type(configuration);
+ struct kconn *kconn = configuration;
__internal_enter();
- r = __internal_can_own(bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, service);
+ r = __internal_can_own(kconn->bus_type, g_udesc.uid, g_udesc.gid, g_udesc.label, service);
__internal_exit();
return r;
}