chiark / gitweb /
detect-virt: print 'none' if no virtualization is detected
[elogind.git] / src / polkit.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/types.h>
23
24 #include <errno.h>
25
26 #include "util.h"
27 #include "dbus-common.h"
28 #include "polkit.h"
29
30 /* This mimics dbus_bus_get_unix_user() */
31 static pid_t get_unix_process_id(
32                 DBusConnection *connection,
33                 const char *name,
34                 DBusError *error) {
35
36         DBusMessage *m = NULL, *reply = NULL;
37         uint32_t pid = 0;
38
39         m = dbus_message_new_method_call(
40                         DBUS_SERVICE_DBUS,
41                         DBUS_PATH_DBUS,
42                         DBUS_INTERFACE_DBUS,
43                         "GetConnectionUnixProcessID");
44         if (!m) {
45                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
46                 goto finish;
47         }
48
49         if (!dbus_message_append_args(
50                             m,
51                             DBUS_TYPE_STRING, &name,
52                             DBUS_TYPE_INVALID)) {
53                 dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
54                 goto finish;
55         }
56
57         reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
58         if (!reply)
59                 goto finish;
60
61         if (dbus_set_error_from_message(error, reply))
62                 goto finish;
63
64         if (!dbus_message_get_args(
65                             reply, error,
66                             DBUS_TYPE_UINT32, &pid,
67                             DBUS_TYPE_INVALID))
68                 goto finish;
69
70 finish:
71         if (m)
72                 dbus_message_unref(m);
73
74         if (reply)
75                 dbus_message_unref(reply);
76
77         return (pid_t) pid;
78 }
79
80 int verify_polkit(
81                 DBusConnection *c,
82                 DBusMessage *request,
83                 const char *action,
84                 bool interactive,
85                 bool *_challenge,
86                 DBusError *error) {
87
88         DBusMessage *m = NULL, *reply = NULL;
89         const char *unix_process = "unix-process", *pid = "pid", *starttime = "start-time", *cancel_id = "";
90         const char *sender;
91         uint32_t flags = interactive ? 1 : 0;
92         pid_t pid_raw;
93         uint32_t pid_u32;
94         unsigned long long starttime_raw;
95         uint64_t starttime_u64;
96         DBusMessageIter iter_msg, iter_struct, iter_array, iter_dict, iter_variant;
97         int r;
98         dbus_bool_t authorized = FALSE, challenge = FALSE;
99
100         assert(c);
101         assert(request);
102
103         sender = dbus_message_get_sender(request);
104         if (!sender)
105                 return -EINVAL;
106
107         pid_raw = get_unix_process_id(c, sender, error);
108         if (pid_raw == 0)
109                 return -EINVAL;
110
111         r = get_starttime_of_pid(pid_raw, &starttime_raw);
112         if (r < 0)
113                 return r;
114
115         m = dbus_message_new_method_call(
116                         "org.freedesktop.PolicyKit1",
117                         "/org/freedesktop/PolicyKit1/Authority",
118                         "org.freedesktop.PolicyKit1.Authority",
119                         "CheckAuthorization");
120         if (!m)
121                 return -ENOMEM;
122
123         dbus_message_iter_init_append(m, &iter_msg);
124
125         pid_u32 = (uint32_t) pid_raw;
126         starttime_u64 = (uint64_t) starttime_raw;
127
128         if (!dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_STRUCT, NULL, &iter_struct) ||
129             !dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_STRING, &unix_process) ||
130             !dbus_message_iter_open_container(&iter_struct, DBUS_TYPE_ARRAY, "{sv}", &iter_array) ||
131             !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) ||
132             !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &pid) ||
133             !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "u", &iter_variant) ||
134             !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT32, &pid_u32) ||
135             !dbus_message_iter_close_container(&iter_dict, &iter_variant) ||
136             !dbus_message_iter_close_container(&iter_array, &iter_dict) ||
137             !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) ||
138             !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &starttime) ||
139             !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "t", &iter_variant) ||
140             !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT64, &starttime_u64) ||
141             !dbus_message_iter_close_container(&iter_dict, &iter_variant) ||
142             !dbus_message_iter_close_container(&iter_array, &iter_dict) ||
143             !dbus_message_iter_close_container(&iter_struct, &iter_array) ||
144             !dbus_message_iter_close_container(&iter_msg, &iter_struct) ||
145             !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &action) ||
146             !dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_ARRAY, "{ss}", &iter_array) ||
147             !dbus_message_iter_close_container(&iter_msg, &iter_array) ||
148             !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_UINT32, &flags) ||
149             !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &cancel_id)) {
150                 r = -ENOMEM;
151                 goto finish;
152         }
153
154         reply = dbus_connection_send_with_reply_and_block(c, m, -1, error);
155         if (!reply) {
156                 r = -EIO;
157                 goto finish;
158         }
159
160         if (dbus_set_error_from_message(error, reply)) {
161                 r = -EIO;
162                 goto finish;
163         }
164
165         if (!dbus_message_iter_init(reply, &iter_msg) ||
166             dbus_message_iter_get_arg_type(&iter_msg) != DBUS_TYPE_STRUCT) {
167                 r = -EIO;
168                 goto finish;
169         }
170
171         dbus_message_iter_recurse(&iter_msg, &iter_struct);
172
173         if (dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) {
174                 r = -EIO;
175                 goto finish;
176         }
177
178         dbus_message_iter_get_basic(&iter_struct, &authorized);
179
180         if (!dbus_message_iter_next(&iter_struct) ||
181             dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) {
182                 r = -EIO;
183                 goto finish;
184         }
185
186         dbus_message_iter_get_basic(&iter_struct, &challenge);
187
188         if (authorized)
189                 r = 1;
190         else if (_challenge) {
191                 *_challenge = !!challenge;
192                 r = 0;
193         } else
194                 r = -EPERM;
195
196 finish:
197
198         if (m)
199                 dbus_message_unref(m);
200
201         if (reply)
202                 dbus_message_unref(reply);
203
204         return r;
205 }