Commit 58f04742 authored by David Zeuthen's avatar David Zeuthen
Browse files

add convenience API to consistently report authorization failures over D-Bus

parent 2b1a2a69
......@@ -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
* <literal>org.freedesktop.PolicyKit.Error.NotAuthorized</literal>
* 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 <literal>libpolkit-dbus</literal>.
*
* 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 <literal>libpolkit-dbus</literal>.
*
* 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;
}
......
......@@ -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 */
......@@ -86,6 +86,80 @@ out:
return action;
}
/**
* 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;
}
......
......@@ -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 */
......
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