]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/bus-convenience.c
bus: add new sd_bus_creds object to encapsulate process credentials
[thirdparty/systemd.git] / src / libsystemd-bus / bus-convenience.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 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-internal.h"
23 #include "bus-message.h"
24 #include "bus-signature.h"
25 #include "bus-util.h"
26 #include "bus-type.h"
27
28 _public_ int sd_bus_emit_signal(
29 sd_bus *bus,
30 const char *path,
31 const char *interface,
32 const char *member,
33 const char *types, ...) {
34
35 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
36 int r;
37
38 assert_return(bus, -EINVAL);
39 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
40 assert_return(!bus_pid_changed(bus), -ECHILD);
41
42 r = sd_bus_message_new_signal(bus, path, interface, member, &m);
43 if (r < 0)
44 return r;
45
46 if (!isempty(types)) {
47 va_list ap;
48
49 va_start(ap, types);
50 r = bus_message_append_ap(m, types, ap);
51 va_end(ap);
52 if (r < 0)
53 return r;
54 }
55
56 return sd_bus_send(bus, m, NULL);
57 }
58
59 _public_ int sd_bus_call_method(
60 sd_bus *bus,
61 const char *destination,
62 const char *path,
63 const char *interface,
64 const char *member,
65 sd_bus_error *error,
66 sd_bus_message **reply,
67 const char *types, ...) {
68
69 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
70 int r;
71
72 assert_return(bus, -EINVAL);
73 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
74 assert_return(!bus_pid_changed(bus), -ECHILD);
75
76 r = sd_bus_message_new_method_call(bus, destination, path, interface, member, &m);
77 if (r < 0)
78 return r;
79
80 if (!isempty(types)) {
81 va_list ap;
82
83 va_start(ap, types);
84 r = bus_message_append_ap(m, types, ap);
85 va_end(ap);
86 if (r < 0)
87 return r;
88 }
89
90 return sd_bus_call(bus, m, 0, error, reply);
91 }
92
93 _public_ int sd_bus_reply_method_return(
94 sd_bus_message *call,
95 const char *types, ...) {
96
97 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
98 int r;
99
100 assert_return(call, -EINVAL);
101 assert_return(call->sealed, -EPERM);
102 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
103 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
104 assert_return(!bus_pid_changed(call->bus), -ECHILD);
105
106 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
107 return 0;
108
109 r = sd_bus_message_new_method_return(call, &m);
110 if (r < 0)
111 return r;
112
113 if (!isempty(types)) {
114 va_list ap;
115
116 va_start(ap, types);
117 r = bus_message_append_ap(m, types, ap);
118 va_end(ap);
119 if (r < 0)
120 return r;
121 }
122
123 return sd_bus_send(call->bus, m, NULL);
124 }
125
126 _public_ int sd_bus_reply_method_error(
127 sd_bus_message *call,
128 const sd_bus_error *e) {
129
130 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
131 int r;
132
133 assert_return(call, -EINVAL);
134 assert_return(call->sealed, -EPERM);
135 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
136 assert_return(sd_bus_error_is_set(e), -EINVAL);
137 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
138 assert_return(!bus_pid_changed(call->bus), -ECHILD);
139
140 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
141 return 0;
142
143 r = sd_bus_message_new_method_error(call, e, &m);
144 if (r < 0)
145 return r;
146
147 return sd_bus_send(call->bus, m, NULL);
148 }
149
150 _public_ int sd_bus_reply_method_errorf(
151 sd_bus_message *call,
152 const char *name,
153 const char *format,
154 ...) {
155
156 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
157 va_list ap;
158
159 assert_return(call, -EINVAL);
160 assert_return(call->sealed, -EPERM);
161 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
162 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
163 assert_return(!bus_pid_changed(call->bus), -ECHILD);
164
165 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
166 return 0;
167
168 va_start(ap, format);
169 bus_error_setfv(&error, name, format, ap);
170 va_end(ap);
171
172 return sd_bus_reply_method_error(call, &error);
173 }
174
175 _public_ int sd_bus_reply_method_errno(
176 sd_bus_message *call,
177 int error,
178 const sd_bus_error *p) {
179
180 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
181
182 assert_return(call, -EINVAL);
183 assert_return(call->sealed, -EPERM);
184 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
185 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
186 assert_return(!bus_pid_changed(call->bus), -ECHILD);
187
188 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
189 return 0;
190
191 if (sd_bus_error_is_set(p))
192 return sd_bus_reply_method_error(call, p);
193
194 sd_bus_error_set_errno(&berror, error);
195
196 return sd_bus_reply_method_error(call, &berror);
197 }
198
199 _public_ int sd_bus_reply_method_errnof(
200 sd_bus_message *call,
201 int error,
202 const char *format,
203 ...) {
204
205 _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
206 va_list ap;
207
208 assert_return(call, -EINVAL);
209 assert_return(call->sealed, -EPERM);
210 assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
211 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
212 assert_return(!bus_pid_changed(call->bus), -ECHILD);
213
214 if (call->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED)
215 return 0;
216
217 va_start(ap, format);
218 bus_error_set_errnofv(&berror, error, format, ap);
219 va_end(ap);
220
221 return sd_bus_reply_method_error(call, &berror);
222 }
223
224 _public_ int sd_bus_get_property(
225 sd_bus *bus,
226 const char *destination,
227 const char *path,
228 const char *interface,
229 const char *member,
230 sd_bus_error *error,
231 sd_bus_message **reply,
232 const char *type) {
233
234 sd_bus_message *rep = NULL;
235 int r;
236
237 assert_return(bus, -EINVAL);
238 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
239 assert_return(member_name_is_valid(member), -EINVAL);
240 assert_return(reply, -EINVAL);
241 assert_return(signature_is_single(type, false), -EINVAL);
242 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
243 assert_return(!bus_pid_changed(bus), -ECHILD);
244
245 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &rep, "ss", strempty(interface), member);
246 if (r < 0)
247 return r;
248
249 r = sd_bus_message_enter_container(rep, 'v', type);
250 if (r < 0) {
251 sd_bus_message_unref(rep);
252 return r;
253 }
254
255 *reply = rep;
256 return 0;
257 }
258
259 _public_ int sd_bus_get_property_trivial(
260 sd_bus *bus,
261 const char *destination,
262 const char *path,
263 const char *interface,
264 const char *member,
265 sd_bus_error *error,
266 char type, void *ptr) {
267
268 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
269 int r;
270
271 assert_return(bus, -EINVAL);
272 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
273 assert_return(member_name_is_valid(member), -EINVAL);
274 assert_return(bus_type_is_trivial(type), -EINVAL);
275 assert_return(ptr, -EINVAL);
276 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
277 assert_return(!bus_pid_changed(bus), -ECHILD);
278
279 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
280 if (r < 0)
281 return r;
282
283 r = sd_bus_message_enter_container(reply, 'v', CHAR_TO_STR(type));
284 if (r < 0)
285 return r;
286
287 r = sd_bus_message_read_basic(reply, type, ptr);
288 if (r < 0)
289 return r;
290
291 return 0;
292 }
293
294 _public_ int sd_bus_get_property_string(
295 sd_bus *bus,
296 const char *destination,
297 const char *path,
298 const char *interface,
299 const char *member,
300 sd_bus_error *error,
301 char **ret) {
302
303 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
304 const char *s;
305 char *n;
306 int r;
307
308 assert_return(bus, -EINVAL);
309 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
310 assert_return(member_name_is_valid(member), -EINVAL);
311 assert_return(ret, -EINVAL);
312 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
313 assert_return(!bus_pid_changed(bus), -ECHILD);
314
315 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
316 if (r < 0)
317 return r;
318
319 r = sd_bus_message_enter_container(reply, 'v', "s");
320 if (r < 0)
321 return r;
322
323 r = sd_bus_message_read_basic(reply, 's', &s);
324 if (r < 0)
325 return r;
326
327 n = strdup(s);
328 if (!n)
329 return -ENOMEM;
330
331 *ret = n;
332 return 0;
333 }
334
335 _public_ int sd_bus_get_property_strv(
336 sd_bus *bus,
337 const char *destination,
338 const char *path,
339 const char *interface,
340 const char *member,
341 sd_bus_error *error,
342 char ***ret) {
343
344 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
345 int r;
346
347 assert_return(bus, -EINVAL);
348 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
349 assert_return(member_name_is_valid(member), -EINVAL);
350 assert_return(ret, -EINVAL);
351 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
352 assert_return(!bus_pid_changed(bus), -ECHILD);
353
354 r = sd_bus_call_method(bus, destination, path, "org.freedesktop.DBus.Properties", "Get", error, &reply, "ss", strempty(interface), member);
355 if (r < 0)
356 return r;
357
358 r = sd_bus_message_enter_container(reply, 'v', NULL);
359 if (r < 0)
360 return r;
361
362 r = sd_bus_message_read_strv(reply, ret);
363 if (r < 0)
364 return r;
365
366 return 0;
367 }
368
369 _public_ int sd_bus_set_property(
370 sd_bus *bus,
371 const char *destination,
372 const char *path,
373 const char *interface,
374 const char *member,
375 sd_bus_error *error,
376 const char *type, ...) {
377
378 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
379 va_list ap;
380 int r;
381
382 assert_return(bus, -EINVAL);
383 assert_return(isempty(interface) || interface_name_is_valid(interface), -EINVAL);
384 assert_return(member_name_is_valid(member), -EINVAL);
385 assert_return(signature_is_single(type, false), -EINVAL);
386 assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN);
387 assert_return(!bus_pid_changed(bus), -ECHILD);
388
389 r = sd_bus_message_new_method_call(bus, destination, path, "org.freedesktop.DBus.Properties", "Set", &m);
390 if (r < 0)
391 return r;
392
393 r = sd_bus_message_append(m, "ss", strempty(interface), member);
394 if (r < 0)
395 return r;
396
397 r = sd_bus_message_open_container(m, 'v', type);
398 if (r < 0)
399 return r;
400
401 va_start(ap, type);
402 r = bus_message_append_ap(m, type, ap);
403 va_end(ap);
404 if (r < 0)
405 return r;
406
407 r = sd_bus_message_close_container(m);
408 if (r < 0)
409 return r;
410
411 return sd_bus_call(bus, m, 0, error, NULL);
412 }
413
414 _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **creds) {
415 sd_bus_creds *c;
416
417 assert_return(call, -EINVAL);
418 assert_return(call->sealed, -EPERM);
419 assert_return(call->bus && BUS_IS_OPEN(call->bus->state), -ENOTCONN);
420 assert_return(!bus_pid_changed(call->bus), -ECHILD);
421
422 c = sd_bus_message_get_creds(call);
423
424 /* All data we need? */
425 if (c && (mask & ~c->mask) == 0) {
426 *creds = sd_bus_creds_ref(c);
427 return 0;
428 }
429
430 /* No data passed? Or not enough data passed to retrieve the missing bits? */
431 if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
432 /* We couldn't read anything from the call, let's try
433 * to get it from the sender or peer */
434
435 if (call->sender)
436 return sd_bus_get_owner_creds(call->bus, call->sender, mask, creds);
437 else
438 return sd_bus_get_peer_creds(call->bus, mask, creds);
439 }
440
441 return sd_bus_creds_extend(c, mask, creds);
442 }