core: relex validity checks when destructing half-set up source outputs/sink inputs
[pulseaudio-mirror.git] / src / daemon / polkit.c
blob9799e09485f8fbb4628fc550f812fa2979391b0f
1 /***
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
20 USA.
21 ***/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <inttypes.h>
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>
39 #include "polkit.h"
41 int pa_polkit_check(const char *action_id) {
42 int ret = -1;
43 DBusError dbus_error;
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);
56 goto finish;
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);
66 goto finish;
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."));
78 goto finish;
81 if (!(polkit_caller_get_ck_session(caller, &session))) {
82 pa_log_error(_("Failed to get CK session."));
83 goto finish;
86 /* We need to overwrite the UID in both the caller and the session
87 * object */
89 if (!(polkit_session_set_uid(session, getuid()))) {
90 pa_log_error(_("Cannot set UID on session object."));
91 goto finish;
94 if (!(action = polkit_action_new())) {
95 pa_log_error(_("Cannot allocate PolKitAction."));
96 goto finish;
99 if (!polkit_action_set_action_id(action, action_id)) {
100 pa_log_error(_("Cannot set action_id"));
101 goto finish;
104 if (!(context = polkit_context_new())) {
105 pa_log_error(_("Cannot allocate PolKitContext."));
106 goto finish;
109 if (!polkit_context_init(context, &polkit_error)) {
110 pa_log_error(_("Cannot initialize PolKitContext: %s"), polkit_error_get_error_message(polkit_error));
111 goto finish;
114 for (;;) {
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));
120 goto finish;
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;
135 break;
138 if (dbus_error_is_set(&dbus_error)) {
139 pa_log_error(_("Cannot obtain auth: %s"), dbus_error.message);
140 goto finish;
144 break;
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;
152 finish:
154 if (caller)
155 polkit_caller_unref(caller);
157 if (action)
158 polkit_action_unref(action);
160 if (context)
161 polkit_context_unref(context);
163 if (bus)
164 dbus_connection_unref(bus);
166 dbus_error_free(&dbus_error);
168 if (polkit_error)
169 polkit_error_free(polkit_error);
171 return ret;