Commit d7749ad4 authored by Slava Monich's avatar Slava Monich

[connman] Added Sailfish access control plugin. JB#37923

parent 66d9240c
......@@ -69,6 +69,7 @@ unit/test-nat
unit/test-nat
unit/test-dnsproxy
unit/test-access
unit/test-sailfish_access
unit/test-sailfish_wakeup_timer
*.gcda
......
......@@ -270,8 +270,8 @@ client_connmanctl_LDADD = gdbus/libgdbus-internal.la @DBUS_LIBS@ @GLIB_LIBS@ \
-lreadline -ldl
endif
noinst_PROGRAMS += unit/test-access unit/test-ippool \
unit/test-sailfish_wakeup_timer unit/test-dnsproxy
noinst_PROGRAMS += unit/test-access unit/test-dnsproxy unit/test-ippool \
unit/test-sailfish_access unit/test-sailfish_wakeup_timer
if TEST_COVERAGE
COVERAGE_OPT = --coverage
......@@ -287,6 +287,11 @@ unit_test_access_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_access_SOURCES = unit/test-access.c src/access.c src/log.c
unit_test_access_LDADD = @GLIB_LIBS@ -ldl
unit_test_sailfish_access_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_sailfish_access_SOURCES = unit/test-sailfish_access.c \
src/log.c src/access.c plugins/sailfish_access.c
unit_test_sailfish_access_LDADD = @GLIB_LIBS@ -ldl
unit_test_sailfish_wakeup_timer_CFLAGS = $(COVERAGE_OPT) $(AM_CFLAGS)
unit_test_sailfish_wakeup_timer_SOURCES = unit/test-sailfish_wakeup_timer.c \
src/log.c src/wakeup_timer.c \
......@@ -296,8 +301,8 @@ unit_test_sailfish_wakeup_timer_LDADD = @GLIB_LIBS@ -lrt -ldl
unit_test_dnsproxy_SOURCES = unit/test-dnsproxy.c src/log.c
unit_test_dnsproxy_LDADD = @GLIB_LIBS@ -lresolv -ldl
TESTS = unit/test-access unit/test-ippool \
unit/test-sailfish_wakeup_timer unit/test-dnsproxy
TESTS = unit/test-access unit/test-ippool unit/test-dnsproxy \
unit/test-sailfish_access unit/test-sailfish_wakeup_timer
if WISPR
noinst_PROGRAMS += tools/wispr
......
......@@ -55,6 +55,11 @@ builtin_modules += jolla_gps
builtin_sources += plugins/jolla-gps.c
endif
if SAILFISH_ACCESS
builtin_modules += sailfish_access
builtin_sources += plugins/sailfish_access.c
endif
if SAILFISH_WAKEUP_TIMER
builtin_modules += sailfish_wakeup_timer
builtin_sources += plugins/sailfish_wakeup_timer.c
......
......@@ -385,6 +385,18 @@ AC_ARG_ENABLE(wispr, AC_HELP_STRING([--disable-wispr],
[enable_wispr=${enableval}])
AM_CONDITIONAL(WISPR, test "${enable_wispr}" != "no")
AC_ARG_ENABLE(sailfish-access,
AC_HELP_STRING([--enable-sailfish-access], [enable Sailfish access control plugin]),
[enable_sailfish_access=${enableval}], [enable_sailfish_access="no"])
AM_CONDITIONAL(SAILFISH_ACCESS, test "${enable_sailfish_access}" != "no")
if (test "${enable_sailfish_access}" = "yes"); then
PKG_CHECK_MODULES(DBUSACCESS, libdbusaccess, dummy=yes,
AC_MSG_ERROR(libdbusaccess is required))
CFLAGS="$CFLAGS $DBUSACCESS_CFLAGS"
LIBS="$LIBS $DBUSACCESS_LIBS"
need_glibutil=yes
fi
AC_ARG_ENABLE(sailfish-debuglog,
AC_HELP_STRING([--enable-sailfish-debuglog], [enable Sailfish logging plugin]),
[enable_sailfish_debuglog=${enableval}], [enable_sailfish_debuglog="no"])
......
/*
* Connection Manager
*
* Copyright (C) 2017 Jolla Ltd. All rights reserved.
* Contact: Slava Monich <slava.monich@jolla.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define CONNMAN_API_SUBJECT_TO_CHANGE
#include <connman/plugin.h>
#include <connman/access.h>
#include <dbusaccess_peer.h>
#include <dbusaccess_policy.h>
#include <gutil_idlepool.h>
#include <gutil_log.h>
struct connman_access_service_policy_impl {
int ref_count;
char *spec;
DAPolicy *impl;
};
enum sailfish_service_access_action {
SERVICE_ACCESS_GET_PROPERTY = 1,
SERVICE_ACCESS_SET_PROPERTY
};
#define SERVICE_ACCESS_BUS DA_BUS_SYSTEM
#define DRIVER_NAME "sailfish"
/* We assume that these match each other an we don't have to convert */
G_STATIC_ASSERT((DA_ACCESS)CONNMAN_ACCESS_DENY == DA_ACCESS_DENY);
G_STATIC_ASSERT((DA_ACCESS)CONNMAN_ACCESS_ALLOW == DA_ACCESS_ALLOW);
static GHashTable *service_policies;
static GUtilIdlePool* service_policies_pool;
static const char *service_policy_default =
DA_POLICY_VERSION ";group(privileged)=allow";
static const DA_ACTION service_policy_actions [] = {
{ "get", SERVICE_ACCESS_GET_PROPERTY, 1 },
{ "set", SERVICE_ACCESS_SET_PROPERTY, 1 },
{ NULL }
};
static void sailfish_access_service_policy_free(
struct connman_access_service_policy_impl *p)
{
GASSERT(p->ref_count > 0);
if (!--(p->ref_count)) {
if (service_policies) {
g_hash_table_remove(service_policies, p->spec);
}
g_free(p->spec);
da_policy_unref(p->impl);
g_slice_free(struct connman_access_service_policy_impl, p);
}
}
static void sailfish_access_service_policy_unref(gpointer data)
{
sailfish_access_service_policy_free(data);
}
static struct connman_access_service_policy_impl *
sailfish_access_service_policy_create(const char *spec)
{
struct connman_access_service_policy_impl *p = NULL;
if (!spec || !spec[0]) {
/* Empty policy = use default */
spec = service_policy_default;
}
if (service_policies) {
p = g_hash_table_lookup(service_policies, spec);
}
if (p) {
/* Re-using the existing policy */
p->ref_count++;
} else {
/* Parse the policy string */
DAPolicy *impl = da_policy_new_full(spec,
service_policy_actions);
if (impl) {
/* String is usable */
p = g_slice_new0(struct
connman_access_service_policy_impl);
p->ref_count = 1;
p->impl = impl;
p->spec = g_strdup(spec);
if (service_policies) {
g_hash_table_replace(service_policies,
p->spec, p);
}
/*
* It's quite common that identical policies
* are being created in a loop and immediately
* get freed without even being used. Adding an
* extra reference to the idle pool saves us from
* having to actually allocate a bunch of identical
* objects.
*/
if (service_policies_pool) {
p->ref_count++;
gutil_idle_pool_add(service_policies_pool, p,
sailfish_access_service_policy_unref);
}
} else {
DBG("invalid spec \"%s\"", spec);
}
}
return p;
}
static enum connman_access sailfish_access_service_check(
struct connman_access_service_policy_impl *policy,
const char *sender, enum sailfish_service_access_action action,
const char *name, enum connman_access default_access)
{
/* Don't unref this one: */
DAPeer* peer = da_peer_get(SERVICE_ACCESS_BUS, sender);
return peer ? (enum connman_access)da_policy_check(policy->impl,
&peer->cred, action, name, (DA_ACCESS)default_access) :
default_access;
}
static enum connman_access sailfish_access_service_get_property(
struct connman_access_service_policy_impl *policy,
const char *sender, const char *name,
enum connman_access default_access)
{
return sailfish_access_service_check(policy, sender,
SERVICE_ACCESS_GET_PROPERTY, name, default_access);
}
static enum connman_access sailfish_access_service_set_property(
struct connman_access_service_policy_impl *policy,
const char *sender, const char *name,
enum connman_access default_access)
{
return sailfish_access_service_check(policy, sender,
SERVICE_ACCESS_SET_PROPERTY, name, default_access);
}
static const struct connman_access_driver sailfish_connman_access_driver = {
.name = DRIVER_NAME,
.service_policy_create = sailfish_access_service_policy_create,
.service_policy_free = sailfish_access_service_policy_free,
.service_get_property = sailfish_access_service_get_property,
.service_set_property = sailfish_access_service_set_property
};
static int sailfish_access_init()
{
int ret;
DBG("");
ret = connman_access_driver_register(&sailfish_connman_access_driver);
if (ret == 0) {
service_policies = g_hash_table_new(g_str_hash, g_str_equal);
service_policies_pool = gutil_idle_pool_new();
}
return ret;
}
static void sailfish_access_exit()
{
DBG("");
connman_access_timer_unregister(&sailfish_connman_access_driver);
da_peer_flush(SERVICE_ACCESS_BUS, NULL);
gutil_idle_pool_unref(service_policies_pool);
service_policies_pool = NULL;
if (service_policies) {
g_hash_table_destroy(service_policies);
service_policies = NULL;
}
}
CONNMAN_PLUGIN_DEFINE(sailfish_access, "Sailfish access control", VERSION,
CONNMAN_PLUGIN_PRIORITY_DEFAULT,
sailfish_access_init, sailfish_access_exit)
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/
......@@ -8,6 +8,7 @@
# Tests with coverage enabled:
TESTS="test-access \
test-ippool \
test-sailfish_access \
test-sailfish_wakeup_timer"
pushd `dirname $0` > /dev/null
......
/*
* Connection Manager
*
* Copyright (C) 2017 Jolla Ltd. All rights reserved.
* Contact: Slava Monich <slava.monich@jolla.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <connman/access.h>
#include <errno.h>
#include <dbusaccess_peer.h>
#include <dbusaccess_policy.h>
#include <gutil_idlepool.h>
#define CONNMAN_API_SUBJECT_TO_CHANGE
#include "plugin.h"
#define DRIVER "sailfish"
#define SPEC_BAD "bad"
#define SPEC_DENY "deny"
#define SPEC_ALLOW "allow"
struct da_policy {
int ref_count;
gboolean allow;
};
static int policy_count;
static GUtilIdlePool* peer_pool;
extern struct connman_plugin_desc __connman_builtin_sailfish_access;
/*==========================================================================*
* Stubs
*==========================================================================*/
DAPolicy *da_policy_new_full(const char *spec, const DA_ACTION *actions)
{
if (!g_strcmp0(spec, SPEC_BAD)) {
return NULL;
} else {
DAPolicy *p = g_new0(DAPolicy, 1);
p->ref_count = 1;
p->allow = !g_strcmp0(spec, SPEC_ALLOW);
policy_count++;
return p;
}
}
DAPolicy *da_policy_ref(DAPolicy *p)
{
if (p) {
g_atomic_int_inc(&p->ref_count);
}
return p;
}
void da_policy_unref(DAPolicy *p)
{
if (p) {
if (g_atomic_int_dec_and_test(&p->ref_count)) {
policy_count--;
g_free(p);
}
}
}
DA_ACCESS da_policy_check(DAPolicy *p, const DACred *cred, guint action,
const char *arg, DA_ACCESS default_access)
{
return p->allow ? DA_ACCESS_ALLOW : DA_ACCESS_DENY;
}
DAPeer* da_peer_get(DA_BUS bus, const char* name)
{
if (name) {
gsize len = strlen(name);
DAPeer *peer = g_malloc0(sizeof(DAPeer) + len + 1);
char *buf = (char*)(peer + 1);
strcpy(buf, name);
peer->name = buf;
gutil_idle_pool_add(peer_pool, peer, g_free);
return peer;
} else {
return NULL;
}
}
void da_peer_flush(DA_BUS bus, const char* name)
{
gutil_idle_pool_drain(peer_pool);
}
/*==========================================================================*
* Tests
*==========================================================================*/
static void test_sailfish_access_register()
{
g_assert(__connman_builtin_sailfish_access.init() == 0);
g_assert(__connman_builtin_sailfish_access.init() == -EALREADY);
__connman_builtin_sailfish_access.exit();
__connman_builtin_sailfish_access.exit();
}
static void test_sailfish_access_badspec()
{
g_assert(__connman_builtin_sailfish_access.init() == 0);
g_assert(!connman_access_service_policy_create(DRIVER ":" SPEC_BAD));
__connman_builtin_sailfish_access.exit();
}
static void test_sailfish_access_latefree()
{
struct connman_access_service_policy *p;
g_assert(__connman_builtin_sailfish_access.init() == 0);
p = connman_access_service_policy_create(NULL);
g_assert(p);
/*
* This is not right to call connman_access_service_policy_free()
* after the plugin the been terminated but it will still work.
*/
__connman_builtin_sailfish_access.exit();
connman_access_service_policy_free(p);
}
static void test_sailfish_access_cache()
{
struct connman_access_service_policy *p1;
struct connman_access_service_policy *p2;
g_assert(__connman_builtin_sailfish_access.init() == 0);
p1 = connman_access_service_policy_create(DRIVER);
p2 = connman_access_service_policy_create(DRIVER);
g_assert(p1);
g_assert(p2);
/* The policy implementation is reused */
g_assert(policy_count == 1);
connman_access_service_policy_free(p1);
connman_access_service_policy_free(p2);
__connman_builtin_sailfish_access.exit();
}
static void test_sailfish_access_allow()
{
struct connman_access_service_policy *p;
g_assert(__connman_builtin_sailfish_access.init() == 0);
p = connman_access_service_policy_create(DRIVER ":" SPEC_ALLOW);
g_assert(p);
g_assert(connman_access_service_get_property(p, "x", "foo",
CONNMAN_ACCESS_DENY) == CONNMAN_ACCESS_ALLOW);
g_assert(connman_access_service_set_property(p, NULL, "foo",
CONNMAN_ACCESS_DENY) == CONNMAN_ACCESS_DENY);
connman_access_service_policy_free(p);
__connman_builtin_sailfish_access.exit();
}
static void test_sailfish_access_deny()
{
struct connman_access_service_policy *p;
g_assert(__connman_builtin_sailfish_access.init() == 0);
p = connman_access_service_policy_create(DRIVER ":" SPEC_DENY);
g_assert(p);
g_assert(connman_access_service_get_property(p, "x", "foo",
CONNMAN_ACCESS_ALLOW) == CONNMAN_ACCESS_DENY);
g_assert(connman_access_service_set_property(p, NULL, "foo",
CONNMAN_ACCESS_ALLOW) == CONNMAN_ACCESS_ALLOW);
connman_access_service_policy_free(p);
__connman_builtin_sailfish_access.exit();
}
#define PREFIX "/sailfish_access/"
int main(int argc, char *argv[])
{
int ret;
peer_pool = gutil_idle_pool_new();
g_test_init(&argc, &argv, NULL);
g_test_add_func(PREFIX "register", test_sailfish_access_register);
g_test_add_func(PREFIX "badspec", test_sailfish_access_badspec);
g_test_add_func(PREFIX "latefree", test_sailfish_access_latefree);
g_test_add_func(PREFIX "cache", test_sailfish_access_cache);
g_test_add_func(PREFIX "allow", test_sailfish_access_allow);
g_test_add_func(PREFIX "deny", test_sailfish_access_deny);
ret = g_test_run();
gutil_idle_pool_unref(peer_pool);
return ret;
}
/*
* Local Variables:
* mode: C
* c-basic-offset: 8
* indent-tabs-mode: t
* End:
*/
......@@ -33,6 +33,7 @@ BuildRequires: pkgconfig(libgofono) >= 2.0.0
BuildRequires: pkgconfig(libgofonoext)
BuildRequires: pkgconfig(libglibutil) >= 1.0.20
BuildRequires: pkgconfig(libdbuslogserver-dbus)
BuildRequires: pkgconfig(libdbusaccess)
BuildRequires: pkgconfig(libmce-glib)
BuildRequires: pkgconfig(libgsupplicant)
BuildRequires: ppp-devel
......@@ -126,6 +127,7 @@ Documentation for connman.
--enable-sailfish-ofono \
--enable-sailfish-usb-tethering \
--enable-sailfish-wifi \
--enable-sailfish-access \
--disable-gadget \
--with-systemdunitdir=/%{_lib}/systemd/system \
--enable-systemd \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment