diff --git a/0001-Add-support-for-the-org.freedesktop.policykit.imply-a.diff b/0001-Add-support-for-the-org.freedesktop.policykit.imply-a.diff new file mode 100644 index 0000000..94f1fff --- /dev/null +++ b/0001-Add-support-for-the-org.freedesktop.policykit.imply-a.diff @@ -0,0 +1,255 @@ +From 6bbd5189e967e8ddc36100bf22cd12bcb152ab5f Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Tue, 20 Sep 2011 14:13:12 -0400 +Subject: [PATCH 1/3] Add support for the org.freedesktop.policykit.imply annotation + +For example, GNOME control center can now defined e.g. + + + Meta Action + Example of a meta action, blabla + + no + no + auth_admin_keep + + org.freedesktop.udisks2.ata-smart-selftest org.freedesktop.udisks2.encrypted-lock-others org.freedesktop.udisks2.filesystem-unmount-others + + +and set up a single GtkLockButton for a PolkitPermission for action id +"org.zee.example.meta". + +When unlocked the given subject will now be authorized for the actions +mentioned in the annotation. + +Example test program: + +int +main (int argc, char *argv[]) +{ + PolkitSubject *subject; + GtkWidget *window; + GtkWidget *table; + GMainLoop *loop; + guint n; + + gtk_init (&argc, &argv); + + subject = polkit_unix_process_new (getpid ()); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + table = gtk_table_new (1, 2, FALSE); + for (n = 1; n < argc; n++) + { + const gchar *action_id = argv[n]; + GPermission *permission; + GtkWidget *label; + GtkWidget *lock_button; + GError *error = NULL; + + label = gtk_label_new (action_id); + + permission = polkit_permission_new_sync (action_id, subject, NULL, &error); + if (permission == NULL) + { + g_error ("Error constructing permission for action_id %s: %s (%s, %d)", + action_id, error->message, g_quark_to_string (error->domain), error->code); + goto out; + } + lock_button = gtk_lock_button_new (permission); + g_object_unref (permission); + + gtk_table_attach (GTK_TABLE (table), label, 0, 1, n - 1, n, GTK_FILL, GTK_FILL, 0, 0); + gtk_table_attach (GTK_TABLE (table), lock_button, 1, 2, n - 1, n, GTK_FILL, GTK_FILL, 0, 0); + } + gtk_container_add (GTK_CONTAINER (window), table); + + gtk_widget_show_all (window); + + loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (loop); + + out: + ; +} + +Compile with: + + gcc -o showpolkit showpolkit.c `pkg-config --cflags --libs polkit-gobject-1 gtk+-3.0` -g -O0 + +Run with: + + ./showpolkit org.freedesktop.udisks2.ata-smart-selftest org.freedesktop.udisks2.encrypted-lock-others org.freedesktop.udisks2.filesystem-unmount-others org.zee.example.meta + +Signed-off-by: David Zeuthen +--- + docs/man/polkit.xml | 25 +++++++- + .../polkitbackendinteractiveauthority.c | 67 ++++++++++++++++++++ + 2 files changed, 90 insertions(+), 2 deletions(-) + +diff --git a/docs/man/polkit.xml b/docs/man/polkit.xml +index bcb276b..bfa5ccd 100644 +--- a/docs/man/polkit.xml ++++ b/docs/man/polkit.xml +@@ -369,8 +369,7 @@ System Context | | + the key attribute and the value is + specified using the value attribute. This + element may appear zero or more times. See +- pkexec1 +- for an example of how this can be used. ++ below for known annotations. + + + vendor +@@ -398,6 +397,28 @@ System Context | | + pkaction1 + command. + ++ ++ Known annotations ++ ++ The org.freedesktop.policykit.exec.path ++ annotation is used by the pkexec program ++ shipped with PolicyKit - see the ++ pkexec1 ++ man page for details. ++ ++ ++ The org.freedesktop.policykit.imply ++ annotation (its value is a string containing a space separated ++ list of action identifiers) can be used to define meta ++ actions. The way it works is that if a subject is ++ authorized for an action with this annotation, then it is also ++ authorized for any action specified by the annotation. A typical ++ use of this annotation is when defining an UI shell with a ++ single lock button that should unlock multiple actions from ++ distinct mechanisms. ++ ++ ++ + + + AUTHOR +diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c +index 8b32459..3566248 100644 +--- a/src/polkitbackend/polkitbackendinteractiveauthority.c ++++ b/src/polkitbackend/polkitbackendinteractiveauthority.c +@@ -148,6 +148,7 @@ static PolkitAuthorizationResult *check_authorization_sync (PolkitBackendAuthori + PolkitDetails *details, + PolkitCheckAuthorizationFlags flags, + PolkitImplicitAuthorization *out_implicit_authorization, ++ gboolean checking_imply, + GError **error); + + static gboolean polkit_backend_interactive_authority_register_authentication_agent (PolkitBackendAuthority *authority, +@@ -890,6 +891,7 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority + details, + flags, + &implicit_authorization, ++ FALSE, /* checking_imply */ + &error); + if (error != NULL) + { +@@ -964,6 +966,7 @@ check_authorization_sync (PolkitBackendAuthority *authority, + PolkitDetails *details, + PolkitCheckAuthorizationFlags flags, + PolkitImplicitAuthorization *out_implicit_authorization, ++ gboolean checking_imply, + GError **error) + { + PolkitBackendInteractiveAuthority *interactive_authority; +@@ -979,12 +982,15 @@ check_authorization_sync (PolkitBackendAuthority *authority, + PolkitImplicitAuthorization implicit_authorization; + const gchar *tmp_authz_id; + PolkitDetails *result_details; ++ GList *actions; ++ GList *l; + + interactive_authority = POLKIT_BACKEND_INTERACTIVE_AUTHORITY (authority); + priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority); + + result = NULL; + ++ actions = NULL; + user_of_subject = NULL; + groups_of_user = NULL; + subject_str = NULL; +@@ -1095,6 +1101,64 @@ check_authorization_sync (PolkitBackendAuthority *authority, + goto out; + } + ++ /* then see if implied by another action that the subject is authorized for ++ * (but only one level deep to avoid infinite recursion) ++ * ++ * TODO: if this is slow, we can maintain a hash table for looking up what ++ * actions implies a given action ++ */ ++ if (!checking_imply) ++ { ++ actions = polkit_backend_action_pool_get_all_actions (priv->action_pool, NULL); ++ for (l = actions; l != NULL; l = l->next) ++ { ++ PolkitActionDescription *imply_ad = POLKIT_ACTION_DESCRIPTION (l->data); ++ const gchar *imply; ++ imply = polkit_action_description_get_annotation (imply_ad, "org.freedesktop.policykit.imply"); ++ if (imply != NULL) ++ { ++ gchar **tokens; ++ guint n; ++ tokens = g_strsplit (imply, " ", 0); ++ for (n = 0; tokens[n] != NULL; n++) ++ { ++ if (g_strcmp0 (tokens[n], action_id) == 0) ++ { ++ PolkitAuthorizationResult *implied_result = NULL; ++ PolkitImplicitAuthorization implied_implicit_authorization; ++ GError *implied_error = NULL; ++ const gchar *imply_action_id; ++ ++ imply_action_id = polkit_action_description_get_action_id (imply_ad); ++ ++ /* g_debug ("%s is implied by %s, checking", action_id, imply_action_id); */ ++ implied_result = check_authorization_sync (authority, caller, subject, ++ imply_action_id, ++ details, flags, ++ &implied_implicit_authorization, TRUE, ++ &implied_error); ++ if (implied_result != NULL) ++ { ++ if (polkit_authorization_result_get_is_authorized (implied_result)) ++ { ++ g_debug (" is authorized (implied by %s)", imply_action_id); ++ result = implied_result; ++ /* cleanup */ ++ g_object_unref (result_details); ++ g_strfreev (tokens); ++ goto out; ++ } ++ g_object_unref (implied_result); ++ } ++ if (implied_error != NULL) ++ g_error_free (implied_error); ++ } ++ } ++ g_strfreev (tokens); ++ } ++ } ++ } ++ + if (implicit_authorization != POLKIT_IMPLICIT_AUTHORIZATION_NOT_AUTHORIZED) + { + if (implicit_authorization == POLKIT_IMPLICIT_AUTHORIZATION_AUTHENTICATION_REQUIRED_RETAINED || +@@ -1118,6 +1182,9 @@ check_authorization_sync (PolkitBackendAuthority *authority, + g_debug (" not authorized"); + } + out: ++ g_list_foreach (actions, (GFunc) g_object_unref, NULL); ++ g_list_free (actions); ++ + g_free (subject_str); + + g_list_foreach (groups_of_user, (GFunc) g_object_unref, NULL); +-- +1.7.3.4 + diff --git a/0002-Add-no-debug-option-and-use-this-for-D-Bus-activation.diff b/0002-Add-no-debug-option-and-use-this-for-D-Bus-activation.diff new file mode 100644 index 0000000..c7ee5b7 --- /dev/null +++ b/0002-Add-no-debug-option-and-use-this-for-D-Bus-activation.diff @@ -0,0 +1,77 @@ +From 3811e51b81320a574bb31aa64b6af56340012527 Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Tue, 18 Oct 2011 13:13:16 -0400 +Subject: [PATCH 2/3] Add --no-debug option and use this for D-Bus activation + +Signed-off-by: David Zeuthen +--- + data/org.freedesktop.PolicyKit1.service.in | 2 +- + src/polkitd/main.c | 27 ++++++++++++++++++++++++++- + 2 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/data/org.freedesktop.PolicyKit1.service.in b/data/org.freedesktop.PolicyKit1.service.in +index 5a54ca1..b6cd02b 100644 +--- a/data/org.freedesktop.PolicyKit1.service.in ++++ b/data/org.freedesktop.PolicyKit1.service.in +@@ -1,4 +1,4 @@ + [D-BUS Service] + Name=org.freedesktop.PolicyKit1 +-Exec=@libexecdir@/polkitd ++Exec=@libexecdir@/polkitd --no-debug + User=root +diff --git a/src/polkitd/main.c b/src/polkitd/main.c +index 33ea511..b21723f 100644 +--- a/src/polkitd/main.c ++++ b/src/polkitd/main.c +@@ -22,6 +22,9 @@ + #include "config.h" + + #include ++ ++#include ++ + #include + #include + +@@ -33,8 +36,10 @@ static PolkitBackendAuthority *authority = NULL; + static gpointer registration_id = NULL; + static GMainLoop *loop = NULL; + static gboolean opt_replace = FALSE; ++static gboolean opt_no_debug = FALSE; + static GOptionEntry opt_entries[] = { +- {"replace", 0, 0, G_OPTION_ARG_NONE, &opt_replace, "Replace existing daemon", NULL}, ++ {"replace", 'r', 0, G_OPTION_ARG_NONE, &opt_replace, "Replace existing daemon", NULL}, ++ {"no-debug", 'n', 0, G_OPTION_ARG_NONE, &opt_no_debug, "Don't print debug information", NULL}, + {NULL } + }; + +@@ -120,6 +125,26 @@ main (int argc, + goto out; + } + ++ /* If --no-debug is requested don't clutter stdout/stderr etc. ++ */ ++ if (opt_no_debug) ++ { ++ gint dev_null_fd; ++ dev_null_fd = open ("/dev/null", O_RDWR); ++ if (dev_null_fd >= 0) ++ { ++ dup2 (dev_null_fd, STDIN_FILENO); ++ dup2 (dev_null_fd, STDOUT_FILENO); ++ dup2 (dev_null_fd, STDERR_FILENO); ++ close (dev_null_fd); ++ } ++ else ++ { ++ g_warning ("Error opening /dev/null: %m"); ++ } ++ } ++ ++ + loop = g_main_loop_new (NULL, FALSE); + + sigint_id = _g_posix_signal_watch_add (SIGINT, +-- +1.7.3.4 + diff --git a/0003-Bug-41025-Add-org.freedesktop.policykit.owner-annotat.diff b/0003-Bug-41025-Add-org.freedesktop.policykit.owner-annotat.diff new file mode 100644 index 0000000..f52fbea --- /dev/null +++ b/0003-Bug-41025-Add-org.freedesktop.policykit.owner-annotat.diff @@ -0,0 +1,161 @@ +From 5cd68a3aa8d5d0fdbbd3baef0601350bd43a0e4d Mon Sep 17 00:00:00 2001 +From: David Zeuthen +Date: Tue, 18 Oct 2011 15:45:40 -0400 +Subject: [PATCH 3/3] =?UTF-8?q?Bug=2041025=20=E2=80=93=20Add=20org.freedesktop.policykit.owner=20annotation?= +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This allows daemons running as a designated uid to check +authorizations. Based on a patch from Christopher James Halse Rogers +. + +https://bugs.freedesktop.org/show_bug.cgi?id=41025 + +Signed-off-by: David Zeuthen +--- + docs/man/polkit.xml | 13 +++ + .../polkitbackendinteractiveauthority.c | 81 +++++++++++++++++-- + 2 files changed, 85 insertions(+), 9 deletions(-) + +diff --git a/docs/man/polkit.xml b/docs/man/polkit.xml +index bfa5ccd..ae67f7c 100644 +--- a/docs/man/polkit.xml ++++ b/docs/man/polkit.xml +@@ -417,6 +417,19 @@ System Context | | + single lock button that should unlock multiple actions from + distinct mechanisms. + ++ ++ The org.freedesktop.policykit.owner ++ annotation can be used to define a set of users who can query ++ whether a client is authorized to perform this action. If this ++ annotation is not specified then only root can query whether a ++ client running as a different user is authorized for an action. ++ The value of this annotation is a string containing a space ++ separated list of PolkitIdentity entries, ++ for example "unix-user:42 unix-user:colord". ++ A typical use of this annotation is for a daemon process that ++ runs as a system user rather than root. ++ + + + +diff --git a/src/polkitbackend/polkitbackendinteractiveauthority.c b/src/polkitbackend/polkitbackendinteractiveauthority.c +index 3566248..99c4782 100644 +--- a/src/polkitbackend/polkitbackendinteractiveauthority.c ++++ b/src/polkitbackend/polkitbackendinteractiveauthority.c +@@ -749,6 +749,62 @@ polkit_backend_interactive_authority_check_authorization_finish (PolkitBackendAu + return result; + } + ++static gboolean ++may_identity_check_authorization (PolkitBackendInteractiveAuthority *interactive_authority, ++ const gchar *action_id, ++ PolkitIdentity *identity) ++{ ++ PolkitBackendInteractiveAuthorityPrivate *priv = POLKIT_BACKEND_INTERACTIVE_AUTHORITY_GET_PRIVATE (interactive_authority); ++ gboolean ret = FALSE; ++ PolkitActionDescription *action_desc = NULL; ++ const gchar *owners = NULL; ++ gchar **tokens = NULL; ++ guint n; ++ ++ /* uid 0 may check anything */ ++ if (POLKIT_IS_UNIX_USER (identity) && polkit_unix_user_get_uid (POLKIT_UNIX_USER (identity)) == 0) ++ { ++ ret = TRUE; ++ goto out; ++ } ++ ++ action_desc = polkit_backend_action_pool_get_action (priv->action_pool, action_id, NULL); ++ if (action_desc == NULL) ++ goto out; ++ ++ owners = polkit_action_description_get_annotation (action_desc, "org.freedesktop.policykit.owner"); ++ if (owners == NULL) ++ goto out; ++ ++ tokens = g_strsplit (owners, " ", 0); ++ for (n = 0; tokens != NULL && tokens[n] != NULL; n++) ++ { ++ PolkitIdentity *owner_identity; ++ GError *error = NULL; ++ owner_identity = polkit_identity_from_string (tokens[n], &error); ++ if (owner_identity == NULL) ++ { ++ g_warning ("Error parsing owner identity %d of action_id %s: %s (%s, %d)", ++ n, action_id, error->message, g_quark_to_string (error->domain), error->code); ++ g_error_free (error); ++ continue; ++ } ++ if (polkit_identity_equal (identity, owner_identity)) ++ { ++ ret = TRUE; ++ g_object_unref (owner_identity); ++ goto out; ++ } ++ g_object_unref (owner_identity); ++ } ++ ++ out: ++ g_clear_object (&action_desc); ++ g_strfreev (tokens); ++ ++ return ret; ++} ++ + static void + polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority *authority, + PolkitSubject *caller, +@@ -851,22 +907,29 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority + g_strfreev (detail_keys); + } + } ++ ++ /* Not anyone is allowed to check that process XYZ is allowed to do ABC. ++ * We only allow this if, and only if, ++ * ++ * - processes may check for another process owned by the *same* user but not ++ * if details are passed (otherwise you'd be able to spoof the dialog) ++ * ++ * - processes running as uid 0 may check anything and pass any details ++ * ++ * - if the action_id has the "org.freedesktop.policykit.owner" annotation ++ * then any uid referenced by that annotation is also allowed to check ++ * to check anything and pass any details ++ */ + if (!polkit_identity_equal (user_of_caller, user_of_subject) || has_details) + { +- /* we only allow trusted callers (uid 0 + others) to check authorizations for subjects +- * they don't own - and only if there are no details passed (to avoid spoofing dialogs). +- * +- * TODO: allow other uids like 'haldaemon'? +- */ +- if (!POLKIT_IS_UNIX_USER (user_of_caller) || +- polkit_unix_user_get_uid (POLKIT_UNIX_USER (user_of_caller)) != 0) ++ if (!may_identity_check_authorization (interactive_authority, action_id, user_of_caller)) + { + if (has_details) + { + g_simple_async_result_set_error (simple, + POLKIT_ERROR, + POLKIT_ERROR_NOT_AUTHORIZED, +- "Only trusted callers (e.g. uid 0) can use CheckAuthorization() and " ++ "Only trusted callers (e.g. uid 0 or an action owner) can use CheckAuthorization() and " + "pass details"); + } + else +@@ -874,7 +937,7 @@ polkit_backend_interactive_authority_check_authorization (PolkitBackendAuthority + g_simple_async_result_set_error (simple, + POLKIT_ERROR, + POLKIT_ERROR_NOT_AUTHORIZED, +- "Only trusted callers (e.g. uid 0) can use CheckAuthorization() for " ++ "Only trusted callers (e.g. uid 0 or an action owner) can use CheckAuthorization() for " + "subjects belonging to other identities"); + } + g_simple_async_result_complete (simple); +-- +1.7.3.4 + diff --git a/polkit.changes b/polkit.changes index ef8de46..b2cd1e0 100644 --- a/polkit.changes +++ b/polkit.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Wed Nov 2 10:30:03 UTC 2011 - lnussel@suse.de + +- pick some patches from git to add support for + org.freedesktop.policykit.imply, disable debug spam and allow + unprivileged users to query authorizations (bnc#698250) + ------------------------------------------------------------------- Fri Sep 2 10:42:54 UTC 2011 - vuntz@opensuse.org diff --git a/polkit.spec b/polkit.spec index eb68ff4..b7cb4a7 100644 --- a/polkit.spec +++ b/polkit.spec @@ -27,6 +27,12 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build Group: System/Libraries Source0: http://hal.freedesktop.org/releases/%{name}-%{version}.tar.gz Source99: baselibs.conf +# PATCH-FIX-UPSTREAM Add support for the org.freedesktop.policykit.imply annotation +Patch0: 0001-Add-support-for-the-org.freedesktop.policykit.imply-a.diff +# PATCH-FIX-UPSTREAM Add --no-debug option and use this for D-Bus activation +Patch1: 0002-Add-no-debug-option-and-use-this-for-D-Bus-activation.diff +# PATCH-FIX-UPSTREAM allow unprivileged users to check authorizations +Patch2: 0003-Bug-41025-Add-org.freedesktop.policykit.owner-annotat.diff BuildRequires: glib2-devel >= 2.25.12 BuildRequires: gobject-introspection-devel >= 0.6.2 BuildRequires: gtk-doc @@ -87,6 +93,9 @@ This package contains the libraries only. %prep %setup -q +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 %build export V=1