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>
|