From: David Zeuthen Date: Mon, 5 Jun 2006 23:39:00 +0000 (+0000) Subject: Lots of changes! Almost ready for 0.2 release. X-Git-Tag: POLICY_KIT_0_3~61 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1c3d5691ad444ae2849d079e3745d6b476614623;p=platform%2Fupstream%2Fpolkit.git Lots of changes! Almost ready for 0.2 release. --- diff --git a/ChangeLog b/ChangeLog index 48add59..8c14219 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,76 @@ +2006-06-05 David Zeuthen + + Lots of changes! Almost ready for 0.2 release. + + * Makefile.am: + * README: + * configure.in: + * doc/TODO: + * doc/api/polkit-docs.xml: + * doc/spec/Makefile.am: + * doc/spec/polkit-spec.html: + * doc/spec/polkit-spec.xml.in: + * libpolkit/Makefile.am: + * libpolkit/libpolkit-grant.c: (have_questions_handler), + (libpolkit_grant_provide_answers), (auth_done_handler), + (libpolkit_grant_new_context), + (libpolkit_grant_get_libpolkit_context), + (libpolkit_grant_set_questions_handler), + (libpolkit_grant_set_grant_complete_handler), + (libpolkit_grant_initiate_temporary_grant), + (libpolkit_grant_get_user_for_auth), + (libpolkit_grant_get_pam_service_for_auth), + (libpolkit_grant_close), (libpolkit_grant_free_context), + (libpolkit_grant_get_user), (libpolkit_grant_get_privilege), + (libpolkit_grant_get_resource): + * libpolkit/libpolkit-grant.h: + * libpolkit/libpolkit.c: + (libpolkit_get_allowed_resources_for_privilege_for_uid), + (libpolkit_is_uid_allowed_for_privilege): + * libpolkit/libpolkit.h: + * pam-polkit-console/Makefile.am: + * pam-polkit-console/pam-polkit-console.c: (_pam_log), + (_parse_module_args), (_is_local_xconsole), (_poke_polkitd), + (pam_sm_authenticate), (pam_sm_setcred), (pam_sm_open_session), + (pam_sm_close_session): + * polkit-interface-manager.xml: + * polkit-interface-session.xml: + * polkit.pc.in: + * polkitd/PolicyKit.in: + * polkitd/main.c: (handle_sigusr1), (sigusr1_iochn_data), (main): + * polkitd/policy.c: (txt_backend_read_policy), + (txt_backend_read_list), (txt_backend_read_word), + (policy_get_sufficient_privileges), + (policy_get_required_privileges), + (policy_get_auth_details_for_policy), + (_policy_is_uid_gid_allowed_for_policy), + (policy_is_uid_gid_allowed_for_policy), + (policy_is_uid_allowed_for_policy): + * polkitd/policy.h: + * polkitd/polkit-manager.c: (_granting_temp_priv), + (_revoking_temp_priv), (polkit_manager_error_get_type), + (bus_name_owner_changed), (polkit_manager_get_caller_info), + (_check_for_temp_privilege), + (polkit_manager_initiate_temporary_privilege_grant), + (polkit_manager_is_user_privileged), + (polkit_manager_get_allowed_resources_for_privilege), + (polkit_manager_revoke_temporary_privilege), + (polkit_manager_add_temporary_privilege), + (polkit_manager_remove_temporary_privilege), + (polkit_manager_update_desktop_console_privileges): + * polkitd/polkit-manager.h: + * polkitd/polkit-session.c: (polkit_session_close), + (polkit_session_grant_privilege_temporarily), (polkit_session_new), + (polkit_session_initiator_disconnected): + * polkitd/polkit-session.h: + * privileges/desktop-console.privilege: + * tools/Makefile.am: + * tools/polkit-grant-privilege.c: (questions_cb), + (grant_complete_cb), (main): + * tools/polkit-is-privileged.c: (usage), (main): + * tools/polkit-list-privileges.c: (main): + * tools/polkit-revoke-privilege.c: (main): + 2006-04-22 David Zeuthen * tools/polkit-list-privileges.c (main): Update to new D-BUS API; diff --git a/Makefile.am b/Makefile.am index 3252cdd..414fc91 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in -SUBDIRS = libpolkit polkitd doc tools privileges +SUBDIRS = libpolkit pam-polkit-console polkitd doc tools privileges pamdir = $(sysconfdir)/pam.d pam_DATA = policy-kit diff --git a/README b/README index 3c03364..2de5278 100644 --- a/README +++ b/README @@ -2,7 +2,6 @@ PolicyKit is a framework for defining policy for system-wide components and for desktop pieces to configure it. It is used by HAL. - See also the file HACKING for notes of interest to developers working on PolicyKit. diff --git a/configure.in b/configure.in index 17e4080..557aa59 100644 --- a/configure.in +++ b/configure.in @@ -1,8 +1,8 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.57) -AC_INIT(PolicyKit, 0.1, david@fubar.dk) -AM_INIT_AUTOMAKE(PolicyKit, 0.1) +AC_INIT(PolicyKit, 0.2, david@fubar.dk) +AM_INIT_AUTOMAKE(PolicyKit, 0.2) AM_CONFIG_HEADER(config.h) AM_MAINTAINER_MODE @@ -48,7 +48,7 @@ AC_DEFINE_UNQUOTED(POLKIT_GROUP,"$POLKIT_GROUP", [Group for PolicyKit]) # Taken from dbus AC_ARG_ENABLE(ansi, [ --enable-ansi enable -ansi -pedantic gcc flags],enable_ansi=$enableval,enable_ansi=no) AC_ARG_ENABLE(verbose-mode, [ --enable-verbose-mode support verbose debug mode],enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE) -AC_ARG_ENABLE(docbook-docs, [ --enable-docbook-docs build documentation (requires docbook2html)],enable_docbook_docs=$enableval,enable_docbook_docs=auto) +AC_ARG_ENABLE(docbook-docs, [ --enable-docbook-docs build documentation (requires xmlto)],enable_docbook_docs=$enableval,enable_docbook_docs=auto) GTK_DOC_CHECK([1.3]) @@ -150,7 +150,7 @@ AC_CHECK_FUNCS(getgrouplist) # DocBook Documentation -AC_PATH_PROG(DOCBOOK, docbook2html, no) +AC_PATH_PROG(XMLTO, xmlto, no) AC_MSG_CHECKING([whether to build DocBook documentation]) @@ -347,6 +347,7 @@ AC_OUTPUT([ policy-kit polkit.pc Makefile +pam-polkit-console/Makefile polkitd/Makefile polkitd/PolicyKit polkitd/PolicyKit.conf diff --git a/doc/TODO b/doc/TODO index 6921cea..ceeab48 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,2 +1,37 @@ -TODO +DONE + + - Write up a nice spec about how all this works since it can be a bit + confusing + + - Refine the .privilege file format so e.g. user 'foo' is always + allowed to grant privilege 'bar' to other users. Also other stuff. + + - write polkit-revoke-privilege + + - make polkit-list-privileges and polkit-is-privileged display if a + privilege is granted permanently or temporary. Also display if it's + confined to a certain D-BUS connection. + + - Factor out auth code in polkit-is-privileged into a GObject and put + it in a libpolkit-gobject library (since the interaction is pretty + hairy (see interaction diagram in polkitd/polkit-session.c) I will + not put this in libpolkit as I want to use the glib bindings and + these require the glib main loop => not suitable for Qt etc.) + +PENDING + + - Make polkitd emit signals on an interface such that privileged apps + can be notified when privileges are granted and revoked. Also + export other useful query operations. + + - make D-BUS interface in general and polkit-grant-privilege in + particular capable of granting privs permanently + + - write some man pages + + - write libpolkit-gnome that GNOME apps can consume + + - implement D-BUS interfaces suitable for a GUI privilege editor + + - write more tests; audit code diff --git a/doc/api/polkit-docs.xml b/doc/api/polkit-docs.xml index 8fceb3b..6d2245b 100644 --- a/doc/api/polkit-docs.xml +++ b/doc/api/polkit-docs.xml @@ -7,8 +7,9 @@ - Client library + Client libraries + diff --git a/doc/spec/Makefile.am b/doc/spec/Makefile.am index dc08beb..e64c56d 100644 --- a/doc/spec/Makefile.am +++ b/doc/spec/Makefile.am @@ -9,7 +9,7 @@ htmldocdir = $(DOCDIR)/spec htmldoc_DATA = polkit-spec.html $(FIGURE_FILES) polkit-spec.html : polkit-spec.xml $(FIGURE_FILES) - $(DOCBOOK) --nochunks polkit-spec.xml -o . + $(XMLTO) html-nochunks polkit-spec.xml clean-local: rm -f *~ diff --git a/doc/spec/polkit-spec.html b/doc/spec/polkit-spec.html index efcaf12..71d0776 100644 --- a/doc/spec/polkit-spec.html +++ b/doc/spec/polkit-spec.html @@ -1,235 +1,14 @@ - -PolicyKit 0.1 Specification

PolicyKit 0.1 Specification

David Zeuthen


-     <david@fubar.dk>
-   

Version 0.1

Table of Contents
Introduction
About
Theory of operation
Privileges
Architecture
Example
Resources
Resource Identifiers
Privileges
Privilege Descriptors
File Format
RequiredPrivileges: Required Privileges
Allow, Deny: Criteria for Possesing a Privilege
CanObtain: Obtaining Privileges
CanGrant: Granting Privileges
ObtainRequireRoot, ObtainPAMService: Authentication Requirements
Privileges defined by PolicyKit

Introduction

About

PolicyKit is a system for enabling unprivileged desktop +PolicyKit 0.2 Specification

PolicyKit 0.2 Specification

David Zeuthen


+     
+   

Version 0.2


Chapter 1. Introduction

Table of Contents

About

About

+ PolicyKit is a system for enabling unprivileged desktop applications to invoke privileged methods on system-wide components in a controlled manner. -


Theory of operation

Privileges

One major concept of the PolicyKit system is the notion of - privileges; a PolicyKit privilege +

Chapter 2. Theory of operation

Privileges

+ One major concept of the PolicyKit system is the notion of + privileges; a PolicyKit privilege (referred to simply as - privilege in the following) is something + privilege in the following) is something that a given user may or may not possess. The thinking behind PolicyKit is that privileged system level components offer functionality to unprivileged desktop applications as D-BUS @@ -237,693 +16,369 @@ CLASS="emphasis" a flexible security policy defining the set of users that are allowed to invoke a method, the system level component defines a set of - privileges. -


Architecture

The PolicyKit system is basically client/server and is + privileges. +

Architecture

+ The PolicyKit system is basically client/server and is implemented as the - system-wide org.freedesktop.PolicyKit D-BUS + system-wide org.freedesktop.PolicyKit D-BUS service. This D-BUS service serves two purposes -

  • System-level components may used D-BUS methods on this +

    • + System-level components may used D-BUS methods on this service to determine if a given caller of their methods are privileged. -

    • Desktop level applications may initiate a dialogue with +

    • + Desktop level applications may initiate a dialogue with this service to (temporarily) obtain a privilege through authorization. -

    In addition, the PolicyKit system includes client side +

+ In addition, the PolicyKit system includes client side libraries and command-line utilities wrapping the D-BUS API of - the org.freedesktop.PolicyKit service. -


Example

As an example, HAL exports the method Mount + the org.freedesktop.PolicyKit service. +

Example

+ As an example, HAL exports the method Mount on the - org.freedesktop.Hal.Device.Volume interface + org.freedesktop.Hal.Device.Volume interface for each hal device object of - capability volume. HAL defines a number + capability volume. HAL defines a number of privileges for mounting - including hal-storage-fixed-mount - and hal-storage-removable-mount. Depending + including hal-storage-fixed-mount + and hal-storage-removable-mount. Depending on the whether the volume stems from a fixed hard disk or a hotpluggable/removable drive, HAL requires the calling user to possess either - the hal-storage-fixed-mount - or hal-storage-removable-mount privilege - in order to carry out the Mount method. -

Upon a user invoking the Mount method, HAL - simply asks the org.freedesktop.PolicyKit - D-BUS service if the calling user posses this privilege and if - this is not the case the Mount method + the hal-storage-fixed-mount + or hal-storage-removable-mount privilege + in order to carry out the Mount method. +

+ Upon a user invoking the Mount method, HAL + simply asks the org.freedesktop.PolicyKit + D-BUS service if the calling user possess this privilege and if + this is not the case the Mount method throws - the org.freedesktop.Hal.Device.PermissionDeniedByPolicy + the org.freedesktop.Hal.Device.PermissionDeniedByPolicy exception. Notably, this exception will tell the caller what privilege the calling user needs to possess, - e.g. either hal-storage-fixed-mount - or hal-storage-removable-mount. -

Should the Mount method fail with the - exception PermissionDeniedByPolicy the + e.g. either hal-storage-fixed-mount + or hal-storage-removable-mount. +

+ Should the Mount method fail with the + exception PermissionDeniedByPolicy the caller now knows what privilege is required. The caller can - now initiate a dialogue with the PolicyKit + now initiate a dialogue with the PolicyKit service to obtain this privilege. This conversation is basically equivalent to a PAM authentication; in fact the - PolicyKit service uses PAM under the hood + PolicyKit service uses PAM under the hood and wraps it in D-BUS calls. For details (like what user to authenticate as) see XXX. When the caller obtains the privilege (after successful authentication) he can now - invoke Mount and after this succeeds he may - tell the PolicyKit service to release the + invoke Mount and after this succeeds he may + tell the PolicyKit service to release the privilege for the user as it is no longer needed. Should the process crash while holding a privilege, - the PolicyKit service will be notifed and + the PolicyKit service will be notifed and the privilege will automatically be revoked. -

Hence, PolicyKit has the notion of - both permament - and temporary privileges. The latter may +

+ Hence, PolicyKit has the notion of + both permament + and temporary privileges. The latter may even be restricted such that only callers from the D-BUS connection (remember, D-BUS connections has unique names) - obtaining the privilege may use the obtained privilege. -

In addition, privileges may be restricted to - certain resources; this is discussed in + obtaining the privilege may use the obtained + privilege. Consequently, if a temporary privilege is + restricted to a certain D-BUS connection, it is revoked when + the owner of this connection disconnects from the system + message bus. +

+ In addition, privileges may be restricted to + certain resources; this is discussed in more detail in XXX. -

-

The whole example is outlined in the diagram above. -


Resources

PolicyKit allows granting privileges only on - certain resources. For example, for HAL, it +

+ +

+ The whole example is outlined in the diagram above. +

Chapter 3. Resources

Table of Contents

Resource Identifiers

+ PolicyKit allows granting privileges only on + certain resources. For example, for HAL, it is possible to grant the - privilege hal-storage-fixed-mount to the + privilege hal-storage-fixed-mount to the user with uid 500 but only for the HAL device object - representing e.g. the /dev/hda3 partition. -


Resource Identifiers

Resource identifers are prefixed with a name identifying + representing e.g. the /dev/hda3 partition. +

Resource Identifiers

Resource identifers are prefixed with a name identifying what service they belong to. The following resource identifiers are defined -

  • hal:// - HAL Unique Device Identifiers also known as HAL UID's. Example: hal:///org/freedesktop/Hal/devices/volume_uuid_1a28b356_9955_44f9_b268_6ed6639978f5 -


Privileges

Privilege Descriptors

- Applications, such as HAL, installs privilege descriptors using the polkit-policy-descriptor-install commandline utility. The descriptor contains the following information -

  • Criteria for determining if a given user possess the privilege on a given resource. -

  • What other privileges a given user must also possess. -

  • Information on whether the user can obtain the privilege, and if he can, whether only temporarily or permanently. -

  • Whether a user with the privilege may permanently grant it to other users. -


File Format

A developer of a system-wide application wanting to define a +

  • + hal:// + HAL Unique Device Identifiers also known as HAL UID's. Example: hal:///org/freedesktop/Hal/devices/volume_uuid_1a28b356_9955_44f9_b268_6ed6639978f5 +

Chapter 4. Privileges

Privilege Descriptors

+ Applications, such as HAL, installs privilege + descriptors into + the /etc/PolicyKit/privilege.d directory + (or more correct, into + the $sysconfdir/PolicyKit/privilege.d + directory depending on where PolicyKit is built). +

+ A policy descriptor contains the following information: +

  • + Criteria for determining if a given user possess the privilege on a given resource. +

  • + What privileges are required to possess a given privilege. +

  • + What privileges are sufficient to possess to automatically possess a given privilege. +

  • + Information on whether the user can obtain the privilege, and if he can, whether only temporarily or permanently. +

  • + Whether a user with the privilege may permanently grant it to other users. +

File Format

+ A developer of a system-wide application wanting to define a privilege must create a privilege descriptor. This is a a - simple .ini-like config file. Here is what + simple .ini-like config file. Here is what the skeleton looks like: -


	[Policy]
+      

+	[Policy]
 	RequiredPrivileges=
+	SufficientPrivileges=
 	Allow=
 	Deny=
 	CanObtain=
 	CanGrant=
 	ObtainRequireRoot=
