chiark / gitweb /
conf-parser: warn if an assignment is place outside of a section
[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 General Public License as published by
10   the Free Software Foundation; either version 2 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   General Public License for more details.
17
18   You should have received a copy of the GNU 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 }