2 This file is part of PulseAudio.
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
7 PulseAudio is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published
9 by the Free Software Foundation; either version 2.1 of the License,
10 or (at your option) any later version.
12 PulseAudio is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with PulseAudio; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
31 #include <dbus/dbus.h>
32 #include <polkit-dbus/polkit-dbus.h>
34 #include <pulse/i18n.h>
36 #include <pulsecore/log.h>
37 #include <pulsecore/macro.h>
41 int pa_polkit_check(const char *action_id
) {
44 DBusConnection
*bus
= NULL
;
45 PolKitCaller
*caller
= NULL
;
46 PolKitAction
*action
= NULL
;
47 PolKitContext
*context
= NULL
;
48 PolKitError
*polkit_error
= NULL
;
49 PolKitSession
*session
= NULL
;
50 PolKitResult polkit_result
;
52 dbus_error_init(&dbus_error
);
54 if (!(bus
= dbus_bus_get(DBUS_BUS_SYSTEM
, &dbus_error
))) {
55 pa_log_error(_("Cannot connect to system bus: %s"), dbus_error
.message
);
59 /* There seems to be a bug in some versions of D-Bus that causes
60 * dbus_shutdown() to call exit() when a connection without this
61 * flag disabled was created during runtime.*/
62 dbus_connection_set_exit_on_disconnect(bus
, FALSE
);
64 if (!(caller
= polkit_caller_new_from_pid(bus
, getpid(), &dbus_error
))) {
65 pa_log_error(_("Cannot get caller from PID: %s"), dbus_error
.message
);
69 /* This function is called when PulseAudio is called SUID root. We
70 * want to authenticate the real user that called us and not the
71 * effective user we gained through being SUID root. Hence we
72 * overwrite the UID caller data here explicitly, just for
73 * paranoia. In fact PolicyKit should fill in the UID here anyway
74 * -- an not the EUID or any other user id. */
76 if (!(polkit_caller_set_uid(caller
, getuid()))) {
77 pa_log_error(_("Cannot set UID on caller object."));
81 if (!(polkit_caller_get_ck_session(caller
, &session
))) {
82 pa_log_error(_("Failed to get CK session."));
86 /* We need to overwrite the UID in both the caller and the session
89 if (!(polkit_session_set_uid(session
, getuid()))) {
90 pa_log_error(_("Cannot set UID on session object."));
94 if (!(action
= polkit_action_new())) {
95 pa_log_error(_("Cannot allocate PolKitAction."));
99 if (!polkit_action_set_action_id(action
, action_id
)) {
100 pa_log_error(_("Cannot set action_id"));
104 if (!(context
= polkit_context_new())) {
105 pa_log_error(_("Cannot allocate PolKitContext."));
109 if (!polkit_context_init(context
, &polkit_error
)) {
110 pa_log_error(_("Cannot initialize PolKitContext: %s"), polkit_error_get_error_message(polkit_error
));
116 polkit_result
= polkit_context_is_caller_authorized(context
, action
, caller
, TRUE
, &polkit_error
);
118 if (polkit_error_is_set(polkit_error
)) {
119 pa_log_error(_("Could not determine whether caller is authorized: %s"), polkit_error_get_error_message(polkit_error
));
123 if (polkit_result
== POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH
||
124 polkit_result
== POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_SESSION
||
125 polkit_result
== POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_KEEP_ALWAYS
||
126 polkit_result
== POLKIT_RESULT_ONLY_VIA_ADMIN_AUTH_ONE_SHOT
||
127 polkit_result
== POLKIT_RESULT_ONLY_VIA_SELF_AUTH
||
128 polkit_result
== POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_SESSION
||
129 polkit_result
== POLKIT_RESULT_ONLY_VIA_SELF_AUTH_KEEP_ALWAYS
||
130 polkit_result
== POLKIT_RESULT_ONLY_VIA_SELF_AUTH_ONE_SHOT
133 if (polkit_auth_obtain(action_id
, 0, getpid(), &dbus_error
)) {
134 polkit_result
= POLKIT_RESULT_YES
;
138 if (dbus_error_is_set(&dbus_error
)) {
139 pa_log_error(_("Cannot obtain auth: %s"), dbus_error
.message
);
147 if (polkit_result
!= POLKIT_RESULT_YES
&& polkit_result
!= POLKIT_RESULT_NO
)
148 pa_log_warn(_("PolicyKit responded with '%s'"), polkit_result_to_string_representation(polkit_result
));
150 ret
= polkit_result
== POLKIT_RESULT_YES
;
155 polkit_caller_unref(caller
);
158 polkit_action_unref(action
);
161 polkit_context_unref(context
);
164 dbus_connection_unref(bus
);
166 dbus_error_free(&dbus_error
);
169 polkit_error_free(polkit_error
);