-	ObtainPAMService=
-      

RequiredPrivileges: Required Privileges

This is a list of privileges the user must possess in order +

RequiredPrivileges: Required Privileges

+ This is a list of privileges the user must possess in order to possess the given privilege. If the user doesn't possess all of these privileges he is not considered to possess the - given privilege. The list may be empty. -


Allow, Deny: Criteria for Possesing a Privilege

Both Allow and Deny + given privilege. The list may be empty. A privilege in this + list is considered being possessed if the user is privileged + for one or more resources. E.g., if foo + is a required privilege then just having this privilege on + one resource is sufficient. +

SufficientPrivileges: Sufficient Privileges

+ This is a list of privileges that, if a user possess any of + these, he is consider to possess the given privilege. The + list may be empty. A privilege in this list is considered + being possessed if the user is privileged for one or more + resources. As with RequiredPrivileges, + if foo is a sufficient privilege then + just having this privilege on one resource is sufficient. +

Allow, Deny: Criteria for Possesing a Privilege

+ Both Allow and Deny contains lists describing what users are allowed respectively denied the privilege. The elements of in each list are of the form - type:value[:resource]. where the last + type:value[:resource]. where the last part, resource, may be omitted. The following types are supported: -

  • uid: Unix user identifer; either +

    • uid: Unix user identifer; either a positive integer or Unix username. Special values - include __all__ (for denoting all - users) and __none__ (for denoting no - users).

    • gid: Unix group identifier, + include __all__ (for denoting all + users) and __none__ (for denoting no + users).

    • gid: Unix group identifier, either a positive integer or Unix groupname. Special - values include __all__ (for denoting - all groups) and __none__ (for denoting - no groups).

    To determine if a given user is allowed for a given + values include __all__ (for denoting + all groups) and __none__ (for denoting + no groups).

+ To determine if a given user is allowed for a given privilege (for a given resource), first - the RequiredPrivileges list is consulted - as described above. If the user possess all of the listed - privileges, the Allow list is now - consulted. For each element we it is tested whether the user - matches. If there are no elements for which the user is + the SufficientPrivileges list is + consulted as described above. If the user possesses one or + more of the listed privileges we're done; the user is + automatically allowed for the given privilege. If this is + not the case, the RequiredPrivileges list + is consulted as described above. If the user possess all of + the listed privileges, the Allow list is + now consulted. For each element it is tested whether the + user matches. If there are no elements for which the user is matches, the user is said not to possess the given privilege (for the given resource). -

If there is a match in the Allow list, - the Deny list is now consulted. If the +

+ If there is a match in the Allow list, + the Deny list is now consulted. If the user matches any of the elements we know he doesn't possess the given privilege. If no elements match we can conclude that the user indeed possesses the given privilege (for the given resource). -

