diff options
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | system-helper/Makefile.am.inc | 18 | ||||
-rw-r--r-- | system-helper/org.freedesktop.XdgApp.policy.in | 86 | ||||
-rw-r--r-- | system-helper/org.freedesktop.XdgApp.rules | 8 | ||||
-rw-r--r-- | system-helper/xdg-app-system-helper.c | 130 |
5 files changed, 239 insertions, 8 deletions
diff --git a/configure.ac b/configure.ac index 369cf6b..8a4bef1 100644 --- a/configure.ac +++ b/configure.ac @@ -101,6 +101,8 @@ AC_SUBST([GLIB_MKENUMS], [`$PKG_CONFIG --variable glib_mkenums glib-2.0`]) AC_SUBST([GLIB_COMPILE_RESOURCES], [`$PKG_CONFIG --variable glib_compile_resources gio-2.0`]) AC_SUBST([GDBUS_CODEGEN], [`$PKG_CONFIG --variable gdbus_codegen gio-2.0`]) +POLKIT_GOBJECT_REQUIRED=0.98 + PKG_CHECK_MODULES(BASE, [glib-2.0 gio-2.0 gio-unix-2.0]) AC_SUBST(BASE_CFLAGS) AC_SUBST(BASE_LIBS) @@ -108,6 +110,9 @@ PKG_CHECK_MODULES(SOUP, [libsoup-2.4]) AC_SUBST(SOUP_CFLAGS) AC_SUBST(SOUP_LIBS) +PKG_CHECK_MODULES(POLKIT, \ + polkit-gobject-1 >= $POLKIT_GOBJECT_REQUIRED) + AC_ARG_ENABLE([xauth], AC_HELP_STRING([--disable-xauth], [Disable Xauth use]), diff --git a/system-helper/Makefile.am.inc b/system-helper/Makefile.am.inc index b14822a..60a377a 100644 --- a/system-helper/Makefile.am.inc +++ b/system-helper/Makefile.am.inc @@ -28,7 +28,21 @@ xdg_app_system_helper_SOURCES = \ system-helper/xdg-app-system-helper.c \ system-helper/xdg-app-resources.h \ system-helper/xdg-app-resources.c \ + lib/xdg-app-error.c \ $(NULL) -xdg_app_system_helper_LDADD = $(BASE_LIBS) $(OSTREE_LIBS) libxdgapp-common.la -xdg_app_system_helper_CFLAGS = $(BASE_CFLAGS) $(OSTREE_CFLAGS) +xdg_app_system_helper_LDADD = $(BASE_LIBS) $(OSTREE_LIBS) $(POLKIT_LIBS) libxdgapp-common.la +xdg_app_system_helper_CFLAGS = $(BASE_CFLAGS) $(OSTREE_CFLAGS) $(POLKIT_CFLAGS) + +polkit_rulesdir = $(datadir)/polkit-1/rules.d +dist_polkit_rules_DATA = \ + system-helper/org.freedesktop.XdgApp.rules + +polkit_policydir = $(datadir)/polkit-1/actions +dist_polkit_policy_DATA = \ + system-helper/org.freedesktop.XdgApp.policy + +@INTLTOOL_POLICY_RULE@ + +EXTRA_DIST += system-helper/org.freedesktop.XdgApp.policy.in +DISTCLEANFILES += system-helper/org.freedesktop.XdgApp.policy diff --git a/system-helper/org.freedesktop.XdgApp.policy.in b/system-helper/org.freedesktop.XdgApp.policy.in new file mode 100644 index 0000000..f5f2272 --- /dev/null +++ b/system-helper/org.freedesktop.XdgApp.policy.in @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE policyconfig PUBLIC + "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN" + "http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd"> +<policyconfig> + + <!-- + Policy definitions for XdgApp system actions. + Copyright (c) 2016 Alexander Larsson <alexl@redhat.com> + --> + + <vendor>The XdgApp Project</vendor> + <vendor_url>https://cgit.freedesktop.org/xdg-app/xdg-app/</vendor_url> + <icon_name>package-x-generic</icon_name> + + <action id="org.freedesktop.XdgApp.app-install"> + <!-- SECURITY: + - Normal users do not need authentication to install signed applications + from signed repositories, as this cannot exploit a system. + - Paranoid users (or parents!) can change this to 'auth_admin' or + 'auth_admin_keep'. + --> + <_description>Install signed application</_description> + <_message>Authentication is required to install software</_message> + <icon_name>package-x-generic</icon_name> + <defaults> + <allow_any>auth_admin</allow_any> + <allow_inactive>auth_admin</allow_inactive> + <allow_active>auth_admin_keep</allow_active> + </defaults> + </action> + + <action id="org.freedesktop.XdgApp.runtime-install"> + <!-- SECURITY: + - Normal users do not need authentication to install signed applications + from signed repositories, as this cannot exploit a system. + - Paranoid users (or parents!) can change this to 'auth_admin' or + 'auth_admin_keep'. + --> + <_description>Install signed runtime</_description> + <_message>Authentication is required to install software</_message> + <icon_name>package-x-generic</icon_name> + <defaults> + <allow_any>auth_admin</allow_any> + <allow_inactive>auth_admin</allow_inactive> + <allow_active>auth_admin_keep</allow_active> + </defaults> + </action> + + <action id="org.freedesktop.XdgApp.app-update"> + <!-- SECURITY: + - Normal users do not require admin authentication to update an + app as the commit will be signed, and the action is required + to update the system when unattended. + - Changing this to anything other than 'yes' will break unattended + updates. + --> + <_description>Update signed application</_description> + <_message>Authentication is required to update software</_message> + <icon_name>package-x-generic</icon_name> + <defaults> + <allow_any>auth_admin</allow_any> + <allow_inactive>auth_admin</allow_inactive> + <allow_active>yes</allow_active> + </defaults> + </action> + + <action id="org.freedesktop.XdgApp.runtime-update"> + <!-- SECURITY: + - Normal users do not require admin authentication to update a + runtime as the commit will be signed, and the action is required + to update the system when unattended. + - Changing this to anything other than 'yes' will break unattended + updates. + --> + <_description>Update signed runtime</_description> + <_message>Authentication is required to update software</_message> + <icon_name>package-x-generic</icon_name> + <defaults> + <allow_any>auth_admin</allow_any> + <allow_inactive>auth_admin</allow_inactive> + <allow_active>yes</allow_active> + </defaults> + </action> + +</policyconfig> diff --git a/system-helper/org.freedesktop.XdgApp.rules b/system-helper/org.freedesktop.XdgApp.rules new file mode 100644 index 0000000..113306b --- /dev/null +++ b/system-helper/org.freedesktop.XdgApp.rules @@ -0,0 +1,8 @@ +polkit.addRule(function(action, subject) { + if ((action.id == "org.freedesktop.XdgApp.app-install" || + action.id == "org.freedesktop.XdgApp.runtime-install") && + subject.active == true && subject.local == true && + subject.isInGroup("wheel")) { + return polkit.Result.YES; + } +}); diff --git a/system-helper/xdg-app-system-helper.c b/system-helper/xdg-app-system-helper.c index 67321d3..0404022 100644 --- a/system-helper/xdg-app-system-helper.c +++ b/system-helper/xdg-app-system-helper.c @@ -24,12 +24,21 @@ #include <stdlib.h> #include <string.h> #include <gio/gio.h> +#include <polkit/polkit.h> #include "xdg-app-dbus.h" #include "xdg-app-dir.h" +#include "lib/xdg-app-error.h" +static PolkitAuthority *authority = NULL; static GDBusNodeInfo *introspection_data = NULL; +#ifndef glib_autoptr_cleanup_PolkitAuthorizationResult +G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitAuthorizationResult, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitDetails, g_object_unref) +G_DEFINE_AUTOPTR_CLEANUP_FUNC(PolkitSubject, g_object_unref) +#endif + static gboolean handle_deploy (XdgAppSystemHelper *object, GDBusMethodInvocation *invocation, @@ -43,13 +52,14 @@ handle_deploy (XdgAppSystemHelper *object, g_autoptr(GFile) path = g_file_new_for_path (arg_repo_path); g_autoptr(GError) error = NULL; g_autoptr(GFile) deploy_dir = NULL; + g_autoptr(PolkitSubject) subject = NULL; + g_autoptr(PolkitDetails) details = NULL; gboolean is_update; - - is_update = (arg_flags & XDG_APP_HELPER_DEPLOY_FLAGS_UPDATE) != 0; + g_autoptr(GMainContext) main_context = NULL; if ((arg_flags & ~XDG_APP_HELPER_DEPLOY_FLAGS_ALL) != 0) { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Unsupported flags enabled: 0x%x", (arg_flags & ~XDG_APP_HELPER_DEPLOY_FLAGS_ALL)); } @@ -59,6 +69,8 @@ handle_deploy (XdgAppSystemHelper *object, return TRUE; } + is_update = (arg_flags & XDG_APP_HELPER_DEPLOY_FLAGS_UPDATE) != 0; + deploy_dir = xdg_app_dir_get_if_deployed (system, arg_ref, NULL, NULL); @@ -68,7 +80,7 @@ handle_deploy (XdgAppSystemHelper *object, if (!is_update) { /* Can't install already installed app */ - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + g_dbus_method_invocation_return_error (invocation, XDG_APP_ERROR, XDG_APP_ERROR_ALREADY_INSTALLED, "%s is already installed", arg_ref); return TRUE; } @@ -76,7 +88,7 @@ handle_deploy (XdgAppSystemHelper *object, real_origin = xdg_app_dir_get_origin (system, arg_ref, NULL, NULL); if (real_origin == NULL || strcmp (real_origin, arg_origin) != 0) { - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "Wrong origin %s for update", arg_origin); return TRUE; } @@ -84,7 +96,7 @@ handle_deploy (XdgAppSystemHelper *object, else if (!deploy_dir && is_update) { /* Can't update not installed app */ - g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + g_dbus_method_invocation_return_error (invocation, XDG_APP_ERROR, XDG_APP_ERROR_ALREADY_INSTALLED, "%s is not installed", arg_ref); return TRUE; } @@ -96,6 +108,10 @@ handle_deploy (XdgAppSystemHelper *object, return TRUE; } + /* Work around ostree-pull spinning the default main context for the sync calls */ + main_context = g_main_context_new (); + g_main_context_push_thread_default (main_context); + if (!xdg_app_dir_pull_untrusted_local (system, arg_repo_path, arg_origin, arg_ref, @@ -103,11 +119,14 @@ handle_deploy (XdgAppSystemHelper *object, NULL, NULL, &error)) { + g_main_context_pop_thread_default (main_context); g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "Error pulling from repo: %s", error->message); return TRUE; } + g_main_context_pop_thread_default (main_context); + if (is_update) { /* TODO: This doesn't support a custom subpath */ @@ -137,6 +156,90 @@ handle_deploy (XdgAppSystemHelper *object, return TRUE; } + +static gboolean +xdg_app_authorize_method_handler (GDBusInterfaceSkeleton *interface, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + const gchar *method_name; + GVariant *parameters; + gboolean authorized; + const gchar *sender; + const gchar *action; + g_autoptr(PolkitSubject) subject = NULL; + g_autoptr(PolkitDetails) details = NULL; + g_autoptr(GError) error = NULL; + g_autoptr(PolkitAuthorizationResult) result = NULL; + + authorized = FALSE; + + method_name = g_dbus_method_invocation_get_method_name (invocation); + parameters = g_dbus_method_invocation_get_parameters (invocation); + + sender = g_dbus_method_invocation_get_sender (invocation); + subject = polkit_system_bus_name_new (sender); + + if (g_strcmp0 (method_name, "Deploy") == 0) + { + const char *ref, *origin; + guint32 flags; + gboolean is_update; + gboolean is_app; + + g_variant_get_child (parameters, 1, "u", &flags); + g_variant_get_child (parameters, 2, "&s", &ref); + g_variant_get_child (parameters, 3, "&s", &origin); + + is_update = (flags & XDG_APP_HELPER_DEPLOY_FLAGS_UPDATE) != 0; + is_app = g_str_has_prefix (ref, "app/"); + + if (is_update) + { + if (is_app) + action = "org.freedesktop.XdgApp.app-update"; + else + action = "org.freedesktop.XdgApp.runtime-update"; + } + else + { + if (is_app) + action = "org.freedesktop.XdgApp.app-install"; + else + action = "org.freedesktop.XdgApp.runtime-install"; + } + + details = polkit_details_new (); + polkit_details_insert (details, "origin", origin); + polkit_details_insert (details, "ref", ref); + + result = polkit_authority_check_authorization_sync (authority, subject, + action, details, + POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, + NULL, &error); + if (result == NULL) + { + g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Authorization error: %s", error->message); + return FALSE; + } + + if (polkit_authorization_result_get_is_authorized (result)) + authorized = TRUE; + } + + if (!authorized) + { + g_dbus_method_invocation_return_error (invocation, + G_IO_ERROR, + G_IO_ERROR_PERMISSION_DENIED, + "Operation not permitted"); + } + + return authorized; +} + + static void on_bus_acquired (GDBusConnection *connection, const gchar *name, @@ -147,8 +250,15 @@ on_bus_acquired (GDBusConnection *connection, helper = xdg_app_system_helper_skeleton_new (); + g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (helper), + G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD); + g_signal_connect (helper, "handle-deploy", G_CALLBACK (handle_deploy), NULL); + g_signal_connect (helper, "g-authorize-method", + G_CALLBACK (xdg_app_authorize_method_handler), + NULL); + if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (helper), connection, "/org/freedesktop/XdgApp/SystemHelper", @@ -181,6 +291,7 @@ main (int argc, guint owner_id; GMainLoop *loop; GBytes *introspection_bytes; + g_autoptr(GError) error = NULL; setlocale (LC_ALL, ""); @@ -188,6 +299,13 @@ main (int argc, g_set_prgname (argv[0]); + authority = polkit_authority_get_sync (NULL, &error); + if (authority == NULL) + { + g_printerr ("Can't get polkit authority: %s\n", error->message); + return 1; + } + introspection_bytes = g_resources_lookup_data ("/org/freedesktop/XdgApp/org.freedesktop.XdgApp.xml", 0, NULL); g_assert (introspection_bytes != NULL); |