]> code.delx.au - pulseaudio/blob - src/daemon/polkit.c
udev: check busy status of alsa cards before loading alsa modules and hence initiatin...
[pulseaudio] / src / daemon / polkit.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2004-2006 Lennart Poettering
5 Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6
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.
11
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.
16
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 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <inttypes.h>
30
31 #include <dbus/dbus.h>
32 #include <polkit-dbus/polkit-dbus.h>
33
34 #include <pulse/i18n.h>
35
36 #include <pulsecore/log.h>
37 #include <pulsecore/macro.h>
38
39 #include "polkit.h"
40
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;
51
52 dbus_error_init(&dbus_error);
53
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;
57 }
58
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);
63
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;
67 }
68
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. */
75
76 if (!(polkit_caller_set_uid(caller, getuid()))) {
77 pa_log_error(_("Cannot set UID on caller object."));
78 goto finish;
79 }
80
81 if (!(polkit_caller_get_ck_session(caller, &session))) {
82 pa_log_error(_("Failed to get CK session."));
83 goto finish;
84 }
85
86 /* We need to overwrite the UID in both the caller and the session
87 * object */
88
89 if (!(polkit_session_set_uid(session, getuid()))) {
90 pa_log_error(_("Cannot set UID on session object."));
91 goto finish;
92 }
93
94 if (!(action = polkit_action_new())) {
95 pa_log_error(_("Cannot allocate PolKitAction."));
96 goto finish;
97 }
98
99 if (!polkit_action_set_action_id(action, action_id)) {
100 pa_log_error(_("Cannot set action_id"));
101 goto finish;
102 }
103
104 if (!(context = polkit_context_new())) {
105 pa_log_error(_("Cannot allocate PolKitContext."));
106 goto finish;
107 }
108
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;
112 }
113
114 for (;;) {
115
116 polkit_result = polkit_context_is_caller_authorized(context, action, caller, TRUE, &polkit_error);
117
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;
121 }
122
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
131 ) {
132
133 if (polkit_auth_obtain(action_id, 0, getpid(), &dbus_error)) {
134 polkit_result = POLKIT_RESULT_YES;
135 break;
136 }
137
138 if (dbus_error_is_set(&dbus_error)) {
139 pa_log_error(_("Cannot obtain auth: %s"), dbus_error.message);
140 goto finish;
141 }
142 }
143
144 break;
145 }
146
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));
149
150 ret = polkit_result == POLKIT_RESULT_YES;
151
152 finish:
153
154 if (caller)
155 polkit_caller_unref(caller);
156
157 if (action)
158 polkit_action_unref(action);
159
160 if (context)
161 polkit_context_unref(context);
162
163 if (bus)
164 dbus_connection_unref(bus);
165
166 dbus_error_free(&dbus_error);
167
168 if (polkit_error)
169 polkit_error_free(polkit_error);
170
171 return ret;
172 }