summaryrefslogtreecommitdiff
path: root/docs/polkit/overview.xml
blob: 2fa55bfc73b2d54a26b40c46092f4b12147cd423 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
<?xml version="1.0"?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
               "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
<!ENTITY version SYSTEM "../version.xml">
<!ENTITY extensiondir SYSTEM "../extensiondir.xml">
]>
<part id="overview">
  <title>polkit Overview</title>
  <chapter id="polkit-intro">
    <title>Introduction</title>
    <para>
      polkit provides an authorization API intended to be used by
      privileged programs (<quote>MECHANISMS</quote>) offering service
      to unprivileged programs (<quote>CLIENTS</quote>). See the
      <link linkend="polkit.8">polkit</link> manual page for
      the system architecture and big picture.
    </para>
  </chapter>

  <chapter id="polkit-apps">
    <title>Writing polkit applications</title>
    <para>
      polkit applications are applications using the polkit authority
      as a decider component. They do this by installing a <filename
      class='extension'>.policy</filename> file into the <filename
      class='directory'>/usr/share/polkit-1/actions</filename>
      directory and communicating with the polkit authority at runtime
      (either via the <link linkend="ref-dbus-api">D-Bus API</link> or
      indirectly through the <link
      linkend="ref-api">libpolkit-gobject-1</link> library or the
      <link linkend="pkcheck.1">pkcheck</link> command).
    </para>

    <simplesect id="polkit-apps-best-practices">
      <title>Best practices</title>
      <itemizedlist mark='opencircle' spacing='compact'>

        <listitem>
          <para>
            <emphasis role='bold'>DO</emphasis> use polkit if you are
            writing a privileged mechanism (that is, running as
            <emphasis>root</emphasis> or otherwise has special
            permissions) that is intended to be used by unprivileged
            programs.
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DO</emphasis> carefully consider
            what actions to define. In many cases there isn't a 1:1
            mapping between operations and polkit actions. Often a
            polkit action has more to do with the object the operation
            is acting on than the operation itself. It is important to
            strike the right balance between too fine-grained and too
            coarse-grained.
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DO</emphasis> try to pick actions
            and implicit authorizations so applications using your
            mechanism will work out-of-the box for users logged in at
            the console. Not interrupting console users with
            authentication dialogs should be considered a
            priority. For example, it is not wise to require console
            users to authenticate for such mundane tasks as adding a
            printer queue (if the administrator really wants the OS to
            act this way, he can always deploy suitable authorization
            rules).
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DO</emphasis> consider the impact of the
            chosen implicit authorizations on multi-user systems.  Generally,
            ordinary users should be able to neither modify important system's
            behavior for other users, nor view other users' private data.  If
            your application needs an authorization framework at all, it is
            fairly likely that the default configuration should deny
            authorization in at least some cases.  Default to using
            <literal>auth_admin</literal>* instead of
            <literal>auth_self</literal>*.  (On single-user desktops, the
            single user is typically configured as a polkit administrator, so
            the two variants behave equally.  On multi-user systems,
            non-administrator users will be restricted by the default
            configuration.)
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DO</emphasis> pass polkit variables
            along with <link
            linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.CheckAuthorization">CheckAuthorization()</link>
            requests so it's possible to write <emphasis>authorization
            rules</emphasis> matching on these. Also document these
            variables in your documentation (for example, see the
            <ulink
            url="http://udisks.freedesktop.org/docs/latest/udisks-polkit-actions.html">udisks2
            actions and variables</ulink>).
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DO</emphasis> pass a customized
            authentication message (using the
            <literal>polkit.message</literal> and
            <literal>polkit.gettext_domain</literal> variables) that
            include more detailed information about the request than
            whatever is declared in the <filename
            class='extension'>.policy</filename> file's
            <literal>message</literal> element. For example, it's
            better to show <quote>Authentication is needed to format
            INTEL SSDSA2MH080G1GC (/dev/sda)</quote> than just
            <quote>Authentication is needed to format the
            device</quote>.
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DO</emphasis> make sure
            your application works even when the
            <literal>org.freedesktop.PolicyKit1</literal>
            D-Bus service is not available (this can
            happen if
            <link linkend="polkitd.8"><citerefentry><refentrytitle>polkitd</refentrytitle><manvolnum>8</manvolnum></citerefentry></link>
            is not installed or if the <emphasis>polkit.service</emphasis> systemd unit/service has been
            <ulink url="http://0pointer.de/blog/projects/three-levels-of-off.html">masked</ulink>). If you are using the
            <link linkend="ref-api">libpolkit-gobject-1</link> library this
            means handling
            <link linkend="polkit-authority-get-sync">polkit_authority_get_sync()</link>
            or
            <link linkend="polkit-authority-get-finish">polkit_authority_get_finish()</link>
            returning <constant>NULL</constant> or
            <link linkend="polkit-authority-check-authorization">polkit_authority_check_authorization()</link> /
            <link linkend="polkit-authority-check-authorization-sync">polkit_authority_check_authorization_sync()</link>
            failing with an error not in the
            <link linkend="POLKIT-ERROR:CAPS">POLKIT_ERROR</link>
            domain.
            An appropriate way of dealing with the polkit authority
            not being available, could be to allow only uid 0 to
            perform operations, forbid all operations or something
            else.
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DON'T</emphasis> use polkit if your
            program isn't intended to be used by unprivileged
            programs. For example, if you are writing developer tools
            or low-level core OS command-line tools it's fine to just
            require the user to be root. Users can always run your
            tool through e.g.
            <citerefentry><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
            <link
            linkend="pkexec.1"><citerefentry><refentrytitle>pkexec</refentrytitle><manvolnum>1</manvolnum></citerefentry></link>
            or write a simple polkit-using mechanism that allows
            access to a (safe) subset of your tool.
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DON'T</emphasis> use polkit unless
            you actually have to. In other words, not every single
            privileged program providing service to unprivileged
            programs has to use polkit. For example, if you have a
            small well-written <ulink
            url="http://en.wikipedia.org/wiki/Setuid">setuid</ulink>
            helper to help deal with some implementation-detail of the
            OS (such as elevating the priority of the sound server
            process to real-time for console users) it's not really
            helpful to define a polkit action for this since,
            realistically, no-one is going to choose to
            <emphasis>not</emphasis> grant the privilege. Remember, a
            secure program is often one with little amount of code and
            few dependencies.
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DON'T</emphasis> call <link
            linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.CheckAuthorization">CheckAuthorization()</link>
            for all your actions every time the authority emits the
            <link
            linkend="eggdbus-signal-org.freedesktop.PolicyKit1.Authority::Changed">Changed</link>
            signal. Not only is this a waste of resources, the result
            may also be inaccurate as authorization rules can return
            whatever they want, whenever they want.
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DON'T</emphasis> block the main
            thread in your mechanism (e.g. the one used to service IPC
            requests from unprivileged programs) while waiting for the
            authority to reply - calls to <link
            linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.CheckAuthorization">CheckAuthorization()</link>
            may take a very long time (seconds, even minutes) to
            complete as user interaction may be involved.  Instead,
            use either the <link
            linkend="polkit-authority-check-authorization">asynchronous
            API</link> or a dedicated thread with the <link
            linkend="polkit-authority-check-authorization-sync">synchronous
            API</link>.
          </para>
        </listitem>

        <listitem>
          <para>
            <emphasis role='bold'>DON'T</emphasis> include any
            authorization rules with your application as this is only
            intended for administrators and special-purpose operating
            systems / environments. See <xref linkend="polkit-rules"/>
            for more information.
          </para>
        </listitem>

      </itemizedlist>
    </simplesect>

    <simplesect id="polkit-apps-unprivileged">
      <title>Usage in unprivileged programs</title>

      <para>
        An unprivileged program normally does not use polkit directly
        - it simply calls into a privileged mechanism and the
        mechanism either renders service (or refuses the request)
        after checking with polkit (which may include presenting an
        authentication dialog). In this setup, the unprivileged
        program is oblivious to the fact that polkit is being used -
        it simply just waits for the privileged mechanism to carry out
        the request (which, if authentication dialogs are involved may
        take many seconds). This is a good thing because not worrying
        about implementation details like polkit, helps simplify the
        unprivileged program.
      </para>
      <para>
        Occasionally unprivileged programs need to disable, modify or
        remove UI elements to convey to the user that a certain action
        cannot be carried out (because e.g. the user is not
        authorized) or authentication is needed (by e.g. displaying a
        padlock icon in the UI). In this case, the best approach is
        usually to have the unprivileged program get this information
        from the privileged mechanism instead of polkit. This is
        especially true because often there is no reliable way that
        the unprivileged program can know what polkit action is going
        to be used. In general, there is no guarantee that operations
        (such as D-Bus methods) map 1:1: to polkit action - for
        example, a disk manager service's <literal>Format()</literal>
        method may check for the action
        <literal>net.company.diskmanager.format-removable</literal> if
        the disk is removable and
        <literal>net.company.diskmanager.format-fixed</literal>
        otherwise.
      </para>
      <para>
        However, in certain cases, for example when using the
        <emphasis>org.freedesktop.policykit.imply</emphasis> annotation
        (see the
        <link linkend="polkit.8"><citerefentry><refentrytitle>polkit</refentrytitle><manvolnum>8</manvolnum></citerefentry></link> man page),
        it is meaningful for an unprivileged program to query the
        polkit authority (to e.g. update UI elements) and it is
        in fact allowed to do so as long as the unprivileged program doesn't pass any variables along with the
        <link linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.CheckAuthorization">CheckAuthorization()</link>
        call (otherwise it would be easy to spoof authentication dialogs and bypass authorization rules).
        In fact, since this use-case is so common,
        <link linkend="ref-api">libpolkit-gobject-1</link> provides the
        <link linkend="PolkitPermission"><type>PolkitPermission</type></link> type (which is derived from
        <ulink url="http://developer.gnome.org/gio/unstable/GPermission.html"><type>GPermission</type></ulink>)
        that can be used together with
        <ulink url="http://developer.gnome.org/gtk3/unstable/GtkLockButton.html"><type>GtkLockButton</type></ulink>.
        Note that for <type>GtkLockButton</type> to work well, the
        polkit action backing it should use <literal>auth_admin_keep</literal>
	for its implicit authorizations (or more rarely
	<literal>auth_self_keep</literal> for services which don't affect other
	users).
        This is often used to implement an <ulink
        url="http://developer.gnome.org/hig-book/3.2/hig-book.html#windows-instant-apply">instant
        apply</ulink> paradigm whereby the user
        <emphasis>unlocks</emphasis> (by authenticating) e.g. a
        preference pane window and is then free to change settings
        until the authorization expires or is revoked.
      </para>
    </simplesect>

    <simplesect id="polkit-apps-no-auth-agent">
      <title>No authentication agent</title>
      <para>
        If a polkit application wants to handle the case where no
        authentication agent exists (for example if the app is launched
        via a
        <citerefentry><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry>
        login), the application can use the <link
        linkend="PolkitAgentTextListener">PolkitAgentTextListener</link>
        type to spawn its own authentication agent as
        needed. Alternatively, the <xref linkend="pkttyagent.1"/>
        helper can be used to do this.
      </para>
    </simplesect>

  </chapter>

  <chapter id="polkit-agents">
    <title>Writing polkit Authentication Agents</title>
    <para>
      Authentication agents are provided by desktop environments. When
      an user session starts, the agent registers with the polkit
      Authority using the <link
      linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.RegisterAuthenticationAgent">RegisterAuthenticationAgent()</link>
      method. When services are needed, the authority will invoke
      methods on the <link
      linkend="eggdbus-interface-org.freedesktop.PolicyKit1.AuthenticationAgent">org.freedesktop.PolicyKit1.AuthenticationAgent</link>
      D-Bus interface. Once the user is authenticated, (a privileged
      part of) the agent invokes the <link
      linkend="eggdbus-method-org.freedesktop.PolicyKit1.Authority.AuthenticationAgentResponse2">AuthenticationAgentResponse2()</link>
      method.  This method should be treated as an internal
      implementation detail, and callers should use the
      <link linkend="PolkitAgentSession">PolkitAgentSession</link> API to invoke
      it, which currently uses a setuid helper program.
    </para>
    <para>
      The <link linkend="ref-authentication-agent-api">libpolkit-agent-1</link>
      library provides helpers to make it easy to build authentication
      agents that use the native authentication system
      e.g. pam<literal>(8)</literal>.
    </para>
    <para>
      If the environment variable <literal>POLKIT_DEBUG</literal> is
      set, the libpolkit-agent-1 library prints out diagnostic
      information on standard output.
    </para>
  </chapter>

</part>