]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/image-dbus.c
logind: open up most bus calls for unpriviliged processes, using PolicyKit
[thirdparty/systemd.git] / src / machine / image-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2014 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 "bus-label.h"
23 #include "bus-common-errors.h"
24 #include "strv.h"
25 #include "bus-util.h"
26 #include "machine-image.h"
27 #include "image-dbus.h"
28
29 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
30
31 int bus_image_method_remove(
32 sd_bus *bus,
33 sd_bus_message *message,
34 void *userdata,
35 sd_bus_error *error) {
36
37 Image *image = userdata;
38 Manager *m = image->userdata;
39 int r;
40
41 assert(bus);
42 assert(message);
43 assert(image);
44
45 r = bus_verify_polkit_async(
46 message,
47 CAP_SYS_ADMIN,
48 "org.freedesktop.machine1.manage-images",
49 false,
50 UID_INVALID,
51 &m->polkit_registry,
52 error);
53 if (r < 0)
54 return r;
55 if (r == 0)
56 return 1; /* Will call us back */
57
58 r = image_remove(image);
59 if (r < 0)
60 return r;
61
62 return sd_bus_reply_method_return(message, NULL);
63 }
64
65 int bus_image_method_rename(
66 sd_bus *bus,
67 sd_bus_message *message,
68 void *userdata,
69 sd_bus_error *error) {
70
71 Image *image = userdata;
72 Manager *m = image->userdata;
73 const char *new_name;
74 int r;
75
76 assert(bus);
77 assert(message);
78 assert(image);
79
80 r = sd_bus_message_read(message, "s", &new_name);
81 if (r < 0)
82 return r;
83
84 if (!image_name_is_valid(new_name))
85 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
86
87 r = bus_verify_polkit_async(
88 message,
89 CAP_SYS_ADMIN,
90 "org.freedesktop.machine1.manage-images",
91 false,
92 UID_INVALID,
93 &m->polkit_registry,
94 error);
95 if (r < 0)
96 return r;
97 if (r == 0)
98 return 1; /* Will call us back */
99
100 r = image_rename(image, new_name);
101 if (r < 0)
102 return r;
103
104 return sd_bus_reply_method_return(message, NULL);
105 }
106
107 int bus_image_method_clone(
108 sd_bus *bus,
109 sd_bus_message *message,
110 void *userdata,
111 sd_bus_error *error) {
112
113 Image *image = userdata;
114 Manager *m = image->userdata;
115 const char *new_name;
116 int r, read_only;
117
118 assert(bus);
119 assert(message);
120 assert(image);
121
122 r = sd_bus_message_read(message, "sb", &new_name, &read_only);
123 if (r < 0)
124 return r;
125
126 if (!image_name_is_valid(new_name))
127 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
128
129 r = bus_verify_polkit_async(
130 message,
131 CAP_SYS_ADMIN,
132 "org.freedesktop.machine1.manage-images",
133 false,
134 UID_INVALID,
135 &m->polkit_registry,
136 error);
137 if (r < 0)
138 return r;
139 if (r == 0)
140 return 1; /* Will call us back */
141
142 r = image_clone(image, new_name, read_only);
143 if (r < 0)
144 return r;
145
146 return sd_bus_reply_method_return(message, NULL);
147 }
148
149 int bus_image_method_mark_read_only(
150 sd_bus *bus,
151 sd_bus_message *message,
152 void *userdata,
153 sd_bus_error *error) {
154
155 Image *image = userdata;
156 Manager *m = image->userdata;
157 int r, read_only;
158
159 assert(bus);
160 assert(message);
161
162 r = sd_bus_message_read(message, "b", &read_only);
163 if (r < 0)
164 return r;
165
166 r = bus_verify_polkit_async(
167 message,
168 CAP_SYS_ADMIN,
169 "org.freedesktop.machine1.manage-images",
170 false,
171 UID_INVALID,
172 &m->polkit_registry,
173 error);
174 if (r < 0)
175 return r;
176 if (r == 0)
177 return 1; /* Will call us back */
178
179 r = image_read_only(image, read_only);
180 if (r < 0)
181 return r;
182
183 return sd_bus_reply_method_return(message, NULL);
184 }
185
186 const sd_bus_vtable image_vtable[] = {
187 SD_BUS_VTABLE_START(0),
188 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
189 SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
190 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Image, type), 0),
191 SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
192 SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
193 SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
194 SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
195 SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
196 SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
197 SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
198 SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
199 SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
200 SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
201 SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
202 SD_BUS_VTABLE_END
203 };
204
205 static int image_flush_cache(sd_event_source *s, void *userdata) {
206 Manager *m = userdata;
207 Image *i;
208
209 assert(s);
210 assert(m);
211
212 while ((i = hashmap_steal_first(m->image_cache)))
213 image_unref(i);
214
215 return 0;
216 }
217
218 int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
219 _cleanup_free_ char *e = NULL;
220 Manager *m = userdata;
221 Image *image = NULL;
222 const char *p;
223 int r;
224
225 assert(bus);
226 assert(path);
227 assert(interface);
228 assert(found);
229
230 p = startswith(path, "/org/freedesktop/machine1/image/");
231 if (!p)
232 return 0;
233
234 e = bus_label_unescape(p);
235 if (!e)
236 return -ENOMEM;
237
238 image = hashmap_get(m->image_cache, e);
239 if (image) {
240 *found = image;
241 return 1;
242 }
243
244 r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
245 if (r < 0)
246 return r;
247
248 if (!m->image_cache_defer_event) {
249 r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m);
250 if (r < 0)
251 return r;
252
253 r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE);
254 if (r < 0)
255 return r;
256 }
257
258 r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT);
259 if (r < 0)
260 return r;
261
262 r = image_find(e, &image);
263 if (r <= 0)
264 return r;
265
266 image->userdata = m;
267
268 r = hashmap_put(m->image_cache, image->name, image);
269 if (r < 0) {
270 image_unref(image);
271 return r;
272 }
273
274 *found = image;
275 return 1;
276 }
277
278 char *image_bus_path(const char *name) {
279 _cleanup_free_ char *e = NULL;
280
281 assert(name);
282
283 e = bus_label_escape(name);
284 if (!e)
285 return NULL;
286
287 return strappend("/org/freedesktop/machine1/image/", e);
288 }
289
290 int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
291 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
292 _cleanup_strv_free_ char **l = NULL;
293 Image *image;
294 Iterator i;
295 int r;
296
297 assert(bus);
298 assert(path);
299 assert(nodes);
300
301 images = hashmap_new(&string_hash_ops);
302 if (!images)
303 return -ENOMEM;
304
305 r = image_discover(images);
306 if (r < 0)
307 return r;
308
309 HASHMAP_FOREACH(image, images, i) {
310 char *p;
311
312 p = image_bus_path(image->name);
313 if (!p)
314 return -ENOMEM;
315
316 r = strv_consume(&l, p);
317 if (r < 0)
318 return r;
319 }
320
321 *nodes = l;
322 l = NULL;
323
324 return 1;
325 }