This logic is best described by a few examples -

  • Allow="uid:davidz uid:501:hal:///deviceFoo gid:admins +

    + This logic is best described by a few examples +

    • + + Allow="uid:davidz uid:501:hal:///deviceFoo gid:admins uid:502" - -

      Deny="gid:dooders uid:502:hal:///deviceBar" - -

      User davidz possess this + +

      + + Deny="gid:dooders uid:502:hal:///deviceBar" + +

      + User davidz possess this privilege. All members of - the dooders group is denied this + the dooders group is denied this privilege. User 501 is allowed this privilege but only - on the hal:///deviceFoo - resource. All users in the admin + on the hal:///deviceFoo + resource. All users in the admin group posseses the privilege. User 502 is allowed this privilege but not on - the hal:///deviceBar + the hal:///deviceBar resource. -

    • Allow="uid:__all__" - -

      Deny="gid:normalstaff" - -

      All users expect those in - the normalstaff group posseses this +

    • + + Allow="uid:__all__" + +

      + + Deny="gid:normalstaff" + +

      + All users expect those in + the normalstaff group posseses this privilege. -


    CanObtain: Obtaining Privileges

    This property denotes whether an user can obtain the - privilege by authentication. It can assume the values - True (the user can obtain the privilege - permanently), Temporary (the user can +

CanObtain: Obtaining Privileges

+ This property denotes whether an user can obtain the + privilege by authentication. This is useful when either + either the privilege in question or one of the privileges + listed in RequiredPrivileges is not + possessed. +

+ The property can assume the values + True (the user can obtain the privilege + permanently), Temporary (the user can only obtain the privilege temporarily) and - False (the user can never obtain the - privilege through authentication). -

The authentication required are specified in - the ObtainRequireRoot - and ObtainPAMService properties. -


CanGrant: Granting Privileges

This property (it can assume the - values True and False) - describes whether an user with the given privilege can grant - it to other users, e.g. modify the Allow - and Deny properties. -

The property CanObtain needs to have the - value True if this property assumes the - value True. -


ObtainRequireRoot, ObtainPAMService: Authentication Requirements

If the property CanObtain assumes the - value True - or Temporary it means the user can - authenticate to gain a privilege. -

The ObtainRequireRoot property specifies - whether authentication requires the super user password - (True) or the users own password - (False). In addition, it can be specified - what PAM service (for example pam_rps) is - to be used for authentication through the - property ObtainPAMService. -

\ No newline at end of file + False (the user can never obtain the + privilege through authentication). +

+ Whether the user needs to autenticate as himself or the + super user is specified in + the ObtainRequireRoot property. Note that + if the user is lacking one or more of the privileges listed + in RequiredPrivileges and one of these + has ObtainRequireRoot=True the user will + have to authenticate as the super user nonwithstanding that + the privilege he attempts to obtain + has ObtainRequireRoot=False. Moreover, if + any of the lacking privileges + in RequiredPrivileges + has CanObtain set + to False, the user will always have to + authenticate as the super user. +

CanGrant: Granting Privileges

+ This property (it can assume the + values True and False) + describes whether an user with the given privilege can + permanently grant it to himself and/or other users,. +

+ Typically, the construct is used in the following kind of UI + dialogs: +

+    +----------------------------------------------------+
+    | You are not privileged to access the volume        |
+    | 'Dave's USB key'. You need to authenticate as the  |
+    | system administrator                               |
+    |                                                    |
+    |   Super user password: [_______________]           |
+    |                                                    |
+    |   Would you also like to automatically allow       |
+    |                                                    |
+    |  (*) This user to mount 'Dave's USB key'           |
+    |  ( ) Any user to mount 'Dave's USB key'            |
+    |  ( ) This user to mount a removable storage device |
+    |  ( ) Any user to mount a removable storage device  |
+    |                                                    |
+    | [Cancel]                                   [Mount] |
+    +----------------------------------------------------+
+       (TODO: replace with screenshot from gnome-mount)
+	

+ The property CanObtain needs to assume + the value True if this property assumes + the value True. Otherwise this property + effectively assumes the value False. +

ObtainRequireRoot: Authentication Requirements

+ If the property CanObtain assumes the + value True + or Temporary it means the user can + authenticate to gain a + privilege. The ObtainRequireRoot property + specifies whether authentication requires the super user + password (True) or the users own password + (False). +

+ See the section called “CanObtain: Obtaining Privileges” for discussion on how + the RequiredPrivileges property affects + the effective value of this property. +

Privileges defined by PolicyKit

+ This section describe privileges defined by PolicyKit and how + they can be used by other pieces of software. Some privileges + have special meaning and affects how PolicyKit works. +

desktop-console : Users at a local console

+desktop-console.privilege:
+
+# This privilege signfies that users holding it are logged into a
+# physical console attached to the system. Thus, it is useful for
+# other privileges for manipulating local devices to simply require
+# this privilege. 
+
+[Privilege]
+RequiredPrivileges=
+SufficientPrivileges=
+Allow=
+Deny=
+CanObtain=Temporary
+CanGrant=False
+ObtainRequireRoot=True
+	

+ This privilege signifies that the user holding it is logged + in at a local console. In this context, "local console" + means that the display / keyboard / pointing device is local + to the system which implies the user got physical access to + the box. +

+ The PAM module pam-polkit-console shipped + with PolicyKit is used to maintain files + in /var/run/polkit-console for users + logging in and out, and signal the PolicyKit daemon to + reread these files and dynamically grant / revoke + the desktop-console privilege. Typically, + graphical login managers such as the GNOME Display Manager + (gdm) will want include this in it's stack of PAM modules. +

+ Remote users (e.g. those not at a local console) can obtain + the desktop-console only by + authenticating as the super user. +

+ The desktop-console privilege can be used + in conjunction with + the RequiredPrivileges property in a + privilege descriptor to ensure only users at a local console + is entitled to a privilege for putting a system to sleep + without having to autenticate. This is achieved by e.g. this + privilege descriptor: +

+hal-system-suspend.privilege:
+
+# This privilege specifies who is allowed to suspend the system.
+
+[Privilege]
+RequiredPrivileges=desktop-console
+SufficientPrivileges=
+Allow=uid:__all__
+Deny=
+CanObtain=True
+CanGrant=True
+ObtainRequireRoot=False
+	

+ For a remote user with the + privilege hal-system-suspend it means + that authentication as the super user is required + as desktop-console + has ObtainRequireRoot=True and this + trumps the ObtainRequireRoot=False + property that is in + the hal-system-suspend privilege (see + the section called “CanObtain: Obtaining Privileges”). Of course, if the user is + logged in at a local console no authentication is required. +

+ Typically, the desktop-console privilege + is granted on a specific resource, namely what console the + user is logged into. At the time of writing, this resource + can only be consider an opaque identifier (such + as console://:0 which refers to X11 + display ":0") and one cannot assign meaning to it. In the + future, it may be possible to assign meaning to it. +

diff --git a/doc/spec/polkit-spec.xml.in b/doc/spec/polkit-spec.xml.in index 3111c91..ddc4277 100644 --- a/doc/spec/polkit-spec.xml.in +++ b/doc/spec/polkit-spec.xml.in @@ -6,9 +6,9 @@ - PolicyKit 0.1 Specification - Version 0.1 - March 28th, 2006 + PolicyKit 0.2 Specification + Version 0.2 + May 12th, 2006 David @@ -120,7 +120,7 @@ Upon a user invoking the Mount method, HAL simply asks the org.freedesktop.PolicyKit - D-BUS service if the calling user posses this privilege and if + D-BUS service if the calling user possess this privilege and if this is not the case the Mount method throws the org.freedesktop.Hal.Device.PermissionDeniedByPolicy @@ -155,7 +155,11 @@ and temporary privileges. The latter may even be restricted such that only callers from the D-BUS connection (remember, D-BUS connections has unique names) - obtaining the privilege may use the obtained privilege. + obtaining the privilege may use the obtained + privilege. Consequently, if a temporary privilege is + restricted to a certain D-BUS connection, it is revoked when + the owner of this connection disconnects from the system + message bus. @@ -215,8 +219,17 @@ Privilege Descriptors - - Applications, such as HAL, installs privilege descriptors using the polkit-policy-descriptor-install commandline utility. The descriptor contains the following information + + Applications, such as HAL, installs privilege + descriptors into + the /etc/PolicyKit/privilege.d directory + (or more correct, into + the $sysconfdir/PolicyKit/privilege.d + directory depending on where PolicyKit is built). + + + + A policy descriptor contains the following information: @@ -228,7 +241,13 @@ - What other privileges a given user must also possess. + What privileges are required to possess a given privilege. + + + + + + What privileges are sufficient to possess to automatically possess a given privilege. @@ -259,12 +278,12 @@ [Policy] RequiredPrivileges= + SufficientPrivileges= Allow= Deny= CanObtain= CanGrant= ObtainRequireRoot= - ObtainPAMService= @@ -273,7 +292,24 @@ This is a list of privileges the user must possess in order to possess the given privilege. If the user doesn't possess all of these privileges he is not considered to possess the - given privilege. The list may be empty. + given privilege. The list may be empty. A privilege in this + list is considered being possessed if the user is privileged + for one or more resources. E.g., if foo + is a required privilege then just having this privilege on + one resource is sufficient. + + + + + <literal>SufficientPrivileges</literal>: Sufficient Privileges + + This is a list of privileges that, if a user possess any of + these, he is consider to possess the given privilege. The + list may be empty. A privilege in this list is considered + being possessed if the user is privileged for one or more + resources. As with RequiredPrivileges, + if foo is a sufficient privilege then + just having this privilege on one resource is sufficient. @@ -308,11 +344,15 @@ To determine if a given user is allowed for a given privilege (for a given resource), first - the RequiredPrivileges list is consulted - as described above. If the user possess all of the listed - privileges, the Allow list is now - consulted. For each element we it is tested whether the user - matches. If there are no elements for which the user is + the SufficientPrivileges list is + consulted as described above. If the user possesses one or + more of the listed privileges we're done; the user is + automatically allowed for the given privilege. If this is + not the case, the RequiredPrivileges list + is consulted as described above. If the user possess all of + the listed privileges, the Allow list is + now consulted. For each element it is tested whether the + user matches. If there are no elements for which the user is matches, the user is said not to possess the given privilege (for the given resource). @@ -378,22 +418,42 @@ - + <literal>CanObtain</literal>: Obtaining Privileges This property denotes whether an user can obtain the - privilege by authentication. It can assume the values + privilege by authentication. This is useful when either + either the privilege in question or one of the privileges + listed in RequiredPrivileges is not + possessed. + + + + The property can assume the values True (the user can obtain the privilege permanently), Temporary (the user can only obtain the privilege temporarily) and False (the user can never obtain the - privilege through authentication). + privilege through authentication). + - The authentication required are specified in - the ObtainRequireRoot - and ObtainPAMService properties. + Whether the user needs to autenticate as himself or the + super user is specified in + the ObtainRequireRoot property. Note that + if the user is lacking one or more of the privileges listed + in RequiredPrivileges and one of these + has ObtainRequireRoot=True the user will + have to authenticate as the super user nonwithstanding that + the privilege he attempts to obtain + has ObtainRequireRoot=False. Moreover, if + any of the lacking privileges + in RequiredPrivileges + has CanObtain set + to False, the user will always have to + authenticate as the super user. + @@ -401,43 +461,166 @@ This property (it can assume the values True and False) - describes whether an user with the given privilege can grant - it to other users, e.g. modify the Allow - and Deny properties. + describes whether an user with the given privilege can + permanently grant it to himself and/or other users,. + + + Typically, the construct is used in the following kind of UI + dialogs: + + + +----------------------------------------------------+ + | You are not privileged to access the volume | + | 'Dave's USB key'. You need to authenticate as the | + | system administrator | + | | + | Super user password: [_______________] | + | | + | Would you also like to automatically allow | + | | + | (*) This user to mount 'Dave's USB key' | + | ( ) Any user to mount 'Dave's USB key' | + | ( ) This user to mount a removable storage device | + | ( ) Any user to mount a removable storage device | + | | + | [Cancel] [Mount] | + +----------------------------------------------------+ + (TODO: replace with screenshot from gnome-mount) + + - The property CanObtain needs to have the - value True if this property assumes the - value True. + The property CanObtain needs to assume + the value True if this property assumes + the value True. Otherwise this property + effectively assumes the value False. - <literal>ObtainRequireRoot, ObtainPAMService</literal>: Authentication Requirements + <literal>ObtainRequireRoot</literal>: Authentication Requirements If the property CanObtain assumes the value True or Temporary it means the user can - authenticate to gain a privilege. + authenticate to gain a + privilege. The ObtainRequireRoot property + specifies whether authentication requires the super user + password (True) or the users own password + (False). - The ObtainRequireRoot property specifies - whether authentication requires the super user password - (True) or the users own password - (False). In addition, it can be specified - what PAM service (for example pam_rps) is - to be used for authentication through the - property ObtainPAMService. + See for discussion on how + the RequiredPrivileges property affects + the effective value of this property. - + Privileges defined by PolicyKit - baz + This section describe privileges defined by PolicyKit and how + they can be used by other pieces of software. Some privileges + have special meaning and affects how PolicyKit works. + + + <literal>desktop-console</literal> : Users at a local console + + +desktop-console.privilege: + +# This privilege signfies that users holding it are logged into a +# physical console attached to the system. Thus, it is useful for +# other privileges for manipulating local devices to simply require +# this privilege. + +[Privilege] +RequiredPrivileges= +SufficientPrivileges= +Allow= +Deny= +CanObtain=Temporary +CanGrant=False +ObtainRequireRoot=True + + + + This privilege signifies that the user holding it is logged + in at a local console. In this context, "local console" + means that the display / keyboard / pointing device is local + to the system which implies the user got physical access to + the box. + + + + The PAM module pam-polkit-console shipped + with PolicyKit is used to maintain files + in /var/run/polkit-console for users + logging in and out, and signal the PolicyKit daemon to + reread these files and dynamically grant / revoke + the desktop-console privilege. Typically, + graphical login managers such as the GNOME Display Manager + (gdm) will want include this in it's stack of PAM modules. + + + + Remote users (e.g. those not at a local console) can obtain + the desktop-console only by + authenticating as the super user. + + + + The desktop-console privilege can be used + in conjunction with + the RequiredPrivileges property in a + privilege descriptor to ensure only users at a local console + is entitled to a privilege for putting a system to sleep + without having to autenticate. This is achieved by e.g. this + privilege descriptor: + + + +hal-system-suspend.privilege: + +# This privilege specifies who is allowed to suspend the system. + +[Privilege] +RequiredPrivileges=desktop-console +SufficientPrivileges= +Allow=uid:__all__ +Deny= +CanObtain=True +CanGrant=True +ObtainRequireRoot=False + + + + For a remote user with the + privilege hal-system-suspend it means + that authentication as the super user is required + as desktop-console + has ObtainRequireRoot=True and this + trumps the ObtainRequireRoot=False + property that is in + the hal-system-suspend privilege (see + ). Of course, if the user is + logged in at a local console no authentication is required. + + + + Typically, the desktop-console privilege + is granted on a specific resource, namely what console the + user is logged into. At the time of writing, this resource + can only be consider an opaque identifier (such + as console://:0 which refers to X11 + display ":0") and one cannot assign meaning to it. In the + future, it may be possible to assign meaning to it. + + + diff --git a/libpolkit/Makefile.am b/libpolkit/Makefile.am index a64391f..a533e86 100644 --- a/libpolkit/Makefile.am +++ b/libpolkit/Makefile.am @@ -12,7 +12,7 @@ INCLUDES = \ @GLIB_CFLAGS@ \ @DBUS_GLIB_CFLAGS@ -lib_LTLIBRARIES=libpolkit.la +lib_LTLIBRARIES=libpolkit.la libpolkit-grant.la libpolkitincludedir=$(includedir)/libpolkit @@ -26,6 +26,29 @@ libpolkit_la_LIBADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ libpolkit_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) + +libpolkit_grantincludedir=$(includedir)/libpolkit + +libpolkit_grantinclude_HEADERS = \ + libpolkit-grant.h + +libpolkit_grant_la_SOURCES = \ + libpolkit-grant.c libpolkit-grant.h \ + polkit-interface-manager-glue.h \ + polkit-interface-session-glue.h + +libpolkit_grant_la_LIBADD = @DBUS_GLIB_LIBS@ @GLIB_LIBS@ + +libpolkit_grant_la_LDFLAGS = -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) + +polkit-interface-manager-glue.h: ../polkit-interface-manager.xml Makefile.am + dbus-binding-tool --prefix=polkit_manager --mode=glib-client --output=polkit-interface-manager-glue.h ../polkit-interface-manager.xml + +polkit-interface-session-glue.h: ../polkit-interface-session.xml Makefile.am + dbus-binding-tool --prefix=polkit_session --mode=glib-client --output=polkit-interface-session-glue.h ../polkit-interface-session.xml + +BUILT_SOURCES = polkit-interface-manager-glue.h polkit-interface-session-glue.h + clean-local : - rm -f *~ + rm -f *~ $(BUILT_SOURCES) diff --git a/libpolkit/libpolkit-grant.c b/libpolkit/libpolkit-grant.c new file mode 100644 index 0000000..4e9e7d1 --- /dev/null +++ b/libpolkit/libpolkit-grant.c @@ -0,0 +1,407 @@ +/*************************************************************************** + * + * libpolkit-grant.c : Wraps temporary grant methods on the PolicyKit daemon + * + * Copyright (C) 2006 David Zeuthen, + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "libpolkit-grant.h" + +#include "polkit-interface-manager-glue.h" +#include "polkit-interface-session-glue.h" + +struct LibPolKitGrantContext_s +{ + DBusGConnection *dbus_g_connection; + char *user; + char *privilege; + char *resource; + gboolean restrict_to_dbus_connection; + + LibPolKitGrantQuestions questions_handler; + LibPolKitGrantComplete grant_complete_handler; + + char *auth_user; + char *auth_service_name; + + DBusGProxy *manager; + DBusGProxy *session; + + LibPolKitContext *polkit_ctx; + + gpointer user_data; +}; + + +static void +have_questions_handler (DBusGProxy *session, gpointer user_data) +{ + char **questions; + GError *error = NULL; + LibPolKitGrantContext *ctx = (LibPolKitGrantContext *) user_data; + gboolean should_continue; + + should_continue = FALSE; + + if (!org_freedesktop_PolicyKit_Session_get_questions (ctx->session, + &questions, + &error)) { + g_warning ("GetQuestions: %s", error->message); + + /* we're done */ + ctx->grant_complete_handler (ctx, FALSE, error->message, ctx->user_data); + + g_error_free (error); + + } else { + ctx->questions_handler (ctx, (const char **) questions, ctx->user_data); + g_strfreev (questions); + } +} + +void +libpolkit_grant_provide_answers (LibPolKitGrantContext *ctx, const char **answers) +{ + GError *error = NULL; + + if (!org_freedesktop_PolicyKit_Session_provide_answers (ctx->session, + (const char **) answers, + &error)) { + g_warning ("ProvideAnswers: %s", error->message); + + /* we're done */ + ctx->grant_complete_handler (ctx, FALSE, error->message, ctx->user_data); + + g_error_free (error); + } +} + + +static void +auth_done_handler (DBusGProxy *session, gpointer user_data) +{ + gboolean auth_result; + //gboolean was_revoked; + GError *error = NULL; + LibPolKitGrantContext *ctx = (LibPolKitGrantContext *) user_data; + + /*g_debug ("in %s", __FUNCTION__);*/ + + if (!org_freedesktop_PolicyKit_Session_is_authenticated (session, + &auth_result, + &error)) { + g_warning ("IsAuthenticated: %s", error->message); + + /* we're done */ + ctx->grant_complete_handler (ctx, FALSE, error->message, ctx->user_data); + + g_error_free (error); + goto out; + } + + /*g_message ("Authentication done. %s", auth_result);*/ + + if (!auth_result) { + char *auth_denied_reason; + + if (!org_freedesktop_PolicyKit_Session_get_auth_denied_reason (session, + &auth_denied_reason, + &error)) { + g_warning ("GetAuthDeniedReason: %s", error->message); + g_error_free (error); + goto out; + } + + /*g_print ("\n" + "Authentication failed (reason: '%s').\n", auth_denied_reason);*/ + + /* we're done */ + ctx->grant_complete_handler (ctx, FALSE, auth_denied_reason, ctx->user_data); + + g_free (auth_denied_reason); + + } else { + /*g_print ("\n" + "Authentication succeeded.\n");*/ + + /* don't restrict privilege to callers unique system bus connection name */ + if (!org_freedesktop_PolicyKit_Session_grant_privilege_temporarily (session, + ctx->restrict_to_dbus_connection, + &error)) { + g_warning ("GrantPrivilegeTemporarily: %s", error->message); + + /* we're done */ + ctx->grant_complete_handler (ctx, FALSE, error->message, ctx->user_data); + + g_error_free (error); + + + } else { + /* we're done */ + ctx->grant_complete_handler (ctx, TRUE, NULL, ctx->user_data); + + } + + } + + + //sleep (20); + + //libpolkit_revoke_temporary_privilege (ctx, grant_user, grant_privilege, grant_resource, &was_revoked); + //g_debug ("was revoked = %d", was_revoked); + //sleep (10000); + +out: + ; +} + + +/** + * libpolkit_grant_new_context: + * @user: User to request privilege for + * @privilege: Privilege to ask for + * @resource: Resource to ask for. May be NULL. + * @restrict_to_dbus_connection: Whether the privilege should be restricted to a particular D-BUS connection on the + * system message bus. + * @user_data: User data to be passed to callbacks + * + * Create a new context for obtaining a privilege. + * + * Returns: The context. It is an opaque data structure. Free with libpolkit_grant_free_context. + */ + +LibPolKitGrantContext* +libpolkit_grant_new_context (DBusGConnection *dbus_g_connection, + const char *user, + const char *privilege, + const char *resource, + gboolean restrict_to_dbus_connection, + gpointer user_data) +{ + LibPolKitGrantContext* ctx; + + ctx = g_new (LibPolKitGrantContext, 1); + ctx->dbus_g_connection = dbus_g_connection; + ctx->user = g_strdup (user); + ctx->privilege = g_strdup (privilege); + ctx->resource = g_strdup (resource); + ctx->restrict_to_dbus_connection = restrict_to_dbus_connection; + ctx->questions_handler = NULL; + ctx->grant_complete_handler = NULL; + ctx->user_data = user_data; + + ctx->auth_user = NULL; + ctx->auth_service_name = NULL; + + ctx->polkit_ctx = libpolkit_new_context (dbus_g_connection_get_connection (dbus_g_connection)); + + return ctx; +} + +LibPolKitContext* +libpolkit_grant_get_libpolkit_context (LibPolKitGrantContext *ctx) +{ + return ctx->polkit_ctx; +} + +void +libpolkit_grant_set_questions_handler (LibPolKitGrantContext *ctx, + LibPolKitGrantQuestions questions_handler) +{ + ctx->questions_handler = questions_handler; +} + +void +libpolkit_grant_set_grant_complete_handler (LibPolKitGrantContext *ctx, + LibPolKitGrantComplete grant_complete_handler) +{ + ctx->grant_complete_handler = grant_complete_handler; +} + +gboolean +libpolkit_grant_initiate_temporary_grant (LibPolKitGrantContext *ctx) +{ + GError *error = NULL; + char *session_objpath; + gboolean rc; + + rc = FALSE; + if (ctx->questions_handler == NULL || + ctx->grant_complete_handler == NULL) + goto out; + + ctx->manager = dbus_g_proxy_new_for_name (ctx->dbus_g_connection, + "org.freedesktop.PolicyKit", + "/org/freedesktop/PolicyKit/Manager", + "org.freedesktop.PolicyKit.Manager"); + if (ctx->manager == NULL) + goto out; + + if (!org_freedesktop_PolicyKit_Manager_initiate_temporary_privilege_grant (ctx->manager, + ctx->user, + ctx->privilege, + ctx->resource, + &session_objpath, + &error)) { + g_warning ("GrantPrivilege: %s", error->message); + g_error_free (error); + goto out; + } + + /*g_debug ("session_objpath = %s", session_objpath);*/ + + ctx->session = dbus_g_proxy_new_for_name (ctx->dbus_g_connection, + "org.freedesktop.PolicyKit", + session_objpath, + "org.freedesktop.PolicyKit.Session"); + if (ctx->session == NULL) + goto out; + + dbus_g_proxy_add_signal (ctx->session, "HaveQuestions", G_TYPE_INVALID); + dbus_g_proxy_connect_signal (ctx->session, "HaveQuestions", G_CALLBACK (have_questions_handler), + (void *) ctx, NULL); + + dbus_g_proxy_add_signal (ctx->session, "AuthenticationDone", G_TYPE_INVALID); + dbus_g_proxy_connect_signal (ctx->session, "AuthenticationDone", G_CALLBACK (auth_done_handler), + (void *) ctx, NULL); + + if (!org_freedesktop_PolicyKit_Session_get_auth_details (ctx->session, + &ctx->auth_user, + &ctx->auth_service_name, + &error)) { + g_warning ("GetAuthDetails: %s", error->message); + g_error_free (error); + goto out; + } + + if (!org_freedesktop_PolicyKit_Session_initiate_auth (ctx->session, + &error)) { + g_warning ("InitiateAuth: %s", error->message); + g_error_free (error); + /* TODO: LIBPOLKIT_GRANT_RESULT_NO_SUCH_PRIVILEGE, LIBPOLKIT_GRANT_RESULT_CANNOT_AUTH_FOR_PRIVILEGE */ + goto out; + } + + + g_free (session_objpath); + + rc = TRUE; +out: + + return rc; +} + + +const char* +libpolkit_grant_get_user_for_auth (LibPolKitGrantContext *ctx) +{ + return ctx->auth_user; +} + +const char* +libpolkit_grant_get_pam_service_for_auth (LibPolKitGrantContext *ctx) +{ + return ctx->auth_service_name; +} + +gboolean +libpolkit_grant_close (LibPolKitGrantContext *ctx, + gboolean revoke_privilege) +{ + GError *error = NULL; + + /* got the privilege; now close the session.. */ + if (!org_freedesktop_PolicyKit_Session_close (ctx->session, + &error)) { + g_warning ("Close: %s", error->message); + g_error_free (error); + } + + if (revoke_privilege) { + gboolean was_revoked; + + libpolkit_revoke_temporary_privilege (ctx->polkit_ctx, + ctx->user, + ctx->privilege, + ctx->resource, + &was_revoked); + + if (!was_revoked) { + g_warning ("Couldn't revoke privilege"); + } + + } + + return TRUE; +} + +void +libpolkit_grant_free_context (LibPolKitGrantContext *ctx) +{ + g_free (ctx->user); + g_free (ctx->privilege); + g_free (ctx->resource); + g_free (ctx->auth_user); + g_free (ctx->auth_service_name); + libpolkit_free_context (ctx->polkit_ctx); + g_free (ctx); +} + +const char* +libpolkit_grant_get_user (LibPolKitGrantContext *ctx) +{ + return ctx->user; +} + +const char* +libpolkit_grant_get_privilege (LibPolKitGrantContext *ctx) +{ + return ctx->privilege; +} + +/** + * libpolkit_grant_get_resource: + * @ctx: Context + * + * Get the resource as passed in from libpolkit_grant_new_context. + * + * Returns: The resource. May be NULL. + */ +const char* +libpolkit_grant_get_resource (LibPolKitGrantContext *ctx) +{ + return ctx->resource; +} + diff --git a/libpolkit/libpolkit-grant.h b/libpolkit/libpolkit-grant.h new file mode 100644 index 0000000..156aac1 --- /dev/null +++ b/libpolkit/libpolkit-grant.h @@ -0,0 +1,125 @@ +/*************************************************************************** + * + * libpolkit-grant.h : Wraps temporary grant methods on the PolicyKit daemon + * + * Copyright (C) 2006 David Zeuthen, + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + **************************************************************************/ + +#ifndef LIBPOLKIT_GRANT_H +#define LIBPOLKIT_GRANT_H + +#include +#include +#include +#include +#include +#include +#include + +#include + + +struct LibPolKitGrantContext_s; +typedef struct LibPolKitGrantContext_s LibPolKitGrantContext; + +/** + * LibPolKitGrantQuestions: + * @ctx: Context + * @questions: NULL terminated series of pairs. Each pair represent one question. + * @user_data: User data + * + * Callback when information is needed from the user in order to + * authenticate. + * + * The first component of the each pair in the questions array denote + * the question type. It can assume the values "PamPromptEchoOff" + * (meaning prompt for answer but don't echo it on the screen as the + * user types it), "PamPromptEchoOn" (meaning prompt for answer and + * echo the answer on the screen as the user types it), "PamErrorMsg" + * (display the message as an error message to the user) and + * "PamTextInfo" (textual information to the user). The second + * component in the pair is the actual question or information + * (e.g. "Password:") and it should be shown to the user next to the + * text input box. + * + * The callee should call libpolkit_grant_provide_answers with a + * string array once it the answers have been obtained from the user. + * + */ +typedef void (*LibPolKitGrantQuestions) (LibPolKitGrantContext *ctx, + const char **questions, + gpointer user_data); + +/** + * LibPolKitGrantComplete: + * @obtained_privilege: Whether the user sucessfully authenticated + * and was granted the privilege. + * @reason_not_obtained: If the user did not obtain the privilege + * this is the reason. May be NULL. + * @user_data: User data + * + * Callback when authorization was complete or there was an error. + * + */ +typedef void (*LibPolKitGrantComplete) (LibPolKitGrantContext *ctx, + gboolean obtained_privilege, + const char *reason_not_obtained, + gpointer user_data); + + +LibPolKitGrantContext* libpolkit_grant_new_context (DBusGConnection *dbus_g_connection, + const char *user, + const char *privilege, + const char *resource, + gboolean restrict_to_dbus_connection, + gpointer user_data); + +const char* libpolkit_grant_get_user (LibPolKitGrantContext *ctx); + +const char* libpolkit_grant_get_privilege (LibPolKitGrantContext *ctx); + +const char* libpolkit_grant_get_resource (LibPolKitGrantContext *ctx); + +LibPolKitContext* libpolkit_grant_get_libpolkit_context (LibPolKitGrantContext *ctx); + +void libpolkit_grant_set_questions_handler (LibPolKitGrantContext *ctx, + LibPolKitGrantQuestions questions_handler); + +void libpolkit_grant_set_grant_complete_handler (LibPolKitGrantContext *ctx, + LibPolKitGrantComplete grant_complete_handler); + +gboolean libpolkit_grant_initiate_temporary_grant (LibPolKitGrantContext *ctx); + +const char* libpolkit_grant_get_user_for_auth (LibPolKitGrantContext *ctx); + +const char* libpolkit_grant_get_pam_service_for_auth (LibPolKitGrantContext *ctx); + +void libpolkit_grant_provide_answers (LibPolKitGrantContext *ctx, + const char **answers); + +gboolean libpolkit_grant_close (LibPolKitGrantContext *ctx, + gboolean revoke_privilege); + +void libpolkit_grant_free_context (LibPolKitGrantContext *ctx); + + +#endif /* LIBPOLKIT_GRANT_H */ + + diff --git a/libpolkit/libpolkit.c b/libpolkit/libpolkit.c index b4a78f5..a00283b 100644 --- a/libpolkit/libpolkit.c +++ b/libpolkit/libpolkit.c @@ -54,8 +54,8 @@ return _ret_; \ } \ if (_ctx_->magic != LIBPOLKIT_MAGIC) { \ - g_warning ("%s: given LibPolKitContext is invalid", \ - __FUNCTION__); \ + g_warning ("%s: given LibPolKitContext is invalid (read magic 0x%08x, should be 0x%08x)", \ + __FUNCTION__, _ctx_->magic, LIBPOLKIT_MAGIC); \ return _ret_; \ } \ } while(0) @@ -102,7 +102,8 @@ LibPolKitResult libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx, const char *user, const char *privilege, - GList **result, + GList **resources, + GList **restrictions, int *num_non_temporary) { LibPolKitResult res; @@ -111,12 +112,15 @@ libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx, DBusError error; char **resource_list; int num_resources; + char **restriction_list; + int num_restrictions; int i; LIBPOLKIT_CHECK_CONTEXT (ctx, LIBPOLKIT_RESULT_INVALID_CONTEXT); res = LIBPOLKIT_RESULT_ERROR; - *result = NULL; + *resources = NULL; + *restrictions = NULL; message = dbus_message_new_method_call ("org.freedesktop.PolicyKit", "/org/freedesktop/PolicyKit/Manager", @@ -149,6 +153,7 @@ libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx, if (!dbus_message_get_args (reply, &error, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &resource_list, &num_resources, + DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &restriction_list, &num_restrictions, DBUS_TYPE_INT32, num_non_temporary, DBUS_TYPE_INVALID)) { g_warning ("Could not extract args from D-BUS message: %s : %s", error.name, error.message); @@ -157,10 +162,15 @@ libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx, } for (i = 0; i < num_resources; i++) { - *result = g_list_append (*result, g_strdup (resource_list[i])); + *resources = g_list_append (*resources, g_strdup (resource_list[i])); } dbus_free_string_array (resource_list); + for (i = 0; i < num_restrictions; i++) { + *restrictions = g_list_append (*restrictions, g_strdup (restriction_list[i])); + } + dbus_free_string_array (restriction_list); + res = LIBPOLKIT_RESULT_OK; out: @@ -172,25 +182,28 @@ out: } LibPolKitResult -libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx, - pid_t pid, - const char *user, - const char *privilege, - const char *resource, - gboolean *is_allowed, - gboolean *is_temporary) +libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx, + const char *system_bus_unique_name, + const char *user, + const char *privilege, + const char *resource, + gboolean *out_is_allowed, + gboolean *out_is_temporary, + char **out_is_privileged_but_restricted_to_system_bus_unique_name) { LibPolKitResult res; DBusMessage *message = NULL; DBusMessage *reply = NULL; DBusError error; const char *myresource = ""; + const char *mysystem_bus_unique_name = ""; + char *but_restricted_to = NULL; LIBPOLKIT_CHECK_CONTEXT (ctx, LIBPOLKIT_RESULT_INVALID_CONTEXT); res = LIBPOLKIT_RESULT_ERROR; - *is_allowed = FALSE; - *is_temporary = FALSE; + *out_is_allowed = FALSE; + *out_is_temporary = FALSE; message = dbus_message_new_method_call ("org.freedesktop.PolicyKit", "/org/freedesktop/PolicyKit/Manager", @@ -204,8 +217,11 @@ libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx, if (resource != NULL) myresource = resource; + if (system_bus_unique_name != NULL) + mysystem_bus_unique_name = system_bus_unique_name; + if (!dbus_message_append_args (message, - DBUS_TYPE_INT32, &pid, + DBUS_TYPE_STRING, &mysystem_bus_unique_name, DBUS_TYPE_STRING, &user, DBUS_TYPE_STRING, &privilege, DBUS_TYPE_STRING, &myresource, @@ -232,14 +248,24 @@ libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx, if (!dbus_message_get_args (reply, &error, - DBUS_TYPE_BOOLEAN, is_allowed, - DBUS_TYPE_BOOLEAN, is_temporary, + DBUS_TYPE_BOOLEAN, out_is_allowed, + DBUS_TYPE_BOOLEAN, out_is_temporary, + DBUS_TYPE_STRING, &but_restricted_to, DBUS_TYPE_INVALID)) { g_warning ("Could not extract args from D-BUS message: %s : %s", error.name, error.message); dbus_error_free (&error); goto out; } + if (out_is_privileged_but_restricted_to_system_bus_unique_name != NULL) { + if (but_restricted_to != NULL && strlen (but_restricted_to) > 0) { + *out_is_privileged_but_restricted_to_system_bus_unique_name = strdup (but_restricted_to); + } else { + *out_is_privileged_but_restricted_to_system_bus_unique_name = NULL; + } + //dbus_free (but_restricted_to); + } + res = LIBPOLKIT_RESULT_OK; out: diff --git a/libpolkit/libpolkit.h b/libpolkit/libpolkit.h index 2b19c56..28b4319 100644 --- a/libpolkit/libpolkit.h +++ b/libpolkit/libpolkit.h @@ -51,12 +51,13 @@ LibPolKitResult libpolkit_get_privilege_list (LibPolKit GList **result); LibPolKitResult libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx, - pid_t pid, + const char *system_bus_unique_name, const char *user, const char *privilege, const char *resource, - gboolean *is_allowed, - gboolean *is_temporary); + gboolean *out_is_allowed, + gboolean *out_is_temporary, + char **out_is_privileged_but_restricted_to_system_bus_unique_name); LibPolKitResult libpolkit_revoke_temporary_privilege (LibPolKitContext *ctx, const char *user, @@ -67,7 +68,8 @@ LibPolKitResult libpolkit_revoke_temporary_privilege (LibPolKit LibPolKitResult libpolkit_get_allowed_resources_for_privilege_for_uid (LibPolKitContext *ctx, const char *user, const char *privilege, - GList **result, + GList **resources, + GList **restrictions, int *num_non_temporary); #endif /* LIBPOLKIT_H */ diff --git a/pam-polkit-console/Makefile.am b/pam-polkit-console/Makefile.am new file mode 100644 index 0000000..c0592f9 --- /dev/null +++ b/pam-polkit-console/Makefile.am @@ -0,0 +1,18 @@ + +LOCKDIR = $(localstatedir)/run/polkit-console +LOCKDIRMODE = 0700 + +securelibdir = /lib/security +securelib_LTLIBRARIES = pam_polkit_console.la + +pam_polkit_console_la_LDFLAGS = -no-undefined -avoid-version -module +pam_polkit_console_la_LIBADD = -lpam +pam_polkit_console_la_CFLAGS = -DLOCKDIR=\"$(LOCKDIR)\" + +pam_polkit_console_la_SOURCES = pam-polkit-console.c + +clean-local : + rm -f *~ + +install-data-local: + mkdir -m $(LOCKDIRMODE) -p $(DESTDIR)$(LOCKDIR) diff --git a/pam-polkit-console/pam-polkit-console.c b/pam-polkit-console/pam-polkit-console.c new file mode 100644 index 0000000..353d596 --- /dev/null +++ b/pam-polkit-console/pam-polkit-console.c @@ -0,0 +1,255 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * pam-polkit-console.c : Maintain files in /var/run/polkit-console to + * maintain a list of what users are logged in at + * what console + * + * Copyright (C) 2006 David Zeuthen, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + **************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +static int debug = 0; + +static void +_pam_log (pam_handle_t *pamh, + int err, + int debug_noforce, + const char *format, ...) +{ + va_list args; + + if (debug_noforce && !debug) + return; + + va_start (args, format); + pam_vsyslog (pamh, err, format, args); + closelog (); +} + +static void +_parse_module_args (pam_handle_t *pamh, + int argc, + const char **argv) +{ + int i; + + for (i = 0; i < argc; i++) { + const char *arg; + + arg = argv[i]; + if (strcmp (arg,"debug") == 0) { + debug = 1; + } else { + _pam_log(pamh, LOG_ERR, FALSE, + "_parse_module_args: unknown option; %s", arg); + } + } +} + +static int +_is_local_xconsole (const char *tty) +{ + int a, b; + + if (sscanf (tty, ":%d.%d", &a, &b) == 2) + return TRUE; + else if (sscanf (tty, ":%d", &a) == 1) + return TRUE; + else + return FALSE; +} + +static void +_poke_polkitd (pam_handle_t *pamh) +{ + char buf[80]; + + /* This is a PAM module so we're loaded into the address space + * of some other process (e.g. gdm) - though it's tempting to + * use D-BUS to poke the PolicyKit daemon it may, just resort to + * using oldskool SIGUSR1 instead. + */ + + FILE *f; + f = fopen (POLKITD_PID_FILE, "r"); + if (f != NULL) { + if (fgets (buf, sizeof (buf), f) != NULL && buf[0] != '\0' && buf[0] != '\n') { + pid_t pid; + char *p; + + pid = strtol (buf, &p, 10); + if ((*p == '\0') || (*p == '\n')) + { + _pam_log (pamh, LOG_DEBUG, TRUE, + "Sending SIGUSR1 to polkitd with pid %d to reload configuration", pid); + kill (pid, SIGUSR1); + } + } + fclose (f); + } +} + +PAM_EXTERN int +pam_sm_authenticate (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + return PAM_AUTH_ERR; +} + +PAM_EXTERN int +pam_sm_setcred (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + return PAM_SUCCESS; +} + +PAM_EXTERN int +pam_sm_open_session (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + const char *username = NULL; + const char *user_prompt = NULL; + const char *tty = NULL; + char buf[256]; + + _pam_log (pamh, LOG_ERR, TRUE, "pam_polkit_console open_session"); + _parse_module_args (pamh, argc, argv); + if(pam_get_item (pamh, PAM_USER_PROMPT, (const void **) &user_prompt) != PAM_SUCCESS) { + user_prompt = "user name: "; + } + username = NULL; + pam_get_user (pamh, &username, user_prompt); + if (username == NULL || strlen (username) == 0) { + return PAM_SESSION_ERR; + } + + pam_get_item(pamh, PAM_TTY, (const void**) &tty); + if (tty == NULL || strlen (tty) == 0) { + _pam_log(pamh, LOG_ERR, TRUE, "TTY not defined"); + return PAM_SESSION_ERR; + } + + _pam_log (pamh, LOG_DEBUG, TRUE, "open_session for user '%s' @ TTY '%s'", username, tty); + + if (_is_local_xconsole (tty)) { + if ((unsigned int) snprintf (buf, sizeof (buf), LOCKDIR "/%s_%s", tty, username) < sizeof (buf)) { + int fd; + + fd = open (buf, O_RDWR|O_CREAT|O_EXCL, 0600); + if (fd > 0) { + _pam_log (pamh, LOG_DEBUG, TRUE, "open_session success; %s %s %s", + username, tty, buf); + close (fd); + _poke_polkitd (pamh); + } + } + } + + return PAM_SUCCESS; +} + +PAM_EXTERN int +pam_sm_close_session (pam_handle_t *pamh, + int flags, + int argc, + const char **argv) +{ + const char *username = NULL; + const char *user_prompt = NULL; + const char *tty = NULL; + char buf[256]; + + _pam_log (pamh, LOG_ERR, TRUE, "pam_polkit_console close_session"); + _parse_module_args (pamh, argc, argv); + if (pam_get_item (pamh, PAM_USER_PROMPT, (const void **) &user_prompt) != PAM_SUCCESS) { + user_prompt = "user name: "; + } + username = NULL; + pam_get_user (pamh, &username, user_prompt); + if (username == NULL || strlen (username) == 0) { + return PAM_SESSION_ERR; + } + + pam_get_item (pamh, PAM_TTY, (const void**) &tty); + if (tty == NULL || strlen (tty) == 0) { + _pam_log(pamh, LOG_ERR, TRUE, "TTY not defined"); + return PAM_SESSION_ERR; + } + + _pam_log (pamh, LOG_DEBUG, TRUE, "close_session for user '%s' @ TTY '%s'", username, tty); + + if (_is_local_xconsole (tty)) { + if ((unsigned int) snprintf (buf, sizeof (buf), LOCKDIR "/%s_%s", tty, username) < sizeof (buf)) { + unlink (buf); + _poke_polkitd (pamh); + } + } + + return PAM_SUCCESS; +} + +#ifdef PAM_STATIC + +/* static module data */ + +struct pam_module _pam_polkit_console_modstruct = { + "pam_polkit_console", + pam_sm_authenticate, + pam_sm_setcred, + NULL, + pam_sm_open_session, + pam_sm_close_session, + NULL, +}; + +#endif + +/* end of module definition */ diff --git a/polkit-interface-manager.xml b/polkit-interface-manager.xml index 1d050d1..c7c461e 100644 --- a/polkit-interface-manager.xml +++ b/polkit-interface-manager.xml @@ -21,20 +21,22 @@ - - - - - - + + + + + + + - - - - + + + + + diff --git a/polkit-interface-session.xml b/polkit-interface-session.xml index ff51bff..0549bda 100644 --- a/polkit-interface-session.xml +++ b/polkit-interface-session.xml @@ -35,12 +35,11 @@ - - + diff --git a/polkit.pc.in b/polkit.pc.in index 8fbc889..55885f5 100644 --- a/polkit.pc.in +++ b/polkit.pc.in @@ -3,10 +3,6 @@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ -user=@POLKIT_USER@ -group=@POLKIT_GROUP@ -txtsrc=@sysconfdir@/PolicyKit/privilege.d - Name: libpolkit Description: library for querying and setting system-wide policy Version: @VERSION@ diff --git a/polkitd/PolicyKit.in b/polkitd/PolicyKit.in index 104386b..023fd7f 100755 --- a/polkitd/PolicyKit.in +++ b/polkitd/PolicyKit.in @@ -23,6 +23,13 @@ servicename=PolicyKit RETVAL=0 +cleanup_state_dir() +{ + # Clean out all files in + rm -f @LOCALSTATEDIR@/run/polkit-console/* + mkdir -p @LOCALSTATEDIR@/run/polkit-console +} + start() { echo -n $"Starting PolicyKit daemon: " daemon --check $servicename $processname @@ -46,6 +53,7 @@ stop() { # See how we were called. case "$1" in start) + cleanup_state_dir start ;; stop) @@ -57,13 +65,11 @@ case "$1" in ;; restart) stop - sleep 3 start ;; condrestart) if [ -f @LOCALSTATEDIR@/lock/subsys/$servicename ]; then stop - sleep 3 start fi ;; diff --git a/polkitd/main.c b/polkitd/main.c index f996540..8286670 100644 --- a/polkitd/main.c +++ b/polkitd/main.c @@ -33,6 +33,7 @@ #include #include #include +#include #include @@ -69,18 +70,61 @@ delete_pid (void) unlink (POLKITD_PID_FILE); } +static int sigusr1_unix_signal_pipe_fds[2]; +static GIOChannel *sigusr1_iochn = NULL; +static PolicyKitManager *manager = NULL; + +static void +handle_sigusr1 (int value) +{ + ssize_t written; + static char marker[1] = {'S'}; + + written = write (sigusr1_unix_signal_pipe_fds[1], marker, 1); +} + +static gboolean +sigusr1_iochn_data (GIOChannel *source, + GIOCondition condition, + gpointer user_data) +{ + GError *err = NULL; + gchar data[1]; + gsize bytes_read; + + /* Empty the pipe */ + if (G_IO_STATUS_NORMAL != + g_io_channel_read_chars (source, data, 1, &bytes_read, &err)) { + g_warning ("Error emptying sigusr1 pipe: %s", err->message); + g_error_free (err); + goto out; + } + + g_debug ("Caught SIGUSR1"); + if (manager != NULL) { + polkit_manager_update_desktop_console_privileges (manager); + } + +out: + return TRUE; +} + + int main (int argc, char *argv[]) { DBusGConnection *bus; DBusGProxy *bus_proxy; GError *error = NULL; - PolicyKitManager *manager; GMainLoop *mainloop; guint request_name_result; int ret; gboolean no_daemon = FALSE; gboolean is_verbose = FALSE; + int pf; + ssize_t written; + char pid[9]; + guint sigusr1_iochn_listener_source_id; static const struct option long_options[] = { {"help", no_argument, NULL, 'h'}, {"no-daemon", no_argument, NULL, 'n'}, @@ -131,10 +175,6 @@ main (int argc, char *argv[]) if (!no_daemon) { int child_pid; int dev_null_fd; - int pf; - ssize_t written; - char pid[9]; - if (chdir ("/") < 0) { g_warning ("Could not chdir to /: %s", strerror (errno)); @@ -170,21 +210,21 @@ main (int argc, char *argv[]) /* create session */ setsid (); - - /* remove old pid file */ - unlink (POLKITD_PID_FILE); - - /* make a new pid file */ - if ((pf = open (POLKITD_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) { - snprintf (pid, sizeof(pid), "%lu\n", (long unsigned) getpid ()); - written = write (pf, pid, strlen(pid)); - close (pf); - g_atexit (delete_pid); - } } else { g_debug (("not becoming a daemon")); } + /* remove old pid file */ + unlink (POLKITD_PID_FILE); + + /* make a new pid file */ + if ((pf = open (POLKITD_PID_FILE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644)) > 0) { + snprintf (pid, sizeof(pid), "%lu\n", (long unsigned) getpid ()); + written = write (pf, pid, strlen(pid)); + close (pf); + g_atexit (delete_pid); + } + g_type_init (); dbus_g_object_type_install_info (POLKIT_TYPE_MANAGER, &dbus_glib_polkit_manager_object_info); @@ -194,6 +234,30 @@ main (int argc, char *argv[]) mainloop = g_main_loop_new (NULL, FALSE); + /* Listen for SIGUSR1 - UNIX signal handlers are evil though, + * so set up a pipe to transmit the signal. + */ + + /* create pipe */ + if (pipe (sigusr1_unix_signal_pipe_fds) != 0) { + g_warning ("Could not setup pipe, errno=%d", errno); + goto out; + } + + /* setup glib handler - 0 is for reading, 1 is for writing */ + sigusr1_iochn = g_io_channel_unix_new (sigusr1_unix_signal_pipe_fds[0]); + if (sigusr1_iochn == NULL) { + g_warning ("Could not create GIOChannel"); + goto out; + } + + /* get callback when there is data to read */ + sigusr1_iochn_listener_source_id = g_io_add_watch ( + sigusr1_iochn, G_IO_IN, sigusr1_iochn_data, NULL); + + /* setup UNIX signal handler for SIGUSR1 */ + signal (SIGUSR1, handle_sigusr1); + bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); if (bus == NULL) { g_warning ("Couldn't connect to system bus: %s", error->message); @@ -222,9 +286,15 @@ main (int argc, char *argv[]) manager = polkit_manager_new (bus, bus_proxy); + if (manager == NULL) { + g_warning ("Could not construct manager object; bailing out"); + goto out; + } g_debug ("service running"); + polkit_manager_update_desktop_console_privileges (manager); + g_main_loop_run (mainloop); ret = 0; diff --git a/polkitd/policy.c b/polkitd/policy.c index 95032ec..32c8f78 100644 --- a/polkitd/policy.c +++ b/polkitd/policy.c @@ -171,7 +171,7 @@ txt_backend_read_policy (const char *policy, goto out; } - value = g_key_file_get_string (keyfile, "Policy", key, &error); + value = g_key_file_get_string (keyfile, "Privilege", key, &error); if (value == NULL) { g_warning ("Cannot get key '%s' in group 'Policy' in file '%s': %s", key, path, error->message); g_error_free (error); @@ -295,6 +295,115 @@ out: return rc; } + +static PolicyResult +txt_backend_read_list (const char *policy, + const char *key, + GList **result) +{ + int i; + GKeyFile *keyfile; + GError *error; + PolicyResult rc; + char *path; + char *value = NULL; + char **tokens = NULL; + GList *res; + char *token; + + error = NULL; + rc = POLICY_RESULT_ERROR; + res = NULL; + *result = NULL; + + keyfile = g_key_file_new (); + path = g_strdup_printf ("%s/%s.privilege", policy_directory, policy); + /*g_message ("Loading %s", path);*/ + if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &error)) { + g_warning ("Couldn't open key-file '%s': %s", path, error->message); + g_error_free (error); + rc = POLICY_RESULT_NO_SUCH_POLICY; + goto out; + } + + value = g_key_file_get_string (keyfile, "Privilege", key, &error); + if (value == NULL) { + g_warning ("Cannot get key '%s' in group 'Policy' in file '%s': %s", key, path, error->message); + g_error_free (error); + rc = POLICY_RESULT_ERROR; + goto out; + } + + /*g_message ("value = '%s'", value);*/ + tokens = g_strsplit (value, " ", 0); + for (i = 0; tokens[i] != NULL; i++) { + token = tokens[i]; + /*g_message (" token = '%s'", token);*/ + + res = g_list_append (res, g_strdup (token)); + } + + *result = res; + rc = POLICY_RESULT_OK; + +out: + g_strfreev (tokens); + g_free (value); + + g_key_file_free (keyfile); + g_free (path); + + return rc; +} + +static PolicyResult +txt_backend_read_word (const char *policy, + const char *key, + char **result) +{ + GKeyFile *keyfile; + GError *error; + PolicyResult rc; + char *path; + char *value = NULL; + + error = NULL; + rc = POLICY_RESULT_ERROR; + *result = NULL; + + keyfile = g_key_file_new (); + path = g_strdup_printf ("%s/%s.privilege", policy_directory, policy); + /*g_message ("Loading %s", path);*/ + if (!g_key_file_load_from_file (keyfile, path, G_KEY_FILE_NONE, &error)) { + g_warning ("Couldn't open key-file '%s': %s", path, error->message); + g_error_free (error); + rc = POLICY_RESULT_NO_SUCH_POLICY; + goto out; + } + + value = g_key_file_get_string (keyfile, "Privilege", key, &error); + if (value == NULL) { + g_warning ("Cannot get key '%s' in group 'Policy' in file '%s': %s", key, path, error->message); + g_error_free (error); + rc = POLICY_RESULT_ERROR; + goto out; + } + + /*g_message ("value = '%s'", value);*/ + + *result = g_strdup (value); + + rc = POLICY_RESULT_OK; + +out: + g_free (value); + + g_key_file_free (keyfile); + g_free (path); + + return rc; +} + static PolicyResult policy_get_whitelist (const char *policy, GList **result) @@ -309,6 +418,20 @@ policy_get_blacklist (const char *policy, return txt_backend_read_policy (policy, "Deny", result); } +static PolicyResult +policy_get_sufficient_privileges (const char *policy, + GList **result) +{ + return txt_backend_read_list (policy, "SufficientPrivileges", result); +} + +static PolicyResult +policy_get_required_privileges (const char *policy, + GList **result) +{ + return txt_backend_read_list (policy, "RequiredPrivileges", result); +} + /** Return all elements in the white-list for a policy * * @param result On success set to a list of dynamically allocated strings. @@ -352,6 +475,177 @@ error: return POLICY_RESULT_ERROR; } +PolicyResult +policy_get_auth_details_for_policy (uid_t uid, + const char *policy, + const char *resource, + gboolean *out_auth_can_obtain, + gboolean *out_auth_can_obtain_is_temporary, + gboolean *out_auth_can_grant, + gboolean *out_auth_obtain_requires_root, + gpointer have_temp_privilege_userdata, + HaveTempPrivCB have_temp_privilege) +{ + PolicyResult res; + GList *required_privs; + GList *l; + char *can_obtain_word; + char *can_grant_word; + char *obtain_requires_root_word; + + required_privs = NULL; + can_obtain_word = NULL; + can_grant_word = NULL; + + *out_auth_can_obtain = FALSE; + *out_auth_can_obtain_is_temporary = FALSE; + *out_auth_can_grant = FALSE; + *out_auth_obtain_requires_root = TRUE; + + res = POLICY_RESULT_ERROR; + + res = txt_backend_read_word (policy, "CanObtain", &can_obtain_word); + if (res != POLICY_RESULT_OK) + goto out; + + res = txt_backend_read_word (policy, "CanGrant", &can_grant_word); + if (res != POLICY_RESULT_OK) + goto out; + + res = txt_backend_read_word (policy, "ObtainRequireRoot", &obtain_requires_root_word); + if (res != POLICY_RESULT_OK) + goto out; + + if (strcmp (can_obtain_word, "True") == 0) { + *out_auth_can_obtain = TRUE; + *out_auth_can_obtain_is_temporary = FALSE; + } else if (strcmp (can_obtain_word, "False") == 0) { + *out_auth_can_obtain = FALSE; + *out_auth_can_obtain_is_temporary = FALSE; + } else if (strcmp (can_obtain_word, "Temporary") == 0) { + *out_auth_can_obtain = TRUE; + *out_auth_can_obtain_is_temporary = TRUE; + } else { + g_critical ("CanObtain has bogus value '%s' in privilege '%s'", + can_obtain_word, policy); + goto out; + } + + if (strcmp (can_grant_word, "True") == 0) { + *out_auth_can_grant = TRUE; + } else if (strcmp (can_grant_word, "False") == 0) { + *out_auth_can_grant = FALSE; + } else { + g_critical ("CanGrant has bogus value '%s' in privilege '%s'", + can_grant_word, policy); + goto out; + } + + if (strcmp (obtain_requires_root_word, "True") == 0) { + *out_auth_obtain_requires_root = TRUE; + } else if (strcmp (obtain_requires_root_word, "False") == 0) { + *out_auth_obtain_requires_root = FALSE; + } else { + g_critical ("ObtainRequireRoot has bogus value '%s' in privilege '%s'", + obtain_requires_root_word, policy); + goto out; + } + + /* no need to check RequiredPrivileges if said privilege says we can't obtain it */ + if ((*out_auth_can_obtain) == FALSE) + goto determined; + + /* if privilege already requires super user, no need to check RequiredPrivileges */ + if ((*out_auth_obtain_requires_root) == TRUE) + goto determined; + + /* So now the user can obtain the privilege and doesn't + * require root. However, per the spec, if he is lacking any + * of the privileges listed and one or more of these have + * + * - has ObtainRequiresRoot set to TRUE; or + * + * - has CanObtain set to FALSE + * + * then effectively ObtainsRequireRoot becomes TRUE. + */ + + res = policy_get_required_privileges (policy, &required_privs); + if (res != POLICY_RESULT_OK) + goto out; + + g_message (" * obtain_requires_root = %d", *out_auth_obtain_requires_root); + + for (l = required_privs; l != NULL; l = g_list_next (l)) { + gboolean has_required_privilege = FALSE; + gboolean has_required_privilege_is_temp = FALSE; + char *has_required_privilege_is_restricted = NULL; + const char *required_privilege = (const char *) l->data; + PolicyResult res2; + + g_message (" checking for required privilege '%s'", required_privilege); + + has_required_privilege = FALSE; + res2 = policy_is_uid_allowed_for_policy (uid, + required_privilege, + NULL, + &has_required_privilege, + &has_required_privilege_is_temp, + &has_required_privilege_is_restricted, + have_temp_privilege_userdata, + have_temp_privilege); + if (res2 != POLICY_RESULT_OK) + goto out; + + g_message (" has_required_privilege = %d", has_required_privilege); + + if (!has_required_privilege || + (has_required_privilege && has_required_privilege_is_restricted != NULL)) { + + g_free (can_obtain_word); + g_free (can_grant_word); + can_obtain_word = NULL; + can_grant_word = NULL; + + res = txt_backend_read_word (required_privilege, "CanObtain", + &can_obtain_word); + if (res != POLICY_RESULT_OK) + goto out; + + res = txt_backend_read_word (required_privilege, "ObtainRequireRoot", + &obtain_requires_root_word); + if (res != POLICY_RESULT_OK) + goto out; + + if (strcmp (can_obtain_word, "False") == 0) { + *out_auth_obtain_requires_root = TRUE; + goto determined; + } + + if (strcmp (obtain_requires_root_word, "True") == 0) { + *out_auth_obtain_requires_root = TRUE; + goto determined; + } + } + } + +determined: + g_message (" ** obtain_requires_root = %d", *out_auth_obtain_requires_root); + res = POLICY_RESULT_OK; + +out: + if (required_privs != NULL) { + g_list_foreach (required_privs, (GFunc) g_free, NULL); + g_list_free (required_privs); + } + + g_free (can_obtain_word); + g_free (can_grant_word); + + return res; +} + + static void afp_process_elem(PolicyElement *elem, gboolean *flag, uid_t uid, guint num_gids, gid_t *gid_list) @@ -467,25 +761,143 @@ out: return res; } -PolicyResult -policy_is_uid_gid_allowed_for_policy (uid_t uid, - guint num_gids, - gid_t *gid_list, - const char *policy, - const char *resource, - gboolean *result) +static PolicyResult +_policy_is_uid_gid_allowed_for_policy (uid_t uid, + guint num_gids, + gid_t *gid_list, + const char *policy, + const char *resource, + gboolean *out_is_privileged, + gboolean *out_is_temporary, + char **out_is_privileged_but_restricted, + gpointer have_temp_privilege_userdata, + HaveTempPrivCB have_temp_privilege, + int recursion_counter) { gboolean is_in_whitelist; gboolean is_in_blacklist; GList *l; GList *whitelist; GList *blacklist; + GList *sufficient_privs; + GList *required_privs; PolicyResult res; + PolicyResult res2; whitelist = NULL; blacklist = NULL; + sufficient_privs = NULL; + required_privs = NULL; res = POLICY_RESULT_ERROR; + *out_is_privileged = FALSE; + *out_is_temporary = FALSE; + *out_is_privileged_but_restricted = NULL; + + if (recursion_counter > 8) { + g_critical ("Maximal (8) recursion depth detected checking privilege '%s'", policy); + goto out; + } + + res = policy_get_sufficient_privileges (policy, &sufficient_privs); + if (res != POLICY_RESULT_OK) + goto out; + + /* first check SufficientPrivileges.. if we have one of those, then return TRUE */ + for (l = sufficient_privs; l != NULL; l = g_list_next (l)) { + gboolean has_sufficient_privilege = FALSE; + gboolean has_sufficient_privilege_is_temp = FALSE; + char *has_sufficient_privilege_is_restricted = NULL; + const char *sufficient_privilege = (const char *) l->data; + + g_message (" checking for sufficient privilege '%s'", sufficient_privilege); + + has_sufficient_privilege = FALSE; + res2 = _policy_is_uid_gid_allowed_for_policy (uid, num_gids, gid_list, + sufficient_privilege, NULL, + &has_sufficient_privilege, + &has_sufficient_privilege_is_temp, + &has_sufficient_privilege_is_restricted, + have_temp_privilege_userdata, + have_temp_privilege, recursion_counter + 1); + if (res2 != POLICY_RESULT_OK) + goto out; + + if (has_sufficient_privilege && has_sufficient_privilege_is_restricted == NULL) { + g_message ("Returned TRUE because we have the sufficient privilege '%s' for privilege '%s'", + sufficient_privilege, policy); + res = POLICY_RESULT_OK; + *out_is_privileged = TRUE; + *out_is_temporary = has_sufficient_privilege_is_temp; + *out_is_privileged_but_restricted = NULL; + goto out; + } + } + + /* then check temporary privileges as it's OK to have a + * privilege temporarily without having the all the + * RequiredPrivileges. + */ + + if ((*out_is_privileged == FALSE) && have_temp_privilege != NULL) { + gboolean ignore_resource; + + if (recursion_counter == 0) + ignore_resource = FALSE; + else + ignore_resource = TRUE; + + /* TODO: ask for restriction */ + if (have_temp_privilege (uid, policy, resource, ignore_resource, have_temp_privilege_userdata)) { + + res = POLICY_RESULT_OK; + *out_is_privileged = TRUE; + *out_is_temporary = TRUE; + *out_is_privileged_but_restricted = NULL; + goto out; + } + } + + + /* now check RequiredPrivileges.. if we have don't have all of those, then return FALSE */ + + res = policy_get_required_privileges (policy, &required_privs); + if (res != POLICY_RESULT_OK) + goto out; + + for (l = required_privs; l != NULL; l = g_list_next (l)) { + gboolean has_required_privilege = FALSE; + gboolean has_required_privilege_is_temp = FALSE; + char *has_required_privilege_is_restricted = NULL; + const char *required_privilege = (const char *) l->data; + + g_message (" checking for required privilege '%s'", required_privilege); + + has_required_privilege = FALSE; + res2 = _policy_is_uid_gid_allowed_for_policy (uid, num_gids, gid_list, + required_privilege, NULL, + &has_required_privilege, + &has_required_privilege_is_temp, + &has_required_privilege_is_restricted, + have_temp_privilege_userdata, + have_temp_privilege, recursion_counter + 1); + if (res2 != POLICY_RESULT_OK) + goto out; + + if (!has_required_privilege || + (has_required_privilege && has_required_privilege_is_restricted != NULL)) { + g_message ("Returned FALSE because we don't have the required privilege '%s' for privilege '%s'", + required_privilege, policy); + res = POLICY_RESULT_OK; + *out_is_privileged = FALSE; + *out_is_temporary = TRUE; + *out_is_privileged_but_restricted = NULL; + goto out; + } + } + + /* Check against whitelist and blacklist */ + res = policy_get_whitelist (policy, &whitelist); if (res != POLICY_RESULT_OK) goto out; @@ -517,11 +929,21 @@ policy_is_uid_gid_allowed_for_policy (uid_t uid, } } - *result = is_in_whitelist && (!is_in_blacklist); + *out_is_privileged = is_in_whitelist && (!is_in_blacklist); + *out_is_temporary = FALSE; + *out_is_privileged_but_restricted = NULL; res = POLICY_RESULT_OK; out: + if (required_privs != NULL) { + g_list_foreach (required_privs, (GFunc) g_free, NULL); + g_list_free (required_privs); + } + if (sufficient_privs != NULL) { + g_list_foreach (sufficient_privs, (GFunc) g_free, NULL); + g_list_free (sufficient_privs); + } if (whitelist != NULL) policy_element_free_list (whitelist); if (blacklist != NULL) @@ -530,6 +952,28 @@ out: return res; } + +PolicyResult +policy_is_uid_gid_allowed_for_policy (uid_t uid, + guint num_gids, + gid_t *gid_list, + const char *policy, + const char *resource, + gboolean *out_is_privileged, + gboolean *out_is_temporary, + char **out_is_privileged_but_restricted, + gpointer have_temp_privilege_userdata, + HaveTempPrivCB have_temp_privilege) +{ + return _policy_is_uid_gid_allowed_for_policy (uid, num_gids, gid_list, policy, + resource, + out_is_privileged, + out_is_temporary, + out_is_privileged_but_restricted, + have_temp_privilege_userdata, + have_temp_privilege, 0); +} + char * policy_util_uid_to_name (uid_t uid, gid_t *default_gid) @@ -686,10 +1130,14 @@ out: } PolicyResult -policy_is_uid_allowed_for_policy (uid_t uid, - const char *policy, - const char *resource, - gboolean *result) +policy_is_uid_allowed_for_policy (uid_t uid, + const char *policy, + const char *resource, + gboolean *out_is_privileged, + gboolean *out_is_temporary, + char **out_is_privileged_but_restricted, + gpointer have_temp_privilege_userdata, + HaveTempPrivCB have_temp_privilege) { int num_groups = 0; gid_t *groups = NULL; @@ -715,7 +1163,11 @@ policy_is_uid_allowed_for_policy (uid_t uid, groups, policy, resource, - result); + out_is_privileged, + out_is_temporary, + out_is_privileged_but_restricted, + have_temp_privilege_userdata, + have_temp_privilege); out: g_free (username); diff --git a/polkitd/policy.h b/polkitd/policy.h index 11865ea..94a2fd3 100644 --- a/polkitd/policy.h +++ b/polkitd/policy.h @@ -35,41 +35,68 @@ typedef enum { POLICY_RESULT_NO_SUCH_POLICY } PolicyResult; -PolicyResult policy_get_policies (GList **result); - -PolicyResult policy_is_uid_allowed_for_policy (uid_t uid, - const char *policy, - const char *resource, - gboolean *result); - -PolicyResult policy_get_allowed_resources_for_policy_for_uid (uid_t uid, - const char *policy, - GList **result); - -PolicyResult policy_get_allowed_resources_for_policy_for_uid_gid (uid_t uid, - guint num_gids, - gid_t *gid_list, - const char *policy, - GList **result); - -PolicyResult policy_is_uid_gid_allowed_for_policy (uid_t uid, - guint num_gids, - gid_t *gid_list, - const char *policy, - const char *resource, - gboolean *result); - -char *policy_util_uid_to_name (uid_t uid, - gid_t *default_gid); - -char *policy_util_gid_to_name (gid_t gid); - -uid_t policy_util_name_to_uid (const char *username, - gid_t *default_gid); - -gid_t policy_util_name_to_gid (const char *groupname); - -void policy_util_set_policy_directory (const char *directory); +typedef gboolean (*HaveTempPrivCB) (uid_t user, + const char *privilege, + const char *resource, + gboolean ignore_resource, + gpointer userdata); + + +PolicyResult policy_get_policies (GList **result); + +PolicyResult policy_is_uid_allowed_for_policy (uid_t uid, + const char *policy, + const char *resource, + gboolean *out_is_privileged, + gboolean *out_is_temporary, + char **out_is_privileged_but_restricted, + gpointer have_temp_privilege_userdata, + HaveTempPrivCB have_temp_privilege); + + +PolicyResult policy_get_auth_details_for_policy (uid_t uid, + const char *policy, + const char *resource, + gboolean *out_auth_can_obtain, + gboolean *out_auth_can_obtain_is_temporary, + gboolean *out_auth_can_grant, + gboolean *out_auth_obtain_requires_root, + gpointer have_temp_privilege_userdata, + HaveTempPrivCB have_temp_privilege); + + +PolicyResult policy_get_allowed_resources_for_policy_for_uid (uid_t uid, + const char *policy, + GList **result); + +PolicyResult policy_get_allowed_resources_for_policy_for_uid_gid (uid_t uid, + guint num_gids, + gid_t *gid_list, + const char *policy, + GList **result); + +PolicyResult policy_is_uid_gid_allowed_for_policy (uid_t uid, + guint num_gids, + gid_t *gid_list, + const char *policy, + const char *resource, + gboolean *out_is_privileged, + gboolean *out_is_temporary, + char **out_is_privileged_but_restricted, + gpointer have_temp_privilege_userdata, + HaveTempPrivCB have_temp_privilege); + +char *policy_util_uid_to_name (uid_t uid, + gid_t *default_gid); + +char *policy_util_gid_to_name (gid_t gid); + +uid_t policy_util_name_to_uid (const char *username, + gid_t *default_gid); + +gid_t policy_util_name_to_gid (const char *groupname); + +void policy_util_set_policy_directory (const char *directory); #endif /* POLICY_H */ diff --git a/polkitd/polkit-manager.c b/polkitd/polkit-manager.c index 52c59d9..947d333 100644 --- a/polkitd/polkit-manager.c +++ b/polkitd/polkit-manager.c @@ -38,7 +38,7 @@ typedef struct uid_t user; char *privilege; char *resource; - pid_t pid_restriction; + char *system_bus_unique_name; /* whether the tmp priv is restricted to e.g. :1.43 */ } TemporaryPrivilege; struct PolicyKitManagerPrivate @@ -58,6 +58,26 @@ G_DEFINE_TYPE(PolicyKitManager, polkit_manager, G_TYPE_OBJECT) static GObjectClass *parent_class = NULL; + +static void +_granting_temp_priv (PolicyKitManager *manager, + TemporaryPrivilege *p) +{ + g_debug ("Granting temporary privilege '%s' to uid %d on resource '%s'", + p->privilege, p->user, p->resource != NULL ? p->resource : "(none)"); + /* TODO: send out D-BUS signal */ +} + +static void +_revoking_temp_priv (PolicyKitManager *manager, + TemporaryPrivilege *p) +{ + g_debug ("Revoking temporary privilege '%s' to uid %d on resource '%s'", + p->privilege, p->user, p->resource != NULL ? p->resource : "(none)"); + /* TODO: send out D-BUS signal */ +} + + typedef struct { uid_t uid; pid_t pid; @@ -130,6 +150,7 @@ polkit_manager_error_get_type (void) ENUM_ENTRY (POLKIT_MANAGER_ERROR_NO_SUCH_USER, "NoSuchUser"), ENUM_ENTRY (POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE, "NoSuchPrivilege"), ENUM_ENTRY (POLKIT_MANAGER_ERROR_NOT_PRIVILEGED, "NotPrivileged"), + ENUM_ENTRY (POLKIT_MANAGER_ERROR_CANNOT_OBTAIN_PRIVILEGE, "CannotObtainPrivilege"), ENUM_ENTRY (POLKIT_MANAGER_ERROR_ERROR, "Error"), { 0, 0, 0 } }; @@ -157,6 +178,8 @@ bus_name_owner_changed (DBusGProxy *bus_proxy, if (strlen (new_service_name) == 0) { CallerInfo *caller_info; PolicyKitSession *session; + GList *i; + TemporaryPrivilege *p; /* evict CallerInfo from cache */ caller_info = (CallerInfo *) g_hash_table_lookup (manager->priv->connection_name_to_caller_info, @@ -177,6 +200,29 @@ bus_name_owner_changed (DBusGProxy *bus_proxy, g_hash_table_remove (manager->priv->connection_name_to_session_object, old_service_name); } + + /* revoke any temporary privileges that is restricted to this name */ + for (i = manager->priv->temporary_privileges; i != NULL; ) { + p = (TemporaryPrivilege *) i->data; + + i = g_list_next (i); + + if (p->system_bus_unique_name != NULL && + strcmp (p->system_bus_unique_name, old_service_name) == 0) { + + /* da, revoke this privilege */ + _revoking_temp_priv (manager, p); + + g_free (p->privilege); + g_free (p->resource); + g_free (p->system_bus_unique_name); + g_free (p); + + manager->priv->temporary_privileges = g_list_remove ( + manager->priv->temporary_privileges, p); + } + } + } /*g_message ("NameOwnerChanged: service_name='%s', old_service_name='%s' new_service_name='%s'", @@ -269,6 +315,7 @@ polkit_manager_get_caller_info (PolicyKitManager *manager, gboolean res; CallerInfo *caller_info; GError *error = NULL; + GArray *calling_selinux_context; res = FALSE; @@ -307,6 +354,22 @@ polkit_manager_get_caller_info (PolicyKitManager *manager, goto out; } + if (!dbus_g_proxy_call (manager->priv->bus_proxy, "GetConnectionSELinuxSecurityContext", &error, + G_TYPE_STRING, sender, + G_TYPE_INVALID, + dbus_g_type_get_collection ("GArray", G_TYPE_UCHAR), &calling_selinux_context, + G_TYPE_INVALID)) { + g_warning ("GetConnectionSELinuxSecurityContext() failed: %s", error->message); + g_error_free (error); + goto out; + } + + char *selinux_context_string; + g_array_append_val (calling_selinux_context, "\0"); + selinux_context_string = (char *) g_array_free (calling_selinux_context, FALSE); + g_message ("selinux context = '%s' for sender '%s'", selinux_context_string, sender); + g_free (selinux_context_string); + caller_info = g_new0 (CallerInfo, 1); caller_info->uid = *calling_uid; caller_info->pid = *calling_pid; @@ -324,6 +387,68 @@ out: return res; } + +typedef struct +{ + PolicyKitManager *manager; + char *system_bus_unique_name; + char *privileged_but_restricted_to; + gboolean is_temporary; +} TempPrivCheckUserData; + +static gboolean +_check_for_temp_privilege (uid_t user, + const char *privilege, + const char *resource, + gboolean ignore_resource, + gpointer userdata) +{ + GList *i; + TempPrivCheckUserData *tpcud = (TempPrivCheckUserData *) userdata; + gboolean is_privileged; + + is_privileged = FALSE; + + g_message ("in _check_for_temp_privilege for user=%d priv=%s resource=%s sbun=%s", + user, privilege, resource, tpcud->system_bus_unique_name); + + for (i = tpcud->manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) { + TemporaryPrivilege *p; + gboolean res_match; + + p = (TemporaryPrivilege *) i->data; + + if (ignore_resource) { + res_match = TRUE; + } else { + if (resource == NULL || strlen (resource) == 0) + res_match = (p->resource == NULL); + else + res_match = (safe_strcmp (p->resource, resource) == 0); + } + + if ((strcmp (p->privilege, privilege) == 0) && + res_match && + (p->user == user)) { + + if (p->system_bus_unique_name == NULL) { + is_privileged = TRUE; + tpcud->is_temporary = TRUE; + break; + } else if (strcmp (p->system_bus_unique_name, tpcud->system_bus_unique_name) == 0) { + is_privileged = TRUE; + tpcud->is_temporary = TRUE; + break; + } else { + tpcud->privileged_but_restricted_to = p->system_bus_unique_name; + } + + } + } + + return is_privileged; +} + gboolean polkit_manager_initiate_temporary_privilege_grant (PolicyKitManager *manager, char *user, @@ -365,14 +490,45 @@ polkit_manager_initiate_temporary_privilege_grant (PolicyKitManager *manag return FALSE; } + + gboolean auth_can_obtain; + gboolean auth_can_obtain_is_temporary; + gboolean auth_can_grant; + gboolean auth_obtain_requires_root; + PolicyResult res; + TempPrivCheckUserData tpcud; + + tpcud.manager = manager; + tpcud.system_bus_unique_name = NULL; + tpcud.privileged_but_restricted_to = ""; + tpcud.is_temporary = FALSE; + + res = policy_get_auth_details_for_policy (uid, + privilege, + resource, + &auth_can_obtain, + &auth_can_obtain_is_temporary, + &auth_can_grant, + &auth_obtain_requires_root, + &tpcud, + _check_for_temp_privilege); + + if (!auth_can_obtain) { + dbus_g_method_return_error (context, + g_error_new (POLKIT_MANAGER_ERROR, + POLKIT_MANAGER_ERROR_ERROR, + "The privilege %s cannot be obtained.", privilege)); + return FALSE; + } + session = polkit_session_new (manager->priv->connection, manager, calling_uid, - calling_pid, sender, uid, privilege, - strlen (resource) > 0 ? resource : NULL); + strlen (resource) > 0 ? resource : NULL, + auth_obtain_requires_root); g_object_weak_ref (G_OBJECT (session), session_finalized, @@ -391,7 +547,7 @@ polkit_manager_initiate_temporary_privilege_grant (PolicyKitManager *manag gboolean polkit_manager_is_user_privileged (PolicyKitManager *manager, - int pid, + char *system_bus_unique_name, char *user, char *privilege, char *resource, @@ -403,7 +559,8 @@ polkit_manager_is_user_privileged (PolicyKitManager *manager, PolicyResult res; gboolean is_privileged; gboolean is_temporary; - + char *is_privileged_but_restricted_to = NULL; + TempPrivCheckUserData tpcud; if (!polkit_manager_get_caller_info (manager, dbus_g_method_get_sender (context), @@ -438,10 +595,18 @@ polkit_manager_is_user_privileged (PolicyKitManager *manager, return FALSE; } + tpcud.manager = manager; + tpcud.system_bus_unique_name = system_bus_unique_name; + tpcud.privileged_but_restricted_to = ""; + tpcud.is_temporary = FALSE; res = policy_is_uid_allowed_for_policy (uid, privilege, strlen (resource) > 0 ? resource : NULL, - &is_privileged); + &is_privileged, + &is_temporary, + &is_privileged_but_restricted_to, + &tpcud, + _check_for_temp_privilege); switch (res) { case POLICY_RESULT_OK: break; @@ -463,35 +628,16 @@ polkit_manager_is_user_privileged (PolicyKitManager *manager, return FALSE; } - is_temporary = FALSE; - - /* check temporary lists */ - if (!is_privileged) { - GList *i; - TemporaryPrivilege *p; - - for (i = manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) { - p = (TemporaryPrivilege *) i->data; - gboolean res_match; - if (strlen (resource) == 0) - res_match = (p->resource == NULL); - else - res_match = (safe_strcmp (p->resource, resource) == 0); - - if ((strcmp (p->privilege, privilege) == 0) && - res_match && - (p->user == uid) && - ((p->pid_restriction == -1) || (p->pid_restriction == pid))) { - - is_privileged = TRUE; - is_temporary = TRUE; - break; - } - } + /* if we ended up being privileged, then don't fill in the _but_restricted_to */ + if (is_privileged) { + g_free (is_privileged_but_restricted_to); + is_privileged_but_restricted_to = g_strdup (""); } - dbus_g_method_return (context, is_privileged, is_temporary); + dbus_g_method_return (context, is_privileged, is_temporary, is_privileged_but_restricted_to); + + g_free (is_privileged_but_restricted_to); return TRUE; } @@ -508,10 +654,12 @@ polkit_manager_get_allowed_resources_for_privilege (PolicyKitManager *manag int n; GList *i; GList *resources; + GList *restrictions; uid_t uid; PolicyResult res; TemporaryPrivilege *p; char **resource_list; + char **restriction_list; int num_non_temporary; if (!polkit_manager_get_caller_info (manager, @@ -572,15 +720,19 @@ polkit_manager_get_allowed_resources_for_privilege (PolicyKitManager *manag num_non_temporary = g_list_length (resources); + restrictions = NULL; + /* check temporary list */ for (i = manager->priv->temporary_privileges; i != NULL; i = g_list_next (i)) { p = (TemporaryPrivilege *) i->data; if ((strcmp (p->privilege, privilege) == 0) && (p->resource != NULL) && - (p->user == uid) && - (p->pid_restriction == -1)) { + (p->user == uid)) { + resources = g_list_append (resources, g_strdup (p->resource)); + restrictions = g_list_append (restrictions, p->system_bus_unique_name != NULL ? + p->system_bus_unique_name : ""); } } @@ -595,7 +747,18 @@ polkit_manager_get_allowed_resources_for_privilege (PolicyKitManager *manag g_list_foreach (resources, (GFunc) g_free, NULL); g_list_free (resources); - dbus_g_method_return (context, resource_list, num_non_temporary); + restriction_list = g_new0 (char *, g_list_length (resources) + 1); + for (n = 0; n < num_non_temporary; n++) { + restriction_list[n] = ""; + } + for (i = restrictions; i != NULL; i = g_list_next (i)) { + char *restriction = (char *) i->data; + restriction_list[n] = g_strdup (restriction); + n++; + } + restriction_list[n] = NULL; + + dbus_g_method_return (context, resource_list, restriction_list, num_non_temporary); return TRUE; } @@ -713,7 +876,8 @@ polkit_manager_revoke_temporary_privilege (PolicyKitManager *manager, uid, privilege, resource, - -1)) { + NULL, + TRUE)) { dbus_g_method_return_error (context, g_error_new (POLKIT_MANAGER_ERROR, POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE, @@ -730,13 +894,12 @@ polkit_manager_revoke_temporary_privilege (PolicyKitManager *manager, /* local methods */ - gboolean polkit_manager_add_temporary_privilege (PolicyKitManager *manager, uid_t user, const char *privilege, const char *resource, - pid_t pid_restriction) + const char *system_bus_unique_name) { GList *i; TemporaryPrivilege *p; @@ -747,7 +910,7 @@ polkit_manager_add_temporary_privilege (PolicyKitManager *manager, if ((strcmp (p->privilege, privilege) == 0) && ((resource != NULL) && (safe_strcmp (p->resource, resource)) == 0) && (p->user == user) && - (p->pid_restriction == pid_restriction)) + (p->system_bus_unique_name == system_bus_unique_name)) return FALSE; } @@ -755,8 +918,9 @@ polkit_manager_add_temporary_privilege (PolicyKitManager *manager, p->user = user; p->privilege = g_strdup (privilege); p->resource = g_strdup (resource); - p->pid_restriction = pid_restriction; + p->system_bus_unique_name = g_strdup (system_bus_unique_name); + _granting_temp_priv (manager, p); manager->priv->temporary_privileges = g_list_append (manager->priv->temporary_privileges, p); return TRUE; @@ -767,7 +931,8 @@ polkit_manager_remove_temporary_privilege (PolicyKitManager *manager, uid_t user, const char *privilege, const char *resource, - pid_t pid_restriction) + const char *system_bus_unique_name, + gboolean remove_even_if_system_bus_unique_name_does_not_match) { GList *i; TemporaryPrivilege *p; @@ -776,13 +941,25 @@ polkit_manager_remove_temporary_privilege (PolicyKitManager *manager, p = (TemporaryPrivilege *) i->data; if ((strcmp (p->privilege, privilege) == 0) && + ((resource == NULL) ? (p->resource == NULL) : ((p->resource != NULL) ? (strcmp (p->resource, resource) == 0) : FALSE)) && + (p->user == user) && - (p->pid_restriction == pid_restriction)) { + + (remove_even_if_system_bus_unique_name_does_not_match || + ((system_bus_unique_name == NULL) ? (p->system_bus_unique_name == NULL) + : ((p->system_bus_unique_name != NULL) ? + (strcmp (p->system_bus_unique_name, system_bus_unique_name) == 0) : + FALSE))) + ) { + + _revoking_temp_priv (manager, p); g_free (p->privilege); g_free (p->resource); + g_free (p->system_bus_unique_name); + g_free (p); manager->priv->temporary_privileges = g_list_remove ( manager->priv->temporary_privileges, p); @@ -793,3 +970,117 @@ polkit_manager_remove_temporary_privilege (PolicyKitManager *manager, return FALSE; } + +void +polkit_manager_update_desktop_console_privileges (PolicyKitManager *manager) +{ + GDir *dir; + GError *err = NULL; + const char *f; + GSList *list; + GSList *j; + GList *i; + TemporaryPrivilege *p; + + g_debug ("Entering polkit_manager_update_desktop_console_privileges"); + + /* Build a list of what /var/run/polkit-console contains; + * e.g. {":0", "davidz", ":1", "bateman", ..} + * + * This is essentially a list of pairs + * denoting what users are logged in at the consoles attached + * to the system. + */ + list = NULL; + if ((dir = g_dir_open (PACKAGE_LOCALSTATEDIR "/run/polkit-console", 0, &err)) == NULL) { + g_warning ("Unable to open " PACKAGE_LOCALSTATEDIR "/run/polkit-console : %s", err->message); + g_error_free (err); + goto out; + } + while ((f = g_dir_read_name (dir)) != NULL) { + char **tokens; + + tokens = g_strsplit (f, "_", 2); + if (tokens != NULL && g_strv_length (tokens) == 2) { + char *console; + char *user; + + console = g_strdup_printf ("console://%s", tokens[0]); + user = g_strdup (tokens[1]); + list = g_slist_append (list, console); + list = g_slist_append (list, user); + } + g_strfreev (tokens); + } + g_dir_close (dir); + + /* now revoke the temporary desktop-console privilege for + * users no longer at the console; go through all tempoary + * desktop-console privileges and check that each one is still + * in the list above... + */ + for (i = manager->priv->temporary_privileges; i != NULL; ) { + p = (TemporaryPrivilege *) i->data; + gboolean found; + + i = g_list_next (i); + + found = FALSE; + + if ((strcmp (p->privilege, "desktop-console") == 0) && p->resource != NULL) { + + for (j = list; j != NULL; j = g_slist_next (j)) { + char *console; + char *user; + uid_t uid; + + console = (char *) j->data; + j = g_slist_next (j); + user = (char *) j->data; + uid = policy_util_name_to_uid (user, NULL); + if (uid != (uid_t) -1 && strcmp (p->resource, console) == 0 && + p->user == uid && + p->system_bus_unique_name == NULL) { + found = TRUE; + break; + } + } + } + + if (!found) { + /* revoke this privilege */ + _revoking_temp_priv (manager, p); + + g_free (p->privilege); + g_free (p->resource); + g_free (p->system_bus_unique_name); + g_free (p); + + manager->priv->temporary_privileges = g_list_remove ( + manager->priv->temporary_privileges, p); + } + } + + /* finally grant temporary desktop-console privilege for users + * now at the console + */ + for (j = list; j != NULL; j = g_slist_next (j)) { + char *console; + char *user; + uid_t uid; + + console = (char *) j->data; + j = g_slist_next (j); + user = (char *) j->data; + uid = policy_util_name_to_uid (user, NULL); + if (uid != (uid_t) -1) { + polkit_manager_add_temporary_privilege (manager, uid, "desktop-console", console, NULL); + } + } + + g_slist_foreach (list, (GFunc) g_free, NULL); + g_slist_free (list); + +out: + ; +} diff --git a/polkitd/polkit-manager.h b/polkitd/polkit-manager.h index f59e2dd..9d7b802 100644 --- a/polkitd/polkit-manager.h +++ b/polkitd/polkit-manager.h @@ -40,6 +40,7 @@ typedef enum POLKIT_MANAGER_ERROR_NO_SUCH_PRIVILEGE = 1, POLKIT_MANAGER_ERROR_NOT_PRIVILEGED = 2, POLKIT_MANAGER_ERROR_ERROR = 3, + POLKIT_MANAGER_ERROR_CANNOT_OBTAIN_PRIVILEGE = 4, POLKIT_MANAGER_NUM_ERRORS } PolkitManagerError; @@ -90,7 +91,7 @@ gboolean polkit_manager_revoke_temporary_privilege (PolicyKitM DBusGMethodInvocation *context); gboolean polkit_manager_is_user_privileged (PolicyKitManager *manager, - int pid, + char *system_bus_unique_name, char *user, char *privilege, char *resource, @@ -116,12 +117,16 @@ gboolean polkit_manager_add_temporary_privilege (PolicyKitM uid_t user, const char *privilege, const char *resource, - pid_t pid_restriction); + const char *system_bus_unique_name); gboolean polkit_manager_remove_temporary_privilege (PolicyKitManager *manager, uid_t user, const char *privilege, const char *resource, - pid_t pid_restriction); + const char *system_bus_unique_name, + gboolean remove_even_if_system_bus_unique_name_does_not_match); + +void polkit_manager_update_desktop_console_privileges (PolicyKitManager *manager); + #endif /* _POLKIT_MANAGER_H */ diff --git a/polkitd/polkit-session.c b/polkitd/polkit-session.c index 458e854..cbc2fb5 100644 --- a/polkitd/polkit-session.c +++ b/polkitd/polkit-session.c @@ -36,6 +36,7 @@ #include #include +#include "policy.h" #include "polkit-session.h" enum @@ -58,13 +59,12 @@ struct PolicyKitSessionPrivate char *auth_with_pam_service; uid_t calling_uid; - pid_t calling_pid; char *calling_dbus_name; uid_t grant_to_uid; char *grant_privilege; char *grant_resource; - pid_t grant_pid_restriction; + char *grant_system_bus_name_unique_name_restriction; gboolean have_granted_temp_privileges; @@ -879,10 +879,9 @@ polkit_session_provide_answers (PolicyKitSession *session, gboolean polkit_session_close (PolicyKitSession *session, - gboolean do_not_revoke_privilege, DBusGMethodInvocation *context) { - /*g_debug ("in %s", __FUNCTION__);*/ + g_debug ("In polkit_session_close for session %d", session->priv->session_number); if (!polkit_session_check_caller (session, context)) return FALSE; @@ -891,21 +890,6 @@ polkit_session_close (PolicyKitSession *session, if (session->priv->child_pid != 0) kill (session->priv->child_pid, SIGTERM); - if (!do_not_revoke_privilege && session->priv->have_granted_temp_privileges) { - - if (!polkit_manager_remove_temporary_privilege (session->priv->manager, - session->priv->grant_to_uid, - session->priv->grant_privilege, - session->priv->grant_resource, - session->priv->grant_pid_restriction)) { - g_warning ("Could not remove tmp priv '%s' to uid %d for resource '%s' on pid %d", - session->priv->grant_privilege, - session->priv->grant_to_uid, - session->priv->grant_resource, - session->priv->grant_pid_restriction); - } - } - g_object_unref (session); dbus_g_method_return (context); @@ -914,7 +898,7 @@ polkit_session_close (PolicyKitSession *session, gboolean polkit_session_grant_privilege_temporarily (PolicyKitSession *session, - gboolean restrict_to_callers_pid, + gboolean restrict_to_callers_system_bus_unique_name, DBusGMethodInvocation *context) { if (!polkit_session_check_caller (session, context)) @@ -936,17 +920,18 @@ polkit_session_grant_privilege_temporarily (PolicyKitSession *session, return FALSE; } - session->priv->grant_pid_restriction = restrict_to_callers_pid ? session->priv->calling_pid : (pid_t) -1; + session->priv->grant_system_bus_name_unique_name_restriction = restrict_to_callers_system_bus_unique_name ? + g_strdup (session->priv->calling_dbus_name) : NULL; if (!polkit_manager_add_temporary_privilege (session->priv->manager, session->priv->grant_to_uid, session->priv->grant_privilege, session->priv->grant_resource, - session->priv->grant_pid_restriction)) { - g_warning ("Could not add tmp priv '%s' to uid %d for resource '%s' on pid %d", + session->priv->grant_system_bus_name_unique_name_restriction)) { + g_warning ("Could not add tmp priv '%s' to uid %d for resource '%s' on connection '%s'", session->priv->grant_privilege, session->priv->grant_to_uid, session->priv->grant_resource, - session->priv->grant_pid_restriction); + session->priv->grant_system_bus_name_unique_name_restriction); } session->priv->have_granted_temp_privileges = TRUE; @@ -959,11 +944,11 @@ PolicyKitSession * polkit_session_new (DBusGConnection *connection, PolicyKitManager *manager, uid_t calling_uid, - pid_t calling_pid, const char *calling_dbus_name, uid_t uid, const char *privilege, - const char *resource) + const char *resource, + gboolean auth_as_root) { char *objpath; PolicyKitSession *session; @@ -978,17 +963,21 @@ polkit_session_new (DBusGConnection *connection, g_free (objpath); session->priv->calling_uid = calling_uid; - session->priv->calling_pid = calling_pid; session->priv->calling_dbus_name = g_strdup (calling_dbus_name); session->priv->grant_to_uid = uid; session->priv->grant_privilege = g_strdup (privilege); session->priv->grant_resource = g_strdup (resource); - /* TODO: look up auth_as_user, auth_with_pam_service from privilege configuration files */ - session->priv->auth_as_user = g_strdup ("root"); + /* TODO: look up auth_as_user from privilege configuration files */ + if (auth_as_root) + session->priv->auth_as_user = g_strdup ("root"); + else + session->priv->auth_as_user = policy_util_uid_to_name (uid, NULL); session->priv->auth_with_pam_service = g_strdup ("policy-kit"); + g_debug ("In polkit_session_new ; established session %d", session->priv->session_number); + return session; } @@ -996,23 +985,29 @@ polkit_session_new (DBusGConnection *connection, void polkit_session_initiator_disconnected (PolicyKitSession *session) { - /*g_debug ("initiator disconnected");*/ + g_debug ("Initiator for session %d disconnected", session->priv->session_number); /* if we have a child... kill it */ if (session->priv->child_pid != 0) kill (session->priv->child_pid, SIGTERM); if (session->priv->have_granted_temp_privileges) { + g_debug (" Revoking temporary privilege %s on %s for uid %d on connection %s", + session->priv->grant_privilege, + session->priv->grant_resource, + session->priv->grant_to_uid, + session->priv->grant_system_bus_name_unique_name_restriction); if (!polkit_manager_remove_temporary_privilege (session->priv->manager, session->priv->grant_to_uid, session->priv->grant_privilege, session->priv->grant_resource, - session->priv->grant_pid_restriction)) { - g_warning ("Could not remove tmp priv '%s' to uid %d for resource '%s' on pid %d", + session->priv->grant_system_bus_name_unique_name_restriction, + FALSE)) { + g_warning ("Could not remove tmp priv '%s' to uid %d for resource '%s' on connection '%s'", session->priv->grant_privilege, session->priv->grant_to_uid, session->priv->grant_resource, - session->priv->grant_pid_restriction); + session->priv->grant_system_bus_name_unique_name_restriction); } } } diff --git a/polkitd/polkit-session.h b/polkitd/polkit-session.h index c02bd22..19fac2f 100644 --- a/polkitd/polkit-session.h +++ b/polkitd/polkit-session.h @@ -80,11 +80,11 @@ struct PolicyKitSessionClass PolicyKitSession *polkit_session_new (DBusGConnection *connection, PolicyKitManager *manager, uid_t calling_uid, - pid_t calling_pid, const char *calling_dbus_name, uid_t uid, const char *privilege, - const char *resource); + const char *resource, + gboolean auth_as_root); /* remote methods */ @@ -102,7 +102,6 @@ gboolean polkit_session_provide_answers (PolicyKitSession DBusGMethodInvocation *context); gboolean polkit_session_close (PolicyKitSession *session, - gboolean do_not_revoke_privilege, DBusGMethodInvocation *context); gboolean polkit_session_get_auth_details (PolicyKitSession *session, @@ -112,7 +111,7 @@ gboolean polkit_session_get_auth_denied_reason (PolicyKitSession DBusGMethodInvocation *context); gboolean polkit_session_grant_privilege_temporarily (PolicyKitSession *session, - gboolean restrict_to_callers_pid, + gboolean restrict_to_callers_system_bus_unique_name, DBusGMethodInvocation *context); /* local methods */ diff --git a/privileges/desktop-console.privilege b/privileges/desktop-console.privilege index 112951b..dbd4712 100644 --- a/privileges/desktop-console.privilege +++ b/privileges/desktop-console.privilege @@ -1,4 +1,14 @@ -[Policy] +# This privilege signfies that users holding it are logged into a +# physical console attached to the system. Thus, it is useful for +# other privileges for manipulating local devices to simply require +# this privilege. + +[Privilege] +RequiredPrivileges= +SufficientPrivileges= Allow= Deny= +CanObtain=False +CanGrant=False +ObtainRequireRoot=True diff --git a/tools/Makefile.am b/tools/Makefile.am index a8d2a54..a16814b 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -24,27 +24,15 @@ polkit_is_privileged_LDADD = @DBUS_CFLAGS@ @GLIB_LIBS@ $(top_builddir)/libpolkit polkit_list_privileges_SOURCES = polkit-list-privileges.c polkit_list_privileges_LDADD = @DBUS_CFLAGS@ @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la -polkit-interface-manager-glue.h: ../polkit-interface-manager.xml Makefile.am - dbus-binding-tool --prefix=polkit_manager --mode=glib-client --output=polkit-interface-manager-glue.h ../polkit-interface-manager.xml - -polkit-interface-session-glue.h: ../polkit-interface-session.xml Makefile.am - dbus-binding-tool --prefix=polkit_session --mode=glib-client --output=polkit-interface-session-glue.h ../polkit-interface-session.xml - - polkit_grant_privilege_SOURCES= \ - polkit-grant-privilege.c \ - polkit-interface-manager-glue.h \ - polkit-interface-session-glue.h -polkit_grant_privilege_LDADD= @DBUS_GLIB_LIBS@ @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la + polkit-grant-privilege.c +polkit_grant_privilege_LDADD= @DBUS_GLIB_LIBS@ @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la $(top_builddir)/libpolkit/libpolkit-grant.la polkit_revoke_privilege_SOURCES= \ polkit-revoke-privilege.c polkit_revoke_privilege_LDADD= @DBUS_GLIB_LIBS@ @GLIB_LIBS@ $(top_builddir)/libpolkit/libpolkit.la - -BUILT_SOURCES = polkit-interface-manager-glue.h polkit-interface-session-glue.h - clean-local : - rm -f *~ $(BUILT_SOURCES) + rm -f *~ diff --git a/tools/polkit-grant-privilege.c b/tools/polkit-grant-privilege.c index 87054a5..b13f34f 100644 --- a/tools/polkit-grant-privilege.c +++ b/tools/polkit-grant-privilege.c @@ -36,27 +36,34 @@ #include #include +#include -#include "polkit-interface-manager-glue.h" -#include "polkit-interface-session-glue.h" -static char *grant_user = NULL; -static char *grant_privilege = NULL; -static char *grant_resource = NULL; -static char *auth_user = NULL; -static char *auth_pam_service_name = NULL; +static gboolean is_verbose = FALSE; + static void -have_questions_handler (DBusGProxy *session, gpointer user_data) +questions_cb (LibPolKitGrantContext *ctx, + const char **questions, + gpointer user_data) { int i; - char **questions; - char **answers; int num_a; - GError *error = NULL; + char **answers; + static gboolean showed_user = FALSE; + - if (auth_user != NULL) { - if (grant_resource != NULL) + /* print banner for user if we are going to ask questions */ + if (!showed_user) { + const char *auth_user; + const char *auth_pam_svc; + + showed_user = TRUE; + + auth_user = libpolkit_grant_get_user_for_auth (ctx); + auth_pam_svc = libpolkit_grant_get_pam_service_for_auth (ctx); + + if (libpolkit_grant_get_resource (ctx) != NULL) { g_print ("\n" "Authentication needed for user '%s' in order to grant the\n" "privilege '%s' to user '%s' for the \n" @@ -65,10 +72,11 @@ have_questions_handler (DBusGProxy *session, gpointer user_data) "The privilege is configured to use PAM service '%s'.\n" "\n", auth_user, - grant_privilege, grant_user, - grant_resource, - auth_pam_service_name); - else + libpolkit_grant_get_privilege (ctx), + libpolkit_grant_get_user (ctx), + libpolkit_grant_get_resource (ctx), + auth_pam_svc); + } else { g_print ("\n" "Authentication needed for user '%s' in order to grant the\n" "privilege '%s' to user '%s'.\n" @@ -76,29 +84,20 @@ have_questions_handler (DBusGProxy *session, gpointer user_data) "The privilege is configured to use PAM service '%s'.\n" "\n", auth_user, - grant_privilege, grant_user, - auth_pam_service_name); - g_free (auth_user); - g_free (auth_pam_service_name); - auth_user = NULL; - auth_pam_service_name = NULL; + libpolkit_grant_get_privilege (ctx), + libpolkit_grant_get_user (ctx), + auth_pam_svc); + } } - if (!org_freedesktop_PolicyKit_Session_get_questions (session, - &questions, - &error)) { - g_warning ("GetQuestions: %s", error->message); - g_error_free (error); - goto out; - } - answers = g_new0 (char *, g_strv_length (questions) + 1); + answers = g_new0 (char *, g_strv_length ((char **) questions) + 1); num_a = 0; for (i = 0; questions[i] != NULL && questions[i+1] != NULL; i++) { char *answer; - char *question = questions[i+1]; - char *qtype = questions[i]; + const char *question = questions[i+1]; + const char *qtype = questions[i]; /*g_debug ("Question 1: '%s' (pamtype %s)\n(warning; secret will be echoed to stdout)", question, qtype);*/ @@ -112,7 +111,7 @@ have_questions_handler (DBusGProxy *session, gpointer user_data) char buf[1024]; fputs (question, stderr); - answer = fgets (question, sizeof (buf), stdin); + answer = fgets ((char *) question, sizeof (buf), stdin); answers[num_a++] = g_strdup (answer); /*g_debug ("Provding answer: '%s'", answer);*/ @@ -127,156 +126,31 @@ have_questions_handler (DBusGProxy *session, gpointer user_data) } answers[num_a] = NULL; - g_strfreev (questions); - - if (!org_freedesktop_PolicyKit_Session_provide_answers (session, - (const char **) answers, - &error)) { - g_warning ("ProvideAnswers: %s", error->message); - g_error_free (error); - goto out; - } + libpolkit_grant_provide_answers (ctx, (const char **) answers); g_strfreev (answers); - -out: - ; } static void -auth_done_handler (DBusGProxy *session, gpointer user_data) +grant_complete_cb (LibPolKitGrantContext *ctx, + gboolean obtained_privilege, + const char *reason_not_obtained, + gpointer user_data) { - gboolean auth_result; - GError *error = NULL; - - /*g_debug ("in %s", __FUNCTION__);*/ - - if (!org_freedesktop_PolicyKit_Session_is_authenticated (session, - &auth_result, - &error)) { - g_warning ("IsAuthenticated: %s", error->message); - g_error_free (error); - goto out; - } - - /*g_message ("Authentication done. %s", auth_result);*/ - - if (!auth_result) { - char *auth_denied_reason; - - if (!org_freedesktop_PolicyKit_Session_get_auth_denied_reason (session, - &auth_denied_reason, - &error)) { - g_warning ("GetAuthDeniedReason: %s", error->message); - g_error_free (error); - goto out; - } - - g_print ("\n" - "Authentication failed (reason: '%s').\n", auth_denied_reason); - g_free (auth_denied_reason); + if (!obtained_privilege) { + g_print ("Privilege not granted: %s\n", reason_not_obtained != NULL ? reason_not_obtained : "(null)"); } else { - g_print ("\n" - "Authentication succeeded.\n"); - - /* don't restrict privilege to callers PID */ - if (!org_freedesktop_PolicyKit_Session_grant_privilege_temporarily (session, - FALSE, - &error)) { - g_warning ("GrantPrivilegeTemporarily: %s", error->message); - g_error_free (error); - } + /* keep the privilege */ + libpolkit_grant_close (ctx, FALSE); } -out: - - /* don't revoke privilege when we close the session */ - if (!org_freedesktop_PolicyKit_Session_close (session, - TRUE, - &error)) { - g_warning ("Close: %s", error->message); - g_error_free (error); - } + libpolkit_free_context (ctx); exit (0); } -static void -do_grant_privilege (DBusGConnection *conn, const char *user, const char *privilege, const char *resource) -{ - GError *error = NULL; - DBusGProxy *manager; - DBusGProxy *session; - char *session_objpath; - GMainLoop *mainloop; - - grant_user = g_strdup (user); - grant_privilege = g_strdup (privilege); - grant_resource = g_strdup (resource); - - mainloop = g_main_loop_new (NULL, FALSE); - - manager = dbus_g_proxy_new_for_name (conn, - "org.freedesktop.PolicyKit", - "/org/freedesktop/PolicyKit/Manager", - "org.freedesktop.PolicyKit.Manager"); - if (manager == NULL) { - goto out; - } - - if (!org_freedesktop_PolicyKit_Manager_initiate_temporary_privilege_grant (manager, - user, - privilege, - resource, - &session_objpath, - &error)) { - g_warning ("GrantPrivilege: %s", error->message); - g_error_free (error); - goto out; - } - - /*g_debug ("session_objpath = %s", session_objpath);*/ - - session = dbus_g_proxy_new_for_name (conn, - "org.freedesktop.PolicyKit", - session_objpath, - "org.freedesktop.PolicyKit.Session"); - if (session == NULL) { - goto out; - } - - dbus_g_proxy_add_signal (session, "HaveQuestions", G_TYPE_INVALID); - dbus_g_proxy_connect_signal (session, "HaveQuestions", G_CALLBACK (have_questions_handler), - NULL, NULL); - - dbus_g_proxy_add_signal (session, "AuthenticationDone", G_TYPE_INVALID); - dbus_g_proxy_connect_signal (session, "AuthenticationDone", G_CALLBACK (auth_done_handler), - NULL, NULL); - - if (!org_freedesktop_PolicyKit_Session_get_auth_details (session, - &auth_user, - &auth_pam_service_name, - &error)) { - g_warning ("GetAuthDetails: %s", error->message); - g_error_free (error); - goto out; - } - - if (!org_freedesktop_PolicyKit_Session_initiate_auth (session, - &error)) { - g_warning ("InitiateAuth: %s", error->message); - g_error_free (error); - goto out; - } - - g_main_loop_run (mainloop); - g_free (session_objpath); -out: - ; -} - static void usage (int argc, char *argv[]) { @@ -297,15 +171,12 @@ usage (int argc, char *argv[]) "be omitted.\n"); } -static gboolean is_verbose = FALSE; - int main (int argc, char **argv) { int rc; GError *error = NULL; DBusGConnection *bus; - LibPolKitContext *ctx; char *user = NULL; char *resource = NULL; char *privilege = NULL; @@ -321,9 +192,15 @@ main (int argc, char **argv) gboolean is_privileged = FALSE; gboolean is_temporary = FALSE; LibPolKitResult result; + LibPolKitGrantContext *gctx; + LibPolKitContext *ctx; + GMainLoop *mainloop; g_type_init (); + mainloop = g_main_loop_new (NULL, FALSE); + + rc = 1; while (TRUE) { @@ -383,15 +260,26 @@ main (int argc, char **argv) return 1; } - ctx = libpolkit_new_context (dbus_g_connection_get_connection (bus)); + gctx = libpolkit_grant_new_context (bus, + user, + privilege, + resource, + FALSE, + NULL); + if (gctx == NULL) { + g_warning ("Cannot initialize new grant context"); + goto out; + } + ctx = libpolkit_grant_get_libpolkit_context (gctx); result = libpolkit_is_uid_allowed_for_privilege (ctx, - -1, + NULL, user, privilege, resource, &is_privileged, - &is_temporary); + &is_temporary, + NULL); switch (result) { case LIBPOLKIT_RESULT_OK: if (is_privileged) { @@ -428,7 +316,15 @@ main (int argc, char **argv) goto out; } - do_grant_privilege (bus, user, privilege, resource); + libpolkit_grant_set_questions_handler (gctx, questions_cb); + libpolkit_grant_set_grant_complete_handler (gctx, grant_complete_cb); + + if (!libpolkit_grant_initiate_temporary_grant (gctx)) { + g_warning ("Cannot initiate temporary grant; bailing out"); + goto out; + } + + g_main_loop_run (mainloop); out: return rc; diff --git a/tools/polkit-is-privileged.c b/tools/polkit-is-privileged.c index 594902e..e6e0cf6 100644 --- a/tools/polkit-is-privileged.c +++ b/tools/polkit-is-privileged.c @@ -41,17 +41,17 @@ usage (int argc, char *argv[]) fprintf (stderr, "\n" "usage : %s -u -p [-r ]\n" - " [-i ]", argv[0]); + " [-s ]", argv[0]); fprintf (stderr, "\n" "Options:\n" - " -u, --user Username or user id\n" - " -i, --pid Pid of process privilege may be restricted to\n" - " -r, --resource Resource\n" - " -p, --privilege Privilege to test for\n" - " -h, --help Show this information and exit\n" - " -v, --verbose Verbose operation\n" - " -V, --version Print version number\n" + " -u, --user Username or user id\n" + " -s, --system-bus-unique-name Unique system bus connection name\n" + " -r, --resource Resource\n" + " -p, --privilege Privilege to test for\n" + " -h, --help Show this information and exit\n" + " -v, --verbose Verbose operation\n" + " -V, --version Print version number\n" "\n" "Queries system policy whether a given user is allowed for a given\n" "privilege for a given resource. The resource may be omitted.\n" @@ -65,10 +65,10 @@ main (int argc, char *argv[]) char *user = NULL; char *privilege = NULL; char *resource = NULL; - pid_t pid = (pid_t) -1; + char *system_bus_unique_name = NULL; static const struct option long_options[] = { {"user", required_argument, NULL, 'u'}, - {"pid", required_argument, NULL, 'i'}, + {"system-bus-unique-name", required_argument, NULL, 's'}, {"resource", required_argument, NULL, 'r'}, {"privilege", required_argument, NULL, 'p'}, {"help", no_argument, NULL, 'h'}, @@ -89,14 +89,14 @@ main (int argc, char *argv[]) while (TRUE) { int c; - c = getopt_long (argc, argv, "u:r:p:i:hVv", long_options, NULL); + c = getopt_long (argc, argv, "u:r:p:s:hVv", long_options, NULL); if (c == -1) break; switch (c) { - case 'i': - pid = atoi (optarg); + case 's': + system_bus_unique_name = g_strdup (optarg); break; case 'u': @@ -157,12 +157,13 @@ main (int argc, char *argv[]) } result = libpolkit_is_uid_allowed_for_privilege (ctx, - pid, + system_bus_unique_name, user, privilege, resource, &is_allowed, - &is_temporary); + &is_temporary, + NULL); switch (result) { case LIBPOLKIT_RESULT_OK: rc = is_allowed ? 0 : 1; diff --git a/tools/polkit-list-privileges.c b/tools/polkit-list-privileges.c index d466805..bd7e941 100644 --- a/tools/polkit-list-privileges.c +++ b/tools/polkit-list-privileges.c @@ -27,6 +27,7 @@ #endif #include +#include #include #include #include @@ -136,8 +137,11 @@ main (int argc, char *argv[]) const char *privilege; gboolean is_allowed; gboolean is_temporary; + char *is_privileged_but_restricted_to; GList *j; + GList *k; GList *resources; + GList *restrictions; int num_non_temporary; privilege = (const char *) l->data; @@ -146,33 +150,46 @@ main (int argc, char *argv[]) } if (libpolkit_is_uid_allowed_for_privilege (ctx, - -1, + NULL, user, privilege, NULL, &is_allowed, - &is_temporary) == LIBPOLKIT_RESULT_OK) { + &is_temporary, + &is_privileged_but_restricted_to) == LIBPOLKIT_RESULT_OK) { if (is_allowed) { g_print ("privilege %s%s\n", privilege, is_temporary ? " (temporary)" : ""); - } + } else if (is_privileged_but_restricted_to != NULL) { + g_print ("privilege %s (temporary) (restricted to %s)\n", + privilege, is_privileged_but_restricted_to); + } if (libpolkit_get_allowed_resources_for_privilege_for_uid ( ctx, user, privilege, &resources, + &restrictions, &num_non_temporary) == LIBPOLKIT_RESULT_OK) { int n; - for (j = resources, n = 0; j != NULL; j = g_list_next (j), n++) { + for (j = resources, k = restrictions, n = 0; j != NULL; j = g_list_next (j), k = g_list_next (k), n++) { const char *resource; + const char *restriction; resource = (const char *) j->data; - g_print ("resource %s privilege %s%s\n", + restriction = (const char *) k->data; + g_print ("resource %s privilege %s%s", resource, privilege, n >= num_non_temporary ? " (temporary)" : ""); + if (strlen (restriction) > 0) + g_print (" (restricted to %s)\n", restriction); + else + g_print ("\n"); } g_list_foreach (resources, (GFunc) g_free, NULL); g_list_free (resources); + g_list_foreach (restrictions, (GFunc) g_free, NULL); + g_list_free (restrictions); } } diff --git a/tools/polkit-revoke-privilege.c b/tools/polkit-revoke-privilege.c index e0109be..2e75b8b 100644 --- a/tools/polkit-revoke-privilege.c +++ b/tools/polkit-revoke-privilege.c @@ -154,11 +154,11 @@ main (int argc, char **argv) case LIBPOLKIT_RESULT_OK: if (was_revoked) { if (resource == NULL) { - g_print ("User '%s' no longer has privilege '%s'.\n", user, privilege); + g_print ("Privilege '%s' succesfully revoked from user '%s'.\n", privilege, user); } else { - g_print ("User '%s' no longer has privilege '%s' for accessing\n" + g_print ("Privilege '%s' succesfully revoked from user '%s' on\n" "resource '%s'.\n", - user, privilege, resource); + privilege, user, resource); } rc = 0; goto out; @@ -166,23 +166,29 @@ main (int argc, char **argv) break; case LIBPOLKIT_RESULT_ERROR: - g_print ("Error granting resource.\n"); + g_print ("Error: There was an error granting the privilege.\n"); goto out; case LIBPOLKIT_RESULT_INVALID_CONTEXT: - g_print ("Invalid context.\n"); + g_print ("Error: Invalid context.\n"); goto out; case LIBPOLKIT_RESULT_NOT_PRIVILEGED: - g_print ("Not privileged.\n"); + g_print ("Error: Not privileged to perform this operation.\n"); goto out; case LIBPOLKIT_RESULT_NO_SUCH_PRIVILEGE: - g_print ("No such privilege '%s'.\n", privilege); + if (resource == NULL) { + g_print ("Error: User '%s' does not have privilege '%s'.\n", user, privilege); + } else { + g_print ("Error: User '%s' does not have privilege '%s' for accessing\n" + "resource '%s'.\n", + user, privilege, resource); + } goto out; case LIBPOLKIT_RESULT_NO_SUCH_USER: - g_print ("No such user '%s'.\n", user); + g_print ("Error: No such user '%s'.\n", user); goto out; }