~jseutter/landscape-client/invalid-integer

« back to all changes in this revision

Viewing changes to landscape/ui/lib/polkit.py

Merged ui-permissions-and-panel [r=therve,free.ekanayaka][f=911665]

The following changes have been made:
  - Split Configuration model into a DBus service mechanism and a proxy for the client.
  - Split Registration model in to a DBus service mechanism and a proxy for the client (with asynchronous registration).
  - Create PolicyKit policies for configuration and registration and cause these to be checked by the relevant DBus service mechanism when it receives dbus calls (effectively trigger a challenge for a password and only allow admin users to continue).
   - Create DBus service and conf files for the two service mechanisms (Allowing them to be run by the System bus on demand)
   - Create an application desktop file causing the landscape-client-settings-ui program to be launchable from gnome-control-center
   - Create the icon preferences-management-service.svg to represent this activity in gnome-control-center.
   - Create setupui.py - a distutils script for the settings-ui components.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import dbus
 
2
import dbus.service
 
3
import dbus.glib
 
4
import gobject
 
5
 
 
6
 
 
7
class PolicyKitMechanism(dbus.service.Object):
 
8
    """
 
9
    L{PolicyKitMechanism} is a specialised L{dbus.service.Object} which
 
10
    provides PolicyKit authorization checks for a provided DBus bus name and
 
11
    object path.  Subclasses must therefore call l{__init__} here with their
 
12
    object path, bus name and an error class to be raised when permission
 
13
    escalation fails.
 
14
 
 
15
    @type object_path: string
 
16
    @param object_path: The object path to register the subclass with.
 
17
    @type bus_name: dbus.service.BusName
 
18
    @param bus_name: The L{BusName} to the register the subclass with.
 
19
    @type permission_error: dbus.DBusException
 
20
    @param permission_error: A L{dbus.DBusException} to be raised when
 
21
        PolicyKit authorisation fails for the client.
 
22
    """
 
23
 
 
24
    def __init__(self, object_path, bus_name, permission_error,
 
25
                 bypass=False, conn=None):
 
26
        super(PolicyKitMechanism, self).__init__(
 
27
            conn, object_path, bus_name)
 
28
        self.permission_error = permission_error
 
29
        self.dbus_info = None
 
30
        self.polkit = None
 
31
        self.bypass = bypass
 
32
 
 
33
    def _get_polkit_authorization(self, pid, privilege):
 
34
        """
 
35
        Check that the process with id L{pid} is allowed, by policy to utilise
 
36
        the L{privilege }.  If the class was initialised with L{bypass}=True
 
37
        then just say it was authorised without checking (useful for testing).
 
38
        """
 
39
        if self.bypass:
 
40
            return (True, None, "Bypass")
 
41
        polkit = self._get_polkit()
 
42
        try:
 
43
            subject = ('unix-process',
 
44
                       {'pid': dbus.UInt32(pid, variant_level=1),
 
45
                        'start-time': dbus.UInt64(0, variant_level=1)})
 
46
            action_id = privilege
 
47
            details = {"": ""}  # <- empty strings allow type inference
 
48
            flags = dbus.UInt32(1)
 
49
            cancellation_id = ""
 
50
            return polkit.CheckAuthorization(
 
51
                subject,
 
52
                action_id,
 
53
                details,
 
54
                flags,
 
55
                cancellation_id,
 
56
                timeout=600)
 
57
        except dbus.DBusException, err:
 
58
            if (err._dbus_error_name ==
 
59
                'org.freedesktop.DBus.Error.ServiceUnknown'):
 
60
                # This occurs on timeouts, so we retry
 
61
                polkit = None
 
62
                return self._get_polkit_authorization(pid, privilege)
 
63
            else:
 
64
                raise
 
65
 
 
66
    def _get_peer_pid(self, sender, conn):
 
67
        """
 
68
        Get the process ID of the L{sender}.
 
69
        """
 
70
        if self.dbus_info is None:
 
71
            self.dbus_info = dbus.Interface(
 
72
                conn.get_object('org.freedesktop.DBus',
 
73
                '/org/freedesktop/DBus/Bus', False), 'org.freedesktop.DBus')
 
74
        return self.dbus_info.GetConnectionUnixProcessID(sender)
 
75
 
 
76
    def _get_polkit(self):
 
77
        """
 
78
        Connect to polkitd via DBus and return the interface.
 
79
        """
 
80
        if self.polkit is None:
 
81
            self.polkit = dbus.Interface(dbus.SystemBus().get_object(
 
82
                'org.freedesktop.PolicyKit1',
 
83
                '/org/freedesktop/PolicyKit1/Authority', False),
 
84
                'org.freedesktop.PolicyKit1.Authority')
 
85
        return self.polkit
 
86
 
 
87
    def _is_local_call(self, sender, conn):
 
88
        """
 
89
        Check if this is a local call, implying it is within a secure context.
 
90
        """
 
91
        return (sender is None and conn is None)
 
92
 
 
93
    def _is_allowed_by_policy(self, sender, conn, privilege):
 
94
        """
 
95
        Check if we are already in a secure context, and if not check if the
 
96
        policy associated with L{privilege} both exists and allows the peer to
 
97
        utilise it.  As a side effect, if escalation of privileges is required
 
98
        then this will occur and a challenge will be generated if needs be.
 
99
        """
 
100
        if self._is_local_call(sender, conn):
 
101
            return True
 
102
        peer_pid = self._get_peer_pid(sender, conn)
 
103
        (is_auth, _, details) = self._get_polkit_authorization(peer_pid,
 
104
                                                               privilege)
 
105
        if not is_auth:
 
106
            raise self.permission_error(privilege)
 
107
        return True
 
108
 
 
109
 
 
110
def listen():
 
111
    """
 
112
    Invoke a L{gobject.MainLoop} to process incoming DBus events.
 
113
    """
 
114
    mainloop = gobject.MainLoop()
 
115
    mainloop.run()