From 58f0474286541970f6b535189514d706d9985cc2 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Wed, 27 Feb 2008 20:05:30 -0500 Subject: [PATCH] add convenience API to consistently report authorization failures over D-Bus --- src/polkit-dbus/polkit-simple.c | 153 ++++++++++++++++++++++++++++++++++++++++ src/polkit-dbus/polkit-simple.h | 3 + src/polkit/polkit-action.c | 94 +++++++++++++++++++++++- src/polkit/polkit-action.h | 5 ++ 4 files changed, 253 insertions(+), 2 deletions(-) diff --git a/src/polkit-dbus/polkit-simple.c b/src/polkit-dbus/polkit-simple.c index 4654cdf..d815046 100644 --- a/src/polkit-dbus/polkit-simple.c +++ b/src/polkit-dbus/polkit-simple.c @@ -398,11 +398,164 @@ out: } +/** + * polkit_dbus_error_generate: + * @action: the action that the caller needs an authorization for + * @result: the result from e.g. polkit_context_is_caller_authorized() + * @error: the #DBusError to set + * + * Convenience function to generate a #DBusError that encapsulates + * information that the caller is not authorized. This includes + * information such as @action that describes what action the caller + * lacks an authorization for, as well as @result that describes if + * the caller can obtain an authorization through authentication. + * + * Typically a privileged mechanism uses this function to generate + * errors. At the other end of the wire, the caller can use + * polkit_dbus_error_parse() to extract @action and @result. + * + * The form of the #DBusError is as follows. The name is + * set to + * org.freedesktop.PolicyKit.Error.NotAuthorized + * and the message consists of two strings separated by a single + * space: the string representation of the action + * (cf. polkit_action_to_string_representation()) and the string + * representation of the result + * (cf. polkit_result_to_string_representation()). + * + * This function is in libpolkit-dbus. + * + * Returns: TRUE if @error was set. FALSE on error or OOM. + * + * Since: 0.8 + */ +polkit_bool_t +polkit_dbus_error_generate (PolKitAction *action, PolKitResult result, DBusError *error) +{ + polkit_bool_t ret; + const char *action_str; + const char *result_str; + + ret = FALSE; + + kit_return_val_if_fail (error != NULL && !dbus_error_is_set (error), FALSE); + kit_return_val_if_fail (action != NULL && polkit_action_validate (action), FALSE); + + action_str = polkit_action_to_string_representation (action); + if (action_str == NULL) + goto out; + + result_str = polkit_result_to_string_representation (result); + if (result_str == NULL) + goto out; + + dbus_set_error (error, + "org.freedesktop.PolicyKit.Error.NotAuthorized", + "%s %s", + action_str, result_str); + + /* on OOM, error->name and error->message are set to preallocated strings */ + if (strcmp (error->name, "org.freedesktop.PolicyKit.Error.NotAuthorized") != 0) + goto out; + + ret = TRUE; + +out: + return ret; +} + +/** + * polkit_dbus_error_parse: + * @error: error to parse; must be set + * @action: return location for #PolKitAction object + * @result: return location for #PolKitResult variable + * + * Parse an error received over D-Bus, typically generated by + * polkit_dbus_error_generate(), into what action an authorization is + * missing for and whether that authorization can be obtained. + * + * This function is in libpolkit-dbus. + * + * Returns: TRUE only if @error was successfully parsed and @action + * and @result is set (and caller must free @action using + * polkit_action_unref()). + * + * Since: 0.8 + */ +polkit_bool_t +polkit_dbus_error_parse (DBusError *error, PolKitAction **action, PolKitResult *result) +{ + char **tokens; + size_t num_tokens; + polkit_bool_t ret; + + kit_return_val_if_fail (error != NULL && dbus_error_is_set (error), FALSE); + kit_return_val_if_fail (action != NULL, FALSE); + kit_return_val_if_fail (result != NULL, FALSE); + + ret = FALSE; + tokens = NULL; + *action = NULL; + + if (!dbus_error_has_name (error, "org.freedesktop.PolicyKit.Error.NotAuthorized")) + goto out; + + tokens = kit_strsplit (error->message, ' ', &num_tokens); + if (tokens == NULL || num_tokens != 2) + goto out; + + *action = polkit_action_new_from_string_representation (tokens[0]); + if (*action == NULL) + goto out; + + if (!polkit_result_from_string_representation (tokens[1], result)) { + polkit_action_unref (*action); + *action = NULL; + goto out; + } + + ret = TRUE; + +out: + if (!ret) + *result = POLKIT_RESULT_UNKNOWN; + + + if (tokens != NULL) + kit_strfreev (tokens); + + return ret; +} + #ifdef POLKIT_BUILD_TESTS static polkit_bool_t _run_test (void) { + PolKitAction *a; + PolKitResult r; + + a = polkit_action_new (); + r = POLKIT_RESULT_ONLY_VIA_SELF_AUTH; + if (a != NULL) { + if (polkit_action_set_action_id (a, "org.example.foo")) { + DBusError error; + + dbus_error_init (&error); + if (polkit_dbus_error_generate (a, r, &error)) { + PolKitAction *a2; + PolKitResult r2; + + if (polkit_dbus_error_parse (&error, &a2, &r2)) { + kit_assert (polkit_action_equal (a, a2)); + kit_assert (r == r2); + polkit_action_unref (a2); + } + } + } + polkit_action_unref (a); + } + return TRUE; } diff --git a/src/polkit-dbus/polkit-simple.h b/src/polkit-dbus/polkit-simple.h index a84e47d..0aff3d4 100644 --- a/src/polkit-dbus/polkit-simple.h +++ b/src/polkit-dbus/polkit-simple.h @@ -43,6 +43,9 @@ polkit_uint64_t polkit_check_authv (pid_t pid, const char **action_ids); polkit_bool_t polkit_auth_obtain (const char *action_id, polkit_uint32_t xid, pid_t pid, DBusError *error); +polkit_bool_t polkit_dbus_error_generate (PolKitAction *action, PolKitResult result, DBusError *error); +polkit_bool_t polkit_dbus_error_parse (DBusError *error, PolKitAction **action, PolKitResult *result); + POLKIT_END_DECLS #endif /* POLKIT_SIMPLE_H */ diff --git a/src/polkit/polkit-action.c b/src/polkit/polkit-action.c index 1292de2..6a81e6a 100644 --- a/src/polkit/polkit-action.c +++ b/src/polkit/polkit-action.c @@ -87,6 +87,80 @@ out: } /** + * polkit_action_to_string_representation: + * @action: the action object + * + * Serializes @action into a textual form that can be transferred from + * process to process or saved on disk. Use + * polkit_action_new_from_string_representation() to deserialize it. + * + * Returns: A string representation of @action or #NULL if the action + * is not valid. String is valid until @action is freed. + * + * Since: 0.8 + */ +const char * +polkit_action_to_string_representation (PolKitAction *action) +{ + kit_return_val_if_fail (action != NULL, NULL); + kit_return_val_if_fail (polkit_action_validate_id (action->id), NULL); + return action->id; +} + +/** + * polkit_action_new_from_string_representation: + * @str: textual representation of an action; typically obtained from + * polkit_action_to_string_representation() + * + * Creates a new #PolKitAction object from a textual representation. + * + * Returns: A new #PolKitAction object or #NULL if OOM or if the + * representation isn't valid. Caller must free this object with + * polkit_action_unref(). + * + * Since: 0.8 + */ +PolKitAction * +polkit_action_new_from_string_representation (const char *str) +{ + PolKitAction *action; + + kit_return_val_if_fail (str != NULL, NULL); + + action = polkit_action_new (); + if (action == NULL) + goto out; + + if (!polkit_action_set_action_id (action, str)) { + polkit_action_unref (action); + action = NULL; + } +out: + return action; +} + +/** + * polkit_action_equal: + * @a: first action + * @b: second action + * + * Test if @a and @b refer to the same action. + * + * Returns: #TRUE iff @a and @b refer to the same action. + * + * Since: 0.8 + */ +polkit_bool_t +polkit_action_equal (PolKitAction *a, PolKitAction *b) +{ + kit_return_val_if_fail (a != NULL && polkit_action_validate (a), FALSE); + kit_return_val_if_fail (b != NULL && polkit_action_validate (b), FALSE); + + return strcmp (a->id, b->id) == 0; +} + + +/** * polkit_action_ref: * @action: the action object * @@ -241,6 +315,8 @@ polkit_action_validate (PolKitAction *action) static polkit_bool_t _run_test (void) { + PolKitAction *a; + char *s; int n; char *valid_action_ids[] = {"org.example.action", "org.example.action-foo", @@ -263,8 +339,6 @@ _run_test (void) kit_assert (! polkit_action_validate_id (invalid_action_ids[n])); } - PolKitAction *a; - char *s; a = polkit_action_new (); if (a == NULL) { /* OOM */ @@ -294,6 +368,22 @@ _run_test (void) polkit_action_unref (a); } + a = polkit_action_new (); + if (a != NULL) { + if (polkit_action_set_action_id (a, "org.example.foo")) { + const char *action_str; + PolKitAction *a2; + + action_str = polkit_action_to_string_representation (a); + kit_assert (action_str != NULL); + a2 = polkit_action_new_from_string_representation (action_str); + if (a2 != NULL) { + kit_assert (polkit_action_equal (a, a2)); + polkit_action_unref (a2); + } + } + polkit_action_unref (a); + } return TRUE; } diff --git a/src/polkit/polkit-action.h b/src/polkit/polkit-action.h index 08b51c3..be2e807 100644 --- a/src/polkit/polkit-action.h +++ b/src/polkit/polkit-action.h @@ -52,6 +52,11 @@ polkit_bool_t polkit_action_validate (PolKitAction *action); polkit_bool_t polkit_action_validate_id (const char *action_id); +polkit_bool_t polkit_action_equal (PolKitAction *a, PolKitAction *b); + +const char *polkit_action_to_string_representation (PolKitAction *action); +PolKitAction *polkit_action_new_from_string_representation (const char *str); + POLKIT_END_DECLS #endif /* POLKIT_ACTION_H */ -- 2.7.4