NaivePolicyChecker &_checker;
};
-struct kconn {
+/*
+ * kconn is a class which binds together a kdbus connection and a corresponding policy checker.
+ * It has two flavors:
+ * - global objects for system bus and session bus with private connections (static get() method);
+ * - objects created on demand when a client shares his kdbus connection with the library (static get_shared() method).
+ *
+ * Because the pointer to such object is passed (through void *) to a client, and then clients
+ * pass the pointer to dbuspolicy1_* functions, we always need to maintain the same type,
+ * regardless of the flavor.
+ *
+ * Thread-safety is ensured by C++ and static initialization in static member functions.
+ */
+class kconn {
+public:
KdbusConnection conn;
- ldp_xml_parser::NaivePolicyChecker *checker;
-} g_conn[2];
+ NaivePolicyChecker &checker;
+ bool can_be_freed;
-static std::once_flag init_once_conn[2];
+ kconn(NaivePolicyChecker &ch, const char *resolved_path)
+ : checker{ch}, can_be_freed{false}
+ {
+ if (conn.connect(resolved_path, 0, _KDBUS_ATTACH_ALL, 0) < 0) {
+ assert(false && "failed kdbus_connect");
+ }
+ }
+
+ kconn(NaivePolicyChecker &ch, int fd)
+ : checker{ch}, can_be_freed{true}
+ {
+ conn.shared_init_fd(fd);
+ }
+
+ static inline kconn &get(BusType bus_type, const char *resolved_path) {
+ if (SYSTEM_BUS == bus_type)
+ return system(resolved_path);
+ return session(resolved_path);
+ }
+
+ static inline kconn *get_shared(BusType bus_type, int fd)
+ {
+ kconn *result = new kconn(Checker::get(bus_type).checker(), fd);
+ if (nullptr == result)
+ LOGE("Error: failed to allocate memory for policy configuration");
+ return result;
+ }
+
+private:
+ static kconn &system(const char *resolved_path) {
+ static kconn c{Checker::system().checker(), resolved_path};
+ return c;
+ }
+ static kconn &session(const char *resolved_path) {
+ static kconn c{Checker::session().checker(), resolved_path};
+ return c;
+ }
+
+};
static std::shared_ptr<const char> bus_type_from_path(const char *bus_path, BusType &bus_type)
{
return resolved_path;
}
-static void init_global_conn_locked(BusType bus_type, std::shared_ptr<const char> resolved_path)
-{
- struct kconn *kconn = &g_conn[bus_type];
- kconn->checker = &Checker::get(bus_type).checker();
-
- if (kconn->conn.connect(resolved_path.get(), 0, _KDBUS_ATTACH_ALL, 0) < 0) {
- assert(false && "failed kdbus_connect");
- }
-}
-
-static struct kconn *get_global_conn(BusType bus_type, std::shared_ptr<const char> resolved_path) noexcept
-{
- std::call_once(init_once_conn[bus_type], init_global_conn_locked, bus_type, resolved_path);
-
- return &g_conn[bus_type];
-}
-
-static kconn *init_shared_fd(BusType bus_type, int fd)
-{
- kconn *result = new kconn;
- if (nullptr == result) {
- LOGE("Error: failed to allocate memory for policy configuration");
- return nullptr;
- }
- result->conn.shared_init_fd(fd);
- result->checker = &Checker::get(bus_type).checker();
- return result;
-}
-
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");
-
BusType bus_type = SESSION_BUS;
uid_t bus_owner = 0;
g_udesc.init();
- struct kconn *result = nullptr;
+ kconn *result = nullptr;
if (Checker::get(bus_type).can_open_owned_by(bus_owner)) {
if (-1 == fd) {
- result = get_global_conn(bus_type, resolved_path);
+ result = &kconn::get(bus_type, resolved_path.get());
} else {
- result = init_shared_fd(bus_type, fd);
+ result = kconn::get_shared(bus_type, fd);
}
}
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;
-
- delete KCONN(configuration);
+ auto kconn = KCONN(configuration);
+ if (kconn->can_be_freed)
+ delete kconn;
}
/*
auto m_type = toMessageType(message_type);
MatchItemSend sendItem(interface, member, path, m_type, destinationInfo.names());
- auto decision = kconn->checker->check(g_udesc.uid, g_udesc.gid, g_udesc.label, sendItem);
+ auto decision = kconn->checker.check(g_udesc.uid, g_udesc.gid, g_udesc.label, sendItem);
if (DecisionResult::ALLOW != decision)
return decisionToRetCode(decision);
return r;
MatchItemReceive receiveItem(interface, member, path, m_type, senderInfo.names());
- return decisionToRetCode(kconn->checker->check(destinationInfo.uid(),
- destinationInfo.gid(),
- destinationInfo.label(),
- receiveItem));
+ return decisionToRetCode(kconn->checker.check(destinationInfo.uid(),
+ destinationInfo.gid(),
+ destinationInfo.label(),
+ receiveItem));
}
DBUSPOLICY1_EXPORT int dbuspolicy1_check_in(void* configuration,
auto m_type = toMessageType(message_type);
MatchItemSend sendItem(interface, member, path, m_type, info.names());
- auto decision = kconn->checker->check(sender_uid, sender_gid, sender_label, sendItem);
+ auto decision = kconn->checker.check(sender_uid, sender_gid, sender_label, sendItem);
if (DecisionResult::ALLOW != decision)
return decisionToRetCode(decision);
KdbusBusNames names;
MatchItemReceive receiveItem(interface, member, path, m_type, names.addSpaceSeparatedNames(sender));
- return decisionToRetCode(kconn->checker->check(g_udesc.uid,
- g_udesc.gid,
- g_udesc.label,
- receiveItem));
+ return decisionToRetCode(kconn->checker.check(g_udesc.uid,
+ g_udesc.gid,
+ g_udesc.label,
+ receiveItem));
}
DBUSPOLICY1_EXPORT int dbuspolicy1_can_own(void* configuration, const char* const service)
{
tslog::LogLock log_lock;
auto kconn = KCONN(configuration);
- return decisionToRetCode(kconn->checker->check(g_udesc.uid,
- g_udesc.gid,
- g_udesc.label,
- MatchItemOwn(service)));
+ return decisionToRetCode(kconn->checker.check(g_udesc.uid,
+ g_udesc.gid,
+ g_udesc.label,
+ MatchItemOwn(service)));
}