diff --git a/Makefile-daemon.am b/Makefile-daemon.am
index 6a5f24b0..9e86f44b 100644
--- a/Makefile-daemon.am
+++ b/Makefile-daemon.am
@@ -105,8 +105,12 @@ servicedir = $(dbusservicedir)
%.service: %.service.in Makefile
$(SED_SUBST) $@.in > $@.tmp && mv $@.tmp $@
+polkit_policy_DATA = $(srcdir)/src/daemon/org.projectatomic.rpmostree1.policy
+polkit_policydir = $(datadir)/polkit-1/actions
+
EXTRA_DIST += \
$(dbusservice_DATA) \
+ $(polkit_policy_DATA) \
$(service_in_files) \
$(systemdunit_in_files) \
$(NULL)
diff --git a/configure.ac b/configure.ac
index a7c91d20..eb42a202 100644
--- a/configure.ac
+++ b/configure.ac
@@ -88,6 +88,7 @@ PKG_CHECK_MODULES(PKGDEP_GIO_UNIX, [gio-unix-2.0])
PKG_CHECK_MODULES(PKGDEP_RPMOSTREE, [gio-unix-2.0 >= 2.40.0 json-glib-1.0
ostree-1 >= 2017.4
libsystemd
+ polkit-gobject-1
rpm librepo
libarchive])
dnl bundled libdnf
diff --git a/packaging/rpm-ostree.spec.in b/packaging/rpm-ostree.spec.in
index 32dead5f..fd78b1ed 100644
--- a/packaging/rpm-ostree.spec.in
+++ b/packaging/rpm-ostree.spec.in
@@ -21,6 +21,7 @@ BuildRequires: pkgconfig(json-glib-1.0)
BuildRequires: pkgconfig(rpm)
BuildRequires: pkgconfig(libarchive)
BuildRequires: pkgconfig(libsystemd)
+BuildRequires: pkgconfig(polkit-gobject-1)
BuildRequires: libcap-devel
BuildRequires: libattr-devel
@@ -115,7 +116,8 @@ python autofiles.py > files \
'%{_sysconfdir}/dbus-1/system.d/*' \
'%{_prefix}/lib/systemd/system/*' \
'%{_libexecdir}/rpm-ostree*' \
- '%{_datadir}/dbus-1/system-services'
+ '%{_datadir}/dbus-1/system-services' \
+ '%{_datadir}/polkit-1/actions/org.projectatomic.rpmostree1.policy'
python autofiles.py > files.devel \
'%{_libdir}/lib*.so' \
'%{_includedir}/*' \
diff --git a/src/daemon/org.projectatomic.rpmostree1.conf b/src/daemon/org.projectatomic.rpmostree1.conf
index a1ae0be8..f4a1e8df 100644
--- a/src/daemon/org.projectatomic.rpmostree1.conf
+++ b/src/daemon/org.projectatomic.rpmostree1.conf
@@ -10,12 +10,16 @@
+
+
+
@@ -27,6 +31,9 @@
send_interface="org.freedesktop.DBus.Properties"
send_member="GetAll"/>
+
+
diff --git a/src/daemon/org.projectatomic.rpmostree1.policy b/src/daemon/org.projectatomic.rpmostree1.policy
new file mode 100644
index 00000000..e5053e1b
--- /dev/null
+++ b/src/daemon/org.projectatomic.rpmostree1.policy
@@ -0,0 +1,120 @@
+
+
+
+
+ Project Atomic
+ https://www.projectatomic.io/
+ package-x-generic
+
+
+ Install and remove packages
+ Authentication is required to install and remove software
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+
+
+
+ Install local packages
+ Authentication is required to install software
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+
+
+
+ Override packages
+ Authentication is required to override base OS software
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+
+
+
+ Update base OS
+ Authentication is required to update software
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+
+
+
+ Update base OS
+ Authentication is required to update software
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+
+
+
+ Switch to a different base OS
+ Authentication is required to switch to a different base OS
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+
+
+
+ Rollback OS updates
+ Authentication is required to roll back software updates
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+
+
+
+ Change boot configuration
+ Authentication is required to change boot configuration
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+
+
+
+ Clear cache
+ Authentication is required to clear cache / pending data
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+
+
+
+ Refresh repository metadata
+ Authentication is required to check available updates
+ package-x-generic
+
+ auth_admin
+ auth_admin
+ auth_admin_keep
+
+
+
diff --git a/src/daemon/rpmostreed-os.c b/src/daemon/rpmostreed-os.c
index 5a38084a..7db16bb0 100644
--- a/src/daemon/rpmostreed-os.c
+++ b/src/daemon/rpmostreed-os.c
@@ -19,7 +19,9 @@
#include "config.h"
#include "ostree.h"
+#include
#include
+#include
#include "rpmostreed-sysroot.h"
#include "rpmostreed-daemon.h"
@@ -40,6 +42,7 @@ typedef struct _RpmostreedOSClass RpmostreedOSClass;
struct _RpmostreedOS
{
RPMOSTreeOSSkeleton parent_instance;
+ PolkitAuthority *authority;
RpmostreedTransactionMonitor *transaction_monitor;
guint signal_id;
};
@@ -53,6 +56,10 @@ static void rpmostreed_os_iface_init (RPMOSTreeOSIface *iface);
static gboolean rpmostreed_os_load_internals (RpmostreedOS *self, GError **error);
+static inline void *vardict_lookup_ptr (GVariantDict *dict, const char *key, const char *fmt);
+
+static gboolean vardict_lookup_bool (GVariantDict *dict, const char *key, gboolean dfault);
+
G_DEFINE_TYPE_WITH_CODE (RpmostreedOS,
rpmostreed_os,
RPMOSTREE_TYPE_OS_SKELETON,
@@ -77,6 +84,146 @@ sysroot_changed (RpmostreedSysroot *sysroot,
g_warning ("%s", local_error->message);
}
+static gboolean
+os_authorize_method (GDBusInterfaceSkeleton *interface,
+ GDBusMethodInvocation *invocation)
+{
+ RpmostreedOS *self = RPMOSTREED_OS (interface);
+ const gchar *method_name = g_dbus_method_invocation_get_method_name (invocation);
+ const gchar *sender = g_dbus_method_invocation_get_sender (invocation);
+ GVariant *parameters = g_dbus_method_invocation_get_parameters (invocation);
+ g_autoptr(GPtrArray) actions = g_ptr_array_new ();
+ gboolean authorized = FALSE;
+
+ if (g_strcmp0 (method_name, "GetDeploymentsRpmDiff") == 0 ||
+ g_strcmp0 (method_name, "GetCachedDeployRpmDiff") == 0 ||
+ g_strcmp0 (method_name, "DownloadDeployRpmDiff") == 0 ||
+ g_strcmp0 (method_name, "GetCachedUpdateRpmDiff") == 0 ||
+ g_strcmp0 (method_name, "DownloadUpdateRpmDiff") == 0 ||
+ g_strcmp0 (method_name, "GetCachedRebaseRpmDiff") == 0 ||
+ g_strcmp0 (method_name, "DownloadRebaseRpmDiff") == 0)
+ {
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.repo-refresh");
+ }
+ else if (g_strcmp0 (method_name, "Deploy") == 0)
+ {
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.deploy");
+ }
+ else if (g_strcmp0 (method_name, "Upgrade") == 0)
+ {
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.upgrade");
+ }
+ else if (g_strcmp0 (method_name, "Rebase") == 0)
+ {
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.rebase");
+ }
+ else if (g_strcmp0 (method_name, "SetInitramfsState") == 0)
+ {
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.bootconfig");
+ }
+ else if (g_strcmp0 (method_name, "Cleanup") == 0)
+ {
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.cleanup");
+ }
+ else if (g_strcmp0 (method_name, "Rollback") == 0 ||
+ g_strcmp0 (method_name, "ClearRollbackTarget") == 0)
+ {
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.rollback");
+ }
+ else if (g_strcmp0 (method_name, "PkgChange") == 0)
+ {
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.install-uninstall-packages");
+ }
+ else if (g_strcmp0 (method_name, "UpdateDeployment") == 0)
+ {
+ g_autoptr(GVariant) modifiers = g_variant_get_child_value (parameters, 0);
+ g_autoptr(GVariant) options = g_variant_get_child_value (parameters, 1);
+ g_auto(GVariantDict) modifiers_dict;
+ g_auto(GVariantDict) options_dict;
+ g_variant_dict_init (&modifiers_dict, modifiers);
+ g_variant_dict_init (&options_dict, options);
+ const char *refspec =
+ vardict_lookup_ptr (&modifiers_dict, "set-refspec", "&s");
+ const char *revision =
+ vardict_lookup_ptr (&modifiers_dict, "set-revision", "&s");
+ g_autofree char **install_pkgs =
+ vardict_lookup_ptr (&modifiers_dict, "install-packages", "^a&s");
+ g_autofree char **uninstall_pkgs =
+ vardict_lookup_ptr (&modifiers_dict, "uninstall-packages", "^a&s");
+ g_autofree const char *const *override_replace_pkgs =
+ vardict_lookup_ptr (&modifiers_dict, "override-replace-packages", "^a&s");
+ g_autofree const char *const *override_remove_pkgs =
+ vardict_lookup_ptr (&modifiers_dict, "override-remove-packages", "^a&s");
+ g_autofree const char *const *override_reset_pkgs =
+ vardict_lookup_ptr (&modifiers_dict, "override-reset-packages", "^a&s");
+ g_autoptr(GVariant) install_local_pkgs =
+ g_variant_dict_lookup_value (&modifiers_dict, "install-local-packages",
+ G_VARIANT_TYPE("ah"));
+ g_autoptr(GVariant) override_replace_local_pkgs =
+ g_variant_dict_lookup_value (&modifiers_dict, "override-replace-local-packages",
+ G_VARIANT_TYPE("ah"));
+ gboolean no_pull_base =
+ vardict_lookup_bool (&options_dict, "no-pull-base", FALSE);
+ gboolean no_overrides =
+ vardict_lookup_bool (&options_dict, "no-overrides", FALSE);
+
+ if (refspec != NULL)
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.rebase");
+ else if (revision != NULL)
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.deploy");
+ else if (!no_pull_base)
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.upgrade");
+
+ if (install_pkgs != NULL || uninstall_pkgs != NULL)
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.install-uninstall-packages");
+
+ if (install_local_pkgs != NULL && g_variant_n_children (install_local_pkgs) > 0)
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.install-local-packages");
+
+ if (override_replace_pkgs != NULL || override_remove_pkgs != NULL || override_reset_pkgs != NULL ||
+ (override_replace_local_pkgs != NULL && g_variant_n_children (override_replace_local_pkgs) > 0) ||
+ no_overrides)
+ g_ptr_array_add (actions, "org.projectatomic.rpmostree1.override");
+ }
+ else
+ {
+ authorized = FALSE;
+ }
+
+ for (guint i = 0; i < actions->len; i++)
+ {
+ const gchar *action = g_ptr_array_index (actions, i);
+ glnx_unref_object PolkitSubject *subject = polkit_system_bus_name_new (sender);
+ glnx_unref_object PolkitAuthorizationResult *result = NULL;
+ g_autoptr(GError) error = NULL;
+
+ result = polkit_authority_check_authorization_sync (self->authority, subject,
+ action, NULL,
+ 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;
+ }
+
+ authorized = polkit_authorization_result_get_is_authorized (result);
+ if (!authorized)
+ break;
+ }
+
+ if (!authorized)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ "rpmostreed OS operation %s not allowed for user", method_name);
+ }
+
+ return authorized;
+}
+
static void
os_dispose (GObject *object)
{
@@ -90,6 +237,7 @@ os_dispose (GObject *object)
object_path, object);
}
+ g_clear_object (&self->authority);
g_clear_object (&self->transaction_monitor);
if (self->signal_id > 0)
@@ -104,9 +252,13 @@ static void
os_constructed (GObject *object)
{
RpmostreedOS *self = RPMOSTREED_OS (object);
+ g_autoptr(GError) error = NULL;
- /* TODO Integrate with PolicyKit via the "g-authorize-method" signal. */
-
+ self->authority = polkit_authority_get_sync (NULL, &error);
+ if (self->authority == NULL)
+ {
+ errx (1, "Can't get polkit authority: %s", error->message);
+ }
self->signal_id = g_signal_connect (rpmostreed_sysroot_get (),
"updated",
G_CALLBACK (sysroot_changed), self);
@@ -117,11 +269,14 @@ static void
rpmostreed_os_class_init (RpmostreedOSClass *klass)
{
GObjectClass *gobject_class;
+ GDBusInterfaceSkeletonClass *gdbus_interface_skeleton_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = os_dispose;
gobject_class->constructed = os_constructed;
+ gdbus_interface_skeleton_class = G_DBUS_INTERFACE_SKELETON_CLASS (klass);
+ gdbus_interface_skeleton_class->g_authorize_method = os_authorize_method;
}
static void