chiark / gitweb /
journal: add new system-cat tool as kind of a more powerfull BSD logger
[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                 DBusError *error) {
86
87         DBusMessage *m = NULL, *reply = NULL;
88         const char *unix_process = "unix-process", *pid = "pid", *starttime = "start-time", *cancel_id = "";
89         const char *sender;
90         uint32_t flags = interactive ? 1 : 0;
91         pid_t pid_raw;
92         uint32_t pid_u32;
93         unsigned long long starttime_raw;
94         uint64_t starttime_u64;
95         DBusMessageIter iter_msg, iter_struct, iter_array, iter_dict, iter_variant;
96         int r;
97         dbus_bool_t authorized = FALSE;
98
99         assert(c);
100         assert(request);
101
102         sender = dbus_message_get_sender(request);
103         if (!sender)
104                 return -EINVAL;
105
106         pid_raw = get_unix_process_id(c, sender, error);
107         if (pid_raw == 0)
108                 return -EINVAL;
109
110         r = get_starttime_of_pid(pid_raw, &starttime_raw);
111         if (r < 0)
112                 return r;
113
114         m = dbus_message_new_method_call(
115                         "org.freedesktop.PolicyKit1",
116                         "/org/freedesktop/PolicyKit1/Authority",
117                         "org.freedesktop.PolicyKit1.Authority",
118                         "CheckAuthorization");
119         if (!m)
120                 return -ENOMEM;
121
122         dbus_message_iter_init_append(m, &iter_msg);
123
124         pid_u32 = (uint32_t) pid_raw;
125         starttime_u64 = (uint64_t) starttime_raw;
126
127         if (!dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_STRUCT, NULL, &iter_struct) ||
128             !dbus_message_iter_append_basic(&iter_struct, DBUS_TYPE_STRING, &unix_process) ||
129             !dbus_message_iter_open_container(&iter_struct, DBUS_TYPE_ARRAY, "{sv}", &iter_array) ||
130             !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) ||
131             !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &pid) ||
132             !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "u", &iter_variant) ||
133             !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT32, &pid_u32) ||
134             !dbus_message_iter_close_container(&iter_dict, &iter_variant) ||
135             !dbus_message_iter_close_container(&iter_array, &iter_dict) ||
136             !dbus_message_iter_open_container(&iter_array, DBUS_TYPE_DICT_ENTRY, NULL, &iter_dict) ||
137             !dbus_message_iter_append_basic(&iter_dict, DBUS_TYPE_STRING, &starttime) ||
138             !dbus_message_iter_open_container(&iter_dict, DBUS_TYPE_VARIANT, "t", &iter_variant) ||
139             !dbus_message_iter_append_basic(&iter_variant, DBUS_TYPE_UINT64, &starttime_u64) ||
140             !dbus_message_iter_close_container(&iter_dict, &iter_variant) ||
141             !dbus_message_iter_close_container(&iter_array, &iter_dict) ||
142             !dbus_message_iter_close_container(&iter_struct, &iter_array) ||
143             !dbus_message_iter_close_container(&iter_msg, &iter_struct) ||
144             !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &action) ||
145             !dbus_message_iter_open_container(&iter_msg, DBUS_TYPE_ARRAY, "{ss}", &iter_array) ||
146             !dbus_message_iter_close_container(&iter_msg, &iter_array) ||
147             !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_UINT32, &flags) ||
148             !dbus_message_iter_append_basic(&iter_msg, DBUS_TYPE_STRING, &cancel_id)) {
149                 r = -ENOMEM;
150                 goto finish;
151         }
152
153         reply = dbus_connection_send_with_reply_and_block(c, m, -1, error);
154         if (!reply) {
155                 r = -EIO;
156                 goto finish;
157         }
158
159         if (dbus_set_error_from_message(error, reply)) {
160                 r = -EIO;
161                 goto finish;
162         }
163
164         if (!dbus_message_iter_init(reply, &iter_msg) ||
165             dbus_message_iter_get_arg_type(&iter_msg) != DBUS_TYPE_STRUCT) {
166                 r = -EIO;
167                 goto finish;
168         }
169
170         dbus_message_iter_recurse(&iter_msg, &iter_struct);
171
172         if (dbus_message_iter_get_arg_type(&iter_struct) != DBUS_TYPE_BOOLEAN) {
173                 r = -EIO;
174                 goto finish;
175         }
176
177         dbus_message_iter_get_basic(&iter_struct, &authorized);
178
179         r = authorized ? 0 : -EPERM;
180
181 finish:
182
183         if (m)
184                 dbus_message_unref(m);
185
186         if (reply)
187                 dbus_message_unref(reply);
188
189         return r;
190 }