PolicyKit: Branch 'master'

David Zeuthen david at kemper.freedesktop.org
Mon Nov 19 20:25:44 PST 2007


 doc/man/polkit-auth.xml                          |   19 ++
 src/polkit-dbus/polkit-simple.c                  |    2 
 src/polkit-grant/polkit-authorization-db-write.c |  145 ++++++++++++++++-----
 src/polkit-grant/polkit-explicit-grant-helper.c  |   33 +++-
 src/polkit-grant/polkit-revoke-helper.c          |    9 -
 src/polkit/polkit-authorization-db.c             |  156 +++++++++++++++++++++--
 src/polkit/polkit-authorization-db.h             |   17 ++
 src/polkit/polkit-authorization.c                |   19 ++
 src/polkit/polkit-authorization.h                |    3 
 src/polkit/polkit-context.c                      |   38 +++--
 tools/polkit-auth.c                              |   57 ++++++--
 tools/polkit-bash-completion.sh                  |   12 -
 12 files changed, 414 insertions(+), 96 deletions(-)

New commits:
commit 45f52acbfd1d898e37f4ccaa830d6425fa4bc2da
Author: David Zeuthen <davidz at redhat.com>
Date:   Mon Nov 19 23:25:30 2007 -0500

    add support for negative authorizations
    
    Negative authorizations is a way to block an entity; previously the
    algorithm was something like (ignoring the config file for now)
    
      Result is_authorized() {
        res = has_implicit_auth();
        if (res == YES) {
          return YES;
        } else if (has_explicit_auth()) {
          return YES;
        }
        return res;
      }
    
    Now it's
    
      Result is_authorized() {
        res = has_implicit_auth();
        expl = has_explicit_auth();
        is_blocked = has_negative_explicit_auth();
    
        if (is_blocked)
          return NO;
    
        if (res == YES) {
          return YES;
        } else if (has_explicit_auth()) {
          return YES;
        }
        return res;
      }
    
    E.g. just a single negative auth will force NO to be returned. I
    really, really need to write into the spec how this works; my mental
    L1 cache can't contain it anymore. Once it's formally defined we need
    to craft a test suite to verify that the code works according to
    spec...

diff --git a/doc/man/polkit-auth.xml b/doc/man/polkit-auth.xml
index 793395a..638f3bb 100644
--- a/doc/man/polkit-auth.xml
+++ b/doc/man/polkit-auth.xml
@@ -24,6 +24,7 @@
       <arg><option><arg><option>--user <replaceable>user</replaceable></option></arg> --explicit</option></arg>
       <arg><option><arg><option>--user <replaceable>user</replaceable></option></arg> --explicit-detail</option></arg>
       <arg><option><arg><option>--user <replaceable>user</replaceable></option></arg> --grant <replaceable>action</replaceable></option><arg><option>--constraint <replaceable>constraint</replaceable></option></arg></arg>
+      <arg><option><arg><option>--user <replaceable>user</replaceable></option></arg> --block <replaceable>action</replaceable></option><arg><option>--constraint <replaceable>constraint</replaceable></option></arg></arg>
       <arg><option><arg><option>--user <replaceable>user</replaceable></option></arg> --revoke <replaceable>action</replaceable></option></arg>
       <arg><option>--version</option></arg>
       <arg><option>--help</option></arg>
@@ -110,6 +111,24 @@
       </varlistentry>
 
       <varlistentry>
+        <term><option><arg><option>--user <replaceable>user</replaceable></option></arg> --block <replaceable>action</replaceable></option><arg><option>--constraint <replaceable>constraint</replaceable></option></arg></term>
+        <listitem>
+          <para>
+            Grant an negative authorization for an action. Negative
+            authorizations are normally used to block users that would
+            normally be authorized due to implicit
+            authorizations. Optionally, a constraint on the granted
+            negative authorization can be specified; allowed values
+            are: <literal>local</literal>,
+            <literal>active</literal>, <literal>local+active</literal>.
+            The authorization needed to grant negative authorizations is
+            <literal>org.freedesktop.policykit.grant</literal> if the
+            "beneficiary" is another user.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><option><arg><option>--user <replaceable>user</replaceable></option></arg> --revoke <replaceable>action</replaceable></option></term>
         <listitem>
           <para>
diff --git a/src/polkit-dbus/polkit-simple.c b/src/polkit-dbus/polkit-simple.c
index b6d9ac9..af1c3c9 100644
--- a/src/polkit-dbus/polkit-simple.c
+++ b/src/polkit-dbus/polkit-simple.c
@@ -157,6 +157,8 @@ polkit_check_authv (pid_t pid, const char **action_ids)
 
         ret = 0;
         errno = ENOENT;
+        context = NULL;
+        caller = NULL;
 
         dbus_error_init (&error);
         bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
diff --git a/src/polkit-grant/polkit-authorization-db-write.c b/src/polkit-grant/polkit-authorization-db-write.c
index 145aed9..fecd475 100644
--- a/src/polkit-grant/polkit-authorization-db-write.c
+++ b/src/polkit-grant/polkit-authorization-db-write.c
@@ -533,6 +533,9 @@ polkit_authorization_db_add_entry_always           (PolKitAuthorizationDB *authd
 typedef struct {
         char *action_id;
         PolKitAuthorizationConstraint  *constraint;
+
+        polkit_bool_t is_authorized;
+        polkit_bool_t is_negative_authorized;
 } CheckDataGrant;
 
 static polkit_bool_t 
@@ -540,6 +543,7 @@ _check_auth_for_grant (PolKitAuthorizationDB *authdb, PolKitAuthorization *auth,
 {
         uid_t pimp;
         polkit_bool_t ret;
+        polkit_bool_t is_negative;
         CheckDataGrant *cd = (CheckDataGrant *) user_data;
 
         ret = FALSE;
@@ -547,42 +551,34 @@ _check_auth_for_grant (PolKitAuthorizationDB *authdb, PolKitAuthorization *auth,
         if (strcmp (polkit_authorization_get_action_id (auth), cd->action_id) != 0)
                 goto no_match;
 
-        if (!polkit_authorization_was_granted_explicitly (auth, &pimp))
+        if (!polkit_authorization_was_granted_explicitly (auth, &pimp, &is_negative))
                 goto no_match;
 
         if (!polkit_authorization_constraint_equal (polkit_authorization_get_constraint (auth), cd->constraint))
                 goto no_match;
 
-        ret = TRUE;
+        if (is_negative) {
+                cd->is_authorized = FALSE;
+                cd->is_negative_authorized = TRUE;
+                /* it only takes a single negative auth to block things so stop iterating */
+                ret = TRUE;
+        } else {
+                cd->is_authorized = TRUE;
+                cd->is_negative_authorized = FALSE;
+                /* keep iterating; we may find negative auths... */
+        }
 
 no_match:
         return ret;
 }
 
-/**
- * polkit_authorization_db_grant_to_uid:
- * @authdb: authorization database
- * @action: action
- * @uid: uid to grant to
- * @constraint: what constraint to put on the authorization
- * @error: return location for error
- *
- * Grants an authorization to a user for a specific action. This
- * requires the org.freedesktop.policykit.grant authorization.
- *
- * This function is in <literal>libpolkit-grant</literal>.
- *
- * Returns: #TRUE if the authorization was granted, #FALSE otherwise
- * and error will be set
- *
- * Since: 0.7
- */
-polkit_bool_t 
-polkit_authorization_db_grant_to_uid (PolKitAuthorizationDB          *authdb,
-                                      PolKitAction                   *action,
-                                      uid_t                           uid,
-                                      PolKitAuthorizationConstraint  *constraint,
-                                      PolKitError                   **error)
+static polkit_bool_t 
+_grant_internal (PolKitAuthorizationDB          *authdb,
+                 PolKitAction                   *action,
+                 uid_t                           uid,
+                 PolKitAuthorizationConstraint  *constraint,
+                 PolKitError                   **error,
+                 polkit_bool_t                   is_negative)
 {
         GError *g_error;
         char *helper_argv[6] = {PACKAGE_LIBEXEC_DIR "/polkit-explicit-grant-helper", NULL, NULL, NULL, NULL, NULL};
@@ -590,6 +586,7 @@ polkit_authorization_db_grant_to_uid (PolKitAuthorizationDB          *authdb,
         gint exit_status;
         char cbuf[256];
         CheckDataGrant cd;
+        polkit_bool_t did_exist;
 
         ret = FALSE;
 
@@ -614,16 +611,29 @@ polkit_authorization_db_grant_to_uid (PolKitAuthorizationDB          *authdb,
 
         /* check if we have the auth already */
         cd.constraint = constraint;
-        if (!polkit_authorization_db_foreach_for_uid (authdb,
-                                                      uid, 
-                                                      _check_auth_for_grant,
-                                                      &cd,
-                                                      error)) {
-                /* happens if caller can't read auths of target user */
-                if (error != NULL && polkit_error_is_set (*error)) {
-                        goto out;
-                }
+        cd.is_authorized = FALSE;
+        cd.is_negative_authorized = FALSE;
+        polkit_authorization_db_foreach_for_uid (authdb,
+                                                 uid, 
+                                                 _check_auth_for_grant,
+                                                 &cd,
+                                                 error);
+
+        /* happens if caller can't read auths of target user */
+        if (error != NULL && polkit_error_is_set (*error)) {
+                goto out;
+        }
+
+        did_exist = FALSE;
+        if (is_negative) {
+                if (cd.is_negative_authorized)
+                        did_exist = TRUE;
         } else {
+                if (cd.is_authorized)
+                        did_exist = TRUE;
+        }
+        
+        if (did_exist) {
                 /* so it did exist.. */
                 polkit_error_set_error (error, 
                                         POLKIT_ERROR_AUTHORIZATION_ALREADY_EXISTS, 
@@ -635,7 +645,10 @@ polkit_authorization_db_grant_to_uid (PolKitAuthorizationDB          *authdb,
 
         helper_argv[1] = cd.action_id;
         helper_argv[2] = cbuf;
-        helper_argv[3] = "uid";
+        if (is_negative)
+                helper_argv[3] = "uid-negative";
+        else
+                helper_argv[3] = "uid";
         helper_argv[4] = g_strdup_printf ("%d", uid);
         helper_argv[5] = NULL;
 
@@ -676,5 +689,65 @@ polkit_authorization_db_grant_to_uid (PolKitAuthorizationDB          *authdb,
 out:
         g_free (helper_argv[4]);
         return ret;
+}
+
+/**
+ * polkit_authorization_db_grant_to_uid:
+ * @authdb: authorization database
+ * @action: action
+ * @uid: uid to grant to
+ * @constraint: what constraint to put on the authorization
+ * @error: return location for error
+ *
+ * Grants an authorization to a user for a specific action. This
+ * requires the org.freedesktop.policykit.grant authorization.
+ *
+ * This function is in <literal>libpolkit-grant</literal>.
+ *
+ * Returns: #TRUE if the authorization was granted, #FALSE otherwise
+ * and error will be set
+ *
+ * Since: 0.7
+ */
+polkit_bool_t 
+polkit_authorization_db_grant_to_uid (PolKitAuthorizationDB          *authdb,
+                                      PolKitAction                   *action,
+                                      uid_t                           uid,
+                                      PolKitAuthorizationConstraint  *constraint,
+                                      PolKitError                   **error)
+{
+        return _grant_internal (authdb, action, uid, constraint, error, FALSE);
+}
 
+/**
+ * polkit_authorization_db_grant_negative_to_uid:
+ * @authdb: authorization database
+ * @action: action
+ * @uid: uid to grant to
+ * @constraint: what constraint to put on the authorization
+ * @error: return location for error
+ *
+ * Grants a negative authorization to a user for a specific action. If
+ * @uid differs from the calling user, the
+ * org.freedesktop.policykit.grant authorization is required. In other
+ * words, users may "grant" negative authorizations to themselves.
+ *
+ * A negative authorization is normally used to block users that would
+ * normally be authorized from an implicit authorization.
+ *
+ * This function is in <literal>libpolkit-grant</literal>.
+ *
+ * Returns: #TRUE if the authorization was granted, #FALSE otherwise
+ * and error will be set
+ *
+ * Since: 0.7
+ */
+polkit_bool_t
+polkit_authorization_db_grant_negative_to_uid           (PolKitAuthorizationDB          *authdb,
+                                                         PolKitAction                   *action,
+                                                         uid_t                           uid,
+                                                         PolKitAuthorizationConstraint  *constraint,
+                                                         PolKitError                   **error)
+{
+        return _grant_internal (authdb, action, uid, constraint, error, TRUE);
 }
diff --git a/src/polkit-grant/polkit-explicit-grant-helper.c b/src/polkit-grant/polkit-explicit-grant-helper.c
index 7d08448..0c7ac60 100644
--- a/src/polkit-grant/polkit-explicit-grant-helper.c
+++ b/src/polkit-grant/polkit-explicit-grant-helper.c
@@ -124,9 +124,16 @@ main (int argc, char *argv[])
 #define TARGET_UID 0
         int target;
         uid_t target_uid = -1;
+        polkit_bool_t is_negative;
 
-        /* (third, fourth) is one of: ("uid", uid) */
-        if (strcmp (argv[3], "uid") == 0) {
+        is_negative = FALSE;
+
+        /* (third, fourth) is one of: ("uid", uid), ("uid-negative", uid) */
+        if (strcmp (argv[3], "uid") == 0 || strcmp (argv[3], "uid-negative") == 0) {
+
+                if (strcmp (argv[3], "uid") != 0) {
+                        is_negative = TRUE;
+                }
 
                 target = TARGET_UID;
                 target_uid = strtol (argv[4], &endp, 10);
@@ -147,14 +154,19 @@ main (int argc, char *argv[])
         /* OK, we're done parsing ... check if the user is authorized */
 
         if (invoking_uid != 0) {
-                pid_t ppid;
-                        
-                ppid = getppid ();
-                if (ppid == 1)
-                        goto out;
 
-                if (polkit_check_auth (ppid, "org.freedesktop.policykit.grant", NULL) == 0) {
-                        goto out;
+                if (is_negative && (invoking_uid == target_uid)) {
+                        /* it's fine to grant negative-auths to one self... */
+                } else {
+                        pid_t ppid;
+                        
+                        ppid = getppid ();
+                        if (ppid == 1)
+                                goto out;
+                        
+                        if (polkit_check_auth (ppid, "org.freedesktop.policykit.grant", NULL) == 0) {
+                                goto out;
+                        }
                 }
         }
 
@@ -169,7 +181,8 @@ main (int argc, char *argv[])
 
         if (snprintf (grant_line, 
                       sizeof (grant_line), 
-                      "grant:%s:%Lu:%d:%s\n",
+                      is_negative ? "grant-negative:%s:%Lu:%d:%s\n" : 
+                                    "grant:%s:%Lu:%d:%s\n" ,
                       action_id,
                       (polkit_uint64_t) now.tv_sec,
                       invoking_uid,
diff --git a/src/polkit-grant/polkit-revoke-helper.c b/src/polkit-grant/polkit-revoke-helper.c
index 6453f81..b59d0c2 100644
--- a/src/polkit-grant/polkit-revoke-helper.c
+++ b/src/polkit-grant/polkit-revoke-helper.c
@@ -185,7 +185,8 @@ main (int argc, char *argv[])
                 root = PACKAGE_LOCALSTATE_DIR "/run/PolicyKit";
         } else if (strcmp (scope, "always") == 0) {
                 root = PACKAGE_LOCALSTATE_DIR "/lib/PolicyKit";
-        } else if (strcmp (scope, "grant") == 0) {
+        } else if (strcmp (scope, "grant") == 0 ||
+                   strcmp (scope, "grant-negative") == 0) {
                 uid_t granted_by;
 
                 root = PACKAGE_LOCALSTATE_DIR "/lib/PolicyKit";
@@ -208,8 +209,10 @@ main (int argc, char *argv[])
         }
 
         if (invoking_uid != 0) {
-                /* Check that the caller is privileged to do this... */
-                if (not_granted_by_self || (invoking_uid != uid_to_revoke)) {
+                /* Check that the caller is privileged to do this... basically, callers can only
+                 * revoke auths granted by themselves...
+                 */
+                if (not_granted_by_self) {
                         pid_t ppid;
                         
                         ppid = getppid ();
diff --git a/src/polkit/polkit-authorization-db.c b/src/polkit/polkit-authorization-db.c
index d31183e..7322355 100644
--- a/src/polkit/polkit-authorization-db.c
+++ b/src/polkit/polkit-authorization-db.c
@@ -340,7 +340,10 @@ _authdb_get_auths_for_uid (PolKitAuthorizationDB *authdb,
                                 auth = _polkit_authorization_new_for_uid (line, uid2);
                                 
                                 if (auth != NULL) {
-                                        ret = kit_list_prepend (ret, auth);
+                                        /* we need the authorizations in the chronological order... 
+                                         * (TODO: optimized: prepend, then reverse after all items have been inserted)
+                                         */
+                                        ret = kit_list_append (ret, auth);
                                 }
                         }
                         
@@ -540,12 +543,17 @@ typedef struct {
         uid_t session_uid; 
         char *session_objpath;
         PolKitSession *session;
+
+        polkit_bool_t *out_is_authorized;
+        polkit_bool_t *out_is_negative_authorized;
 } CheckDataSession;
 
 static polkit_bool_t 
 _check_auth_for_session (PolKitAuthorizationDB *authdb, PolKitAuthorization *auth, void *user_data)
 {
         polkit_bool_t ret;
+        uid_t pimp_uid;
+        polkit_bool_t is_negative;
         CheckDataSession *cd = (CheckDataSession *) user_data;
         PolKitAuthorizationConstraint *constraint;
 
@@ -573,7 +581,29 @@ _check_auth_for_session (PolKitAuthorizationDB *authdb, PolKitAuthorization *aut
                 break;
         }
 
-        ret = TRUE;
+        if (!polkit_authorization_was_granted_explicitly (auth, &pimp_uid, &is_negative))
+                is_negative = FALSE;
+
+        if (is_negative) {
+                *(cd->out_is_authorized) = FALSE;
+                *(cd->out_is_negative_authorized) = TRUE;
+        } else {
+                *(cd->out_is_authorized) = TRUE;
+                *(cd->out_is_negative_authorized) = FALSE;
+        }
+
+        /* keep iterating; we may find negative auths... */
+
+        if (is_negative) {
+                *(cd->out_is_authorized) = FALSE;
+                *(cd->out_is_negative_authorized) = TRUE;
+                /* it only takes a single negative auth to block things so stop iterating */
+                ret = TRUE;
+        } else {
+                *(cd->out_is_authorized) = TRUE;
+                *(cd->out_is_negative_authorized) = FALSE;
+                /* keep iterating; we may find negative auths... */
+        }
 
 no_match:
         return ret;
@@ -585,9 +615,14 @@ no_match:
  * @action: the action to check for
  * @session: the session to check for
  * @out_is_authorized: return location
+ * @out_is_negative_authorized: return location
  *
  * Looks in the authorization database and determine if processes from
- * the given session are authorized to do the given specific action.
+ * the given session are authorized to do the given specific
+ * action. If there is an authorization record that matches the
+ * session, @out_is_authorized will be set to %TRUE. If there is a
+ * negative authorization record matching the session
+ * @out_is_negative_authorized will be set to %TRUE.
  *
  * Returns: #TRUE if the look up was performed; #FALSE if the caller
  * of this function lacks privileges to ask this question (e.g. asking
@@ -599,7 +634,8 @@ polkit_bool_t
 polkit_authorization_db_is_session_authorized (PolKitAuthorizationDB *authdb,
                                                PolKitAction          *action,
                                                PolKitSession         *session,
-                                               polkit_bool_t         *out_is_authorized)
+                                               polkit_bool_t         *out_is_authorized,
+                                               polkit_bool_t         *out_is_negative_authorized)
 {
         polkit_bool_t ret;
         CheckDataSession cd;
@@ -624,13 +660,17 @@ polkit_authorization_db_is_session_authorized (PolKitAuthorizationDB *authdb,
 
         ret = TRUE;
 
+        cd.out_is_authorized = out_is_authorized;
+        cd.out_is_negative_authorized = out_is_negative_authorized;
         *out_is_authorized = FALSE;
+        *out_is_negative_authorized = FALSE;
+
         if (polkit_authorization_db_foreach_for_uid (authdb,
                                                      cd.session_uid, 
                                                      _check_auth_for_session,
                                                      &cd,
                                                      NULL)) {
-                *out_is_authorized = TRUE;
+                ;
         }
 
         return ret;
@@ -644,13 +684,17 @@ typedef struct {
         char *session_objpath;
         PolKitCaller *caller;
         polkit_bool_t revoke_if_one_shot;
+
+        polkit_bool_t *out_is_authorized;
+        polkit_bool_t *out_is_negative_authorized;
 } CheckData;
 
 static polkit_bool_t 
 _check_auth_for_caller (PolKitAuthorizationDB *authdb, PolKitAuthorization *auth, void *user_data)
 {
-
         polkit_bool_t ret;
+        uid_t pimp_uid;
+        polkit_bool_t is_negative;
         pid_t caller_pid;
         polkit_uint64_t caller_pid_start_time;
         CheckData *cd = (CheckData *) user_data;
@@ -701,7 +745,19 @@ _check_auth_for_caller (PolKitAuthorizationDB *authdb, PolKitAuthorization *auth
                 break;
         }
 
-        ret = TRUE;
+        if (!polkit_authorization_was_granted_explicitly (auth, &pimp_uid, &is_negative))
+                is_negative = FALSE;
+
+        if (is_negative) {
+                *(cd->out_is_authorized) = FALSE;
+                *(cd->out_is_negative_authorized) = TRUE;
+                /* it only takes a single negative auth to block things so stop iterating */
+                ret = TRUE;
+        } else {
+                *(cd->out_is_authorized) = TRUE;
+                *(cd->out_is_negative_authorized) = FALSE;
+                /* keep iterating; we may find negative auths... */
+        }
 
 
 no_match:
@@ -716,9 +772,13 @@ no_match:
  * @revoke_if_one_shot: Whether to revoke one-shot authorizations. See
  * discussion in polkit_context_is_caller_authorized() for details.
  * @out_is_authorized: return location
+ * @out_is_negative_authorized: return location
  *
  * Looks in the authorization database if the given caller is
- * authorized to do the given action.
+ * authorized to do the given action. If there is an authorization
+ * record that matches the caller, @out_is_authorized will be set to
+ * %TRUE. If there is a negative authorization record matching the
+ * caller @out_is_negative_authorized will be set to %TRUE.
  *
  * Returns: #TRUE if the look up was performed; #FALSE if the caller
  * of this function lacks privileges to ask this question (e.g. asking
@@ -731,7 +791,8 @@ polkit_authorization_db_is_caller_authorized (PolKitAuthorizationDB *authdb,
                                               PolKitAction          *action,
                                               PolKitCaller          *caller,
                                               polkit_bool_t          revoke_if_one_shot,
-                                              polkit_bool_t         *out_is_authorized)
+                                              polkit_bool_t         *out_is_authorized,
+                                              polkit_bool_t         *out_is_negative_authorized)
 {
         PolKitSession *session;
         polkit_bool_t ret;
@@ -769,13 +830,17 @@ polkit_authorization_db_is_caller_authorized (PolKitAuthorizationDB *authdb,
 
         ret = TRUE;
 
+        cd.out_is_authorized = out_is_authorized;
+        cd.out_is_negative_authorized = out_is_negative_authorized;
         *out_is_authorized = FALSE;
+        *out_is_negative_authorized = FALSE;
+
         if (polkit_authorization_db_foreach_for_uid (authdb,
                                                      cd.caller_uid, 
                                                      _check_auth_for_caller,
                                                      &cd,
                                                      NULL)) {
-                *out_is_authorized = TRUE;
+                ;
         }
 
         return ret;
@@ -849,6 +914,77 @@ out:
         return ret;
 }
 
+static polkit_bool_t
+_check_self_block_foreach (PolKitAuthorizationDB *authdb,
+                           PolKitAuthorization   *auth, 
+                           void                  *user_data)
+{
+        polkit_bool_t *is_self_blocked = (polkit_bool_t *) user_data;
+        polkit_bool_t is_negative;
+        uid_t pimp_uid;
+        polkit_bool_t ret;
+
+        if (!polkit_authorization_was_granted_explicitly (auth, &pimp_uid, &is_negative))
+                is_negative = FALSE;
+
+        if (is_negative) {
+                if (pimp_uid == getuid ()) {
+                        *is_self_blocked = TRUE;
+                        /* can't stop iterating.. there may be another one who blocked us too! */
+                } else {
+                        *is_self_blocked = FALSE;
+                        ret = TRUE;
+                        /* nope; someone else blocked us.. that's enough to ruin it */
+                }                        
+        }
+        
+        return ret;
+}
+
+/**
+ * polkit_authorization_db_is_uid_blocked_by_self:
+ * @authdb: the authorization database
+ * @action: the action to check for
+ * @uid: the user to check for
+ * @error: return location for error
+ *
+ * Determine whether there exists negative authorizations for the
+ * particular uid on the given action and whether those negative
+ * authorization are "granted" by the uid itself.
+ *
+ * If uid is different from getuid(), e.g. if the calling process asks
+ * for auths of another user this function will set an error if the
+ * calling user is not authorized for org.freedesktop.policykit.read.
+ *
+ * Returns: Result of computation described above; if error is set
+ * will return %FALSE.
+ *
+ * Since: 0.7
+ */
+polkit_bool_t
+polkit_authorization_db_is_uid_blocked_by_self (PolKitAuthorizationDB *authdb,
+                                                PolKitAction          *action,
+                                                uid_t                  uid,
+                                                PolKitError          **error)
+{
+        polkit_bool_t is_self_blocked;
+
+        kit_return_val_if_fail (authdb != NULL, FALSE);
+        kit_return_val_if_fail (action != NULL, FALSE);
+                                
+        is_self_blocked = FALSE;
+        polkit_authorization_db_foreach_for_action_for_uid (authdb,
+                                                            action,
+                                                            uid,
+                                                            _check_self_block_foreach,
+                                                            &is_self_blocked,
+                                                            error);
+
+        return is_self_blocked;
+}
+
+
+
 #ifdef POLKIT_BUILD_TESTS
 
 static polkit_bool_t
diff --git a/src/polkit/polkit-authorization-db.h b/src/polkit/polkit-authorization-db.h
index 8089bd4..3e4dffe 100644
--- a/src/polkit/polkit-authorization-db.h
+++ b/src/polkit/polkit-authorization-db.h
@@ -68,13 +68,15 @@ polkit_bool_t          polkit_authorization_db_validate       (PolKitAuthorizati
 polkit_bool_t polkit_authorization_db_is_session_authorized (PolKitAuthorizationDB *authdb,
                                                              PolKitAction          *action,
                                                              PolKitSession         *session,
-                                                             polkit_bool_t         *out_is_authorized);
+                                                             polkit_bool_t         *out_is_authorized,
+                                                             polkit_bool_t         *out_is_negative_authorized);
 
 polkit_bool_t polkit_authorization_db_is_caller_authorized (PolKitAuthorizationDB *authdb,
                                                             PolKitAction          *action,
                                                             PolKitCaller          *caller,
                                                             polkit_bool_t          revoke_if_one_shot,
-                                                            polkit_bool_t         *out_is_authorized);
+                                                            polkit_bool_t         *out_is_authorized,
+                                                            polkit_bool_t         *out_is_negative_authorized);
 
 /**
  * PolKitAuthorizationDBForeach:
@@ -144,11 +146,22 @@ polkit_bool_t polkit_authorization_db_grant_to_uid           (PolKitAuthorizatio
                                                               PolKitAuthorizationConstraint  *constraint,
                                                               PolKitError                   **error);
 
+polkit_bool_t polkit_authorization_db_grant_negative_to_uid           (PolKitAuthorizationDB          *authdb,
+                                                                       PolKitAction                   *action,
+                                                                       uid_t                           uid,
+                                                                       PolKitAuthorizationConstraint  *constraint,
+                                                                       PolKitError                   **error);
+
 polkit_bool_t polkit_authorization_db_revoke_entry (PolKitAuthorizationDB *authdb,
                                                     PolKitAuthorization *auth,
                                                     PolKitError **error);
 
 
+polkit_bool_t polkit_authorization_db_is_uid_blocked_by_self (PolKitAuthorizationDB *authdb,
+                                                              PolKitAction          *action,
+                                                              uid_t                  uid,
+                                                              PolKitError          **error);
+
 POLKIT_END_DECLS
 
 #endif /* POLKIT_AUTHORIZATION_DB_H */
diff --git a/src/polkit/polkit-authorization.c b/src/polkit/polkit-authorization.c
index 265d37f..cf11342 100644
--- a/src/polkit/polkit-authorization.c
+++ b/src/polkit/polkit-authorization.c
@@ -83,6 +83,8 @@ struct _PolKitAuthorization
         polkit_bool_t explicitly_granted;
         uid_t explicitly_granted_by;
 
+        polkit_bool_t is_negative;
+
         char *session_id;
 };
 
@@ -250,11 +252,16 @@ _polkit_authorization_new_for_uid (const char *entry_in_auth_file, uid_t uid)
  *                     authc_str) >= (int) sizeof (grant_line)) {
  *
  */
-        else if (strcmp (t[0], "grant") == 0) {
+        else if (strcmp (t[0], "grant") == 0 ||
+                 strcmp (t[0], "grant-negative") == 0) {
 
                 if (num_t != 5)
                         goto error;
 
+                if (strcmp (t[0], "grant-negative") == 0) {
+                        auth->is_negative = TRUE;
+                }
+
                 auth->scope = POLKIT_AUTHORIZATION_SCOPE_ALWAYS;
                 auth->explicitly_granted = TRUE;
 
@@ -545,6 +552,7 @@ polkit_authorization_was_granted_via_defaults (PolKitAuthorization *auth,
  * polkit_authorization_was_granted_explicitly:
  * @auth: the object
  * @out_by_whom: return location
+ * @out_is_negative: return location
  *
  * Determine if the authorization was explicitly granted by a
  * sufficiently privileged user.
@@ -553,21 +561,26 @@ polkit_authorization_was_granted_via_defaults (PolKitAuthorization *auth,
  * one of these functions can return #TRUE.
  *
  * Returns: #TRUE if the authorization was explicitly granted by a
- * sufficiently privileger user.
+ * sufficiently privileger user. If %TRUE, the user who granted the
+ * authorization is returned in %out_by_whom. If the authorization is
+ * negative, %TRUE is returned in %out_is_negative.
  *
  * Since: 0.7
  */ 
 polkit_bool_t 
 polkit_authorization_was_granted_explicitly (PolKitAuthorization *auth,
-                                             uid_t *out_by_whom)
+                                             uid_t               *out_by_whom,
+                                             polkit_bool_t       *out_is_negative)
 {
         kit_return_val_if_fail (auth != NULL, FALSE);
         kit_return_val_if_fail (out_by_whom != NULL, FALSE);
+        kit_return_val_if_fail (out_is_negative != NULL, FALSE);
 
         if (!auth->explicitly_granted)
                 return FALSE;
 
         *out_by_whom = auth->explicitly_granted_by;
+        *out_is_negative = auth->is_negative;
 
         return TRUE;
 }
diff --git a/src/polkit/polkit-authorization.h b/src/polkit/polkit-authorization.h
index 0e107be..96841bf 100644
--- a/src/polkit/polkit-authorization.h
+++ b/src/polkit/polkit-authorization.h
@@ -91,7 +91,8 @@ polkit_bool_t polkit_authorization_was_granted_via_defaults  (PolKitAuthorizatio
                                                               uid_t *out_user_authenticated_as);
 
 polkit_bool_t polkit_authorization_was_granted_explicitly  (PolKitAuthorization *auth,
-                                                            uid_t *out_by_whom);
+                                                            uid_t *out_by_whom,
+                                                            polkit_bool_t *out_is_negative);
 
 POLKIT_END_DECLS
 
diff --git a/src/polkit/polkit-context.c b/src/polkit/polkit-context.c
index a7e0091..88685bf 100644
--- a/src/polkit/polkit-context.c
+++ b/src/polkit/polkit-context.c
@@ -448,6 +448,7 @@ polkit_context_is_session_authorized (PolKitContext         *pk_context,
         PolKitResult result_from_config;
         PolKitResult result_from_grantdb;
         polkit_bool_t from_authdb;
+        polkit_bool_t from_authdb_negative;
         PolKitResult result;
         PolKitConfig *config;
 
@@ -493,10 +494,12 @@ polkit_context_is_session_authorized (PolKitContext         *pk_context,
         result_from_config = polkit_config_can_session_do_action (config, action, session);
 
         result_from_grantdb = POLKIT_RESULT_UNKNOWN;
+        from_authdb_negative = FALSE;
         if (polkit_authorization_db_is_session_authorized (pk_context->authdb, 
                                                            action, 
                                                            session,
-                                                           &from_authdb)) {
+                                                           &from_authdb,
+                                                           &from_authdb_negative)) {
                 if (from_authdb)
                         result_from_grantdb = POLKIT_RESULT_YES;
         }
@@ -529,13 +532,15 @@ polkit_context_is_session_authorized (PolKitContext         *pk_context,
                 goto found;
         }
 
-        /* Otherwise, fall back to defaults as specified in the .policy file */
-        policy_default = polkit_policy_file_entry_get_default (pfe);
-        if (policy_default == NULL) {
-                kit_warning ("no default policy for action!");
-                goto out;
+        /* Otherwise, unless we found a negative auth, fall back to defaults as specified in the .policy file */
+        if (!from_authdb_negative) {
+                policy_default = polkit_policy_file_entry_get_default (pfe);
+                if (policy_default == NULL) {
+                        kit_warning ("no default policy for action!");
+                        goto out;
+                }
+                result = polkit_policy_default_can_session_do_action (policy_default, action, session);
         }
-        result = polkit_policy_default_can_session_do_action (policy_default, action, session);
 
 found:
         /* Never return UNKNOWN to user */
@@ -600,6 +605,7 @@ polkit_context_is_caller_authorized (PolKitContext         *pk_context,
         PolKitPolicyDefault *policy_default;
         PolKitConfig *config;
         polkit_bool_t from_authdb;
+        polkit_bool_t from_authdb_negative;
 
         result = POLKIT_RESULT_NO;
         kit_return_val_if_fail (pk_context != NULL, result);
@@ -643,11 +649,13 @@ polkit_context_is_caller_authorized (PolKitContext         *pk_context,
         result_from_config = polkit_config_can_caller_do_action (config, action, caller);
 
         result_from_grantdb = POLKIT_RESULT_UNKNOWN;
+        from_authdb_negative = FALSE;
         if (polkit_authorization_db_is_caller_authorized (pk_context->authdb, 
                                                           action, 
                                                           caller,
                                                           revoke_if_one_shot,
-                                                          &from_authdb)) {
+                                                          &from_authdb,
+                                                          &from_authdb_negative)) {
                 if (from_authdb)
                         result_from_grantdb = POLKIT_RESULT_YES;
         }
@@ -680,13 +688,15 @@ polkit_context_is_caller_authorized (PolKitContext         *pk_context,
                 goto found;
         }
 
-        /* Otherwise, fall back to defaults as specified in the .policy file */
-        policy_default = polkit_policy_file_entry_get_default (pfe);
-        if (policy_default == NULL) {
-                kit_warning ("no default policy for action!");
-                goto out;
+        /* Otherwise, unless we found a negative auth, fall back to defaults as specified in the .policy file */
+        if (!from_authdb_negative) {
+                policy_default = polkit_policy_file_entry_get_default (pfe);
+                if (policy_default == NULL) {
+                        kit_warning ("no default policy for action!");
+                        goto out;
+                }
+                result = polkit_policy_default_can_caller_do_action (policy_default, action, caller);
         }
-        result = polkit_policy_default_can_caller_do_action (policy_default, action, caller);
 
 found:
 
diff --git a/tools/polkit-auth.c b/tools/polkit-auth.c
index ac4d96c..4d73c0a 100644
--- a/tools/polkit-auth.c
+++ b/tools/polkit-auth.c
@@ -56,6 +56,7 @@ static polkit_bool_t opt_show_obtainable;
 static char *opt_revoke_action_id;
 static char *opt_user;
 static char *opt_grant_action_id;
+static char *opt_block_action_id;
 static char *opt_constraint;
 
 typedef struct {
@@ -414,8 +415,6 @@ auth_iterator_cb (PolKitAuthorizationDB *authdb,
                 g_hash_table_insert (already_shown, g_strdup (action_id), (gpointer) 1);
         }
 
-        printf ("%s\n", action_id);
-
         if (opt_show_explicit_detail) {
                 char *s;
                 time_t time_granted;
@@ -423,6 +422,7 @@ auth_iterator_cb (PolKitAuthorizationDB *authdb,
                 char time_string[128];
                 uid_t auth_uid;
                 uid_t pimp_uid;
+                polkit_bool_t is_negative;
                 pid_t pid;
                 polkit_uint64_t pid_start_time;
                 const char *cstr;
@@ -431,6 +431,8 @@ auth_iterator_cb (PolKitAuthorizationDB *authdb,
                 PolKitResult pk_result;
                 char exe[PATH_MAX];
 
+                printf ("%s\n", action_id);
+
                 pk_action = polkit_action_new ();
                 polkit_action_set_action_id (pk_action, action_id);
                 pk_result = polkit_context_is_caller_authorized (pk_context, pk_action, pk_caller, FALSE, NULL);
@@ -461,11 +463,12 @@ auth_iterator_cb (PolKitAuthorizationDB *authdb,
                 time_granted = polkit_authorization_get_time_of_grant (auth);
                 time_tm = localtime (&time_granted);
 
+                is_negative = FALSE;
                 if (polkit_authorization_was_granted_via_defaults (auth, &auth_uid)) { 
                         s = g_strdup_printf ("%%c by auth as %s (uid %d)", get_name_from_uid (auth_uid), auth_uid);
                         strftime (time_string, sizeof (time_string), s, time_tm);
                         g_free (s);
-                } else if (polkit_authorization_was_granted_explicitly (auth, &pimp_uid)) { 
+                } else if (polkit_authorization_was_granted_explicitly (auth, &pimp_uid, &is_negative)) { 
                         s = g_strdup_printf ("%%c from %s (uid %d)", get_name_from_uid (pimp_uid), pimp_uid);
                         strftime (time_string, sizeof (time_string), s, time_tm);
                         g_free (s);
@@ -489,7 +492,20 @@ auth_iterator_cb (PolKitAuthorizationDB *authdb,
                 }
                 printf ("  Constraints: %s\n", cstr);
 
+                if (is_negative) {
+                        printf ("  Negative:    Yes\n");
+                }
+
                 printf ("\n");
+        } else {
+                uid_t pimp_uid;
+                polkit_bool_t is_negative;
+
+                if (!polkit_authorization_was_granted_explicitly (auth, &pimp_uid, &is_negative))
+                        is_negative = FALSE;
+
+                if (!is_negative)
+                        printf ("%s\n", action_id);
         }
 
 
@@ -681,6 +697,7 @@ main (int argc, char *argv[])
         opt_is_version = FALSE;
         opt_obtain_action_id = NULL;
         opt_grant_action_id = NULL;
+        opt_block_action_id = NULL;
         opt_constraint = NULL;
         opt_revoke_action_id = NULL;
         opt_show_obtainable = FALSE;
@@ -695,6 +712,7 @@ main (int argc, char *argv[])
                         {"explicit-detail", 0, NULL, 0},
 			{"obtain", 1, NULL, 0},
 			{"grant", 1, NULL, 0},
+			{"block", 1, NULL, 0},
                         {"constraint", 1, NULL, 0},
 			{"revoke", 1, NULL, 0},
 			{"show-obtainable", 0, NULL, 0},
@@ -721,6 +739,8 @@ main (int argc, char *argv[])
 				opt_obtain_action_id = strdup (optarg);
 			} else if (strcmp (opt, "grant") == 0) {
 				opt_grant_action_id = strdup (optarg);
+			} else if (strcmp (opt, "block") == 0) {
+				opt_block_action_id = strdup (optarg);
 			} else if (strcmp (opt, "constraint") == 0) {
 				opt_constraint = strdup (optarg);
 			} else if (strcmp (opt, "revoke") == 0) {
@@ -765,10 +785,12 @@ main (int argc, char *argv[])
                 if (!obtain_authorization (opt_obtain_action_id))
                         goto out;                
                 ret = 0;
-        } else if (opt_grant_action_id != NULL) {
+        } else if (opt_grant_action_id != NULL ||
+                   opt_block_action_id != NULL) {
                 PolKitAction *pk_action;
                 PolKitError *pk_error;
                 PolKitAuthorizationConstraint *constraint;
+                polkit_bool_t res;
 
                 if (opt_user == NULL && uid == 0) {
                         fprintf (stderr, "polkit-auth: Cowardly refusing to grant authorization to uid 0 (did you forget to specify what user to grant to?). To force, run with --user root.\n");
@@ -776,7 +798,10 @@ main (int argc, char *argv[])
                 }
 
                 pk_action = polkit_action_new ();
-                polkit_action_set_action_id (pk_action, opt_grant_action_id);
+                if (opt_block_action_id != NULL)
+                        polkit_action_set_action_id (pk_action, opt_block_action_id);
+                else
+                        polkit_action_set_action_id (pk_action, opt_grant_action_id);
 
                 if (opt_constraint != NULL) {
                         constraint = polkit_authorization_constraint_from_string (opt_constraint);
@@ -789,18 +814,28 @@ main (int argc, char *argv[])
                 }
 
                 pk_error = NULL;
-                if (!polkit_authorization_db_grant_to_uid (pk_authdb,
-                                                           pk_action,
-                                                           uid,
-                                                           constraint,
-                                                           &pk_error)) {
+                if (opt_block_action_id != NULL) {
+                        res = polkit_authorization_db_grant_negative_to_uid (pk_authdb,
+                                                                             pk_action,
+                                                                             uid,
+                                                                             constraint,
+                                                                             &pk_error);
+                } else {
+                        res = polkit_authorization_db_grant_to_uid (pk_authdb,
+                                                                    pk_action,
+                                                                    uid,
+                                                                    constraint,
+                                                                    &pk_error);
+                }
+
+                if (!res) {
                         fprintf (stderr, "polkit-auth: %s: %s\n", 
                                  polkit_error_get_error_name (pk_error),
                                  polkit_error_get_error_message (pk_error));
                         polkit_error_free (pk_error);
                         goto out;
                 }
-
+                
                 ret = 0;
 
         } else if (opt_revoke_action_id != NULL) {
diff --git a/tools/polkit-bash-completion.sh b/tools/polkit-bash-completion.sh
index 2f94048..8d1d2a4 100644
--- a/tools/polkit-bash-completion.sh
+++ b/tools/polkit-bash-completion.sh
@@ -7,7 +7,7 @@ __polkit_auth() {
 
     case $COMP_CWORD in
         1)
-            COMPREPLY=($(IFS=: compgen -S' ' -W "--obtain:--show-obtainable:--explicit:--explicit-detail:--grant:--revoke:--user:--version:--help" -- $cur))
+            COMPREPLY=($(IFS=: compgen -S' ' -W "--obtain:--show-obtainable:--explicit:--explicit-detail:--grant:--block:--revoke:--user:--version:--help" -- $cur))
             ;;
         2)
 	    case "${COMP_WORDS[1]}" in
@@ -17,7 +17,7 @@ __polkit_auth() {
                 --revoke) 
                     COMPREPLY=($(compgen -W "$(polkit-auth --explicit)" -- $cur))
                     ;;
-                --grant) 
+                --grant|--block)
                     COMPREPLY=($(compgen -W "$(polkit-action)" -- $cur))
                     ;;
                 --user)   
@@ -28,9 +28,9 @@ __polkit_auth() {
         3)
 	    case "${COMP_WORDS[1]}" in
                 --user)
-                    COMPREPLY=($(IFS=: compgen -S' ' -W "--explicit:--explicit-detail:--grant:--revoke" -- $cur))
+                    COMPREPLY=($(IFS=: compgen -S' ' -W "--explicit:--explicit-detail:--grant:--block:--revoke" -- $cur))
                     ;;
-                --grant)
+                --grant|--block)
                     COMPREPLY=($(IFS=: compgen -S' ' -W "--constraint" -- $cur))
                     ;;
             esac
@@ -54,7 +54,7 @@ __polkit_auth() {
                             ;;
                     esac
                     ;;
-                --grant)
+                --grant|--block)
                     COMPREPLY=($(compgen -W "$(polkit-action)" -- $cur))
                     ;;
                 --constraint)
@@ -64,7 +64,7 @@ __polkit_auth() {
             ;;
         5)
 	    case "${COMP_WORDS[3]}" in
-                --grant)
+                --grant|--block)
                     COMPREPLY=($(IFS=: compgen -S' ' -W "--constraint" -- $cur))
                     ;;
             esac


More information about the hal-commit mailing list