]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-bus/bus-dump.c
sd-bus: refuse properties that claim to be both writable and constant at the same...
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-dump.c
CommitLineData
3db0e46b
LP
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
3db0e46b
LP
22#include "util.h"
23#include "capability.h"
24#include "strv.h"
5b12334d 25#include "audit.h"
1f70b087 26#include "macro.h"
3db0e46b
LP
27
28#include "bus-message.h"
29#include "bus-internal.h"
30#include "bus-type.h"
31#include "bus-dump.h"
32
d55192ad 33static char *indent(unsigned level, unsigned flags) {
f8cfb5f5 34 char *p;
d55192ad 35 unsigned n, i = 0;
f8cfb5f5 36
d55192ad
LP
37 n = 0;
38
39 if (flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY && level > 0)
40 level -= 1;
41
42 if (flags & BUS_MESSAGE_DUMP_WITH_HEADER)
43 n += 2;
44
45 p = new(char, n + level*8 + 1);
f8cfb5f5
LP
46 if (!p)
47 return NULL;
48
d55192ad
LP
49 if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) {
50 p[i++] = ' ';
51 p[i++] = ' ';
52 }
53
54 memset(p + i, ' ', level*8);
55 p[i + level*8] = 0;
f8cfb5f5
LP
56
57 return p;
58}
59
d55192ad 60int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
3db0e46b
LP
61 unsigned level = 1;
62 int r;
3db0e46b
LP
63
64 assert(m);
65
66 if (!f)
67 f = stdout;
68
d55192ad 69 if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) {
3db0e46b 70 fprintf(f,
6b01f1d3 71 "%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%lli",
f8cfb5f5
LP
72 m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() :
73 m->header->type == SD_BUS_MESSAGE_METHOD_RETURN ? ansi_highlight_green() :
74 m->header->type != SD_BUS_MESSAGE_SIGNAL ? ansi_highlight() : "", draw_special_char(DRAW_TRIANGULAR_BULLET), ansi_highlight_off(),
3db0e46b 75 ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(),
f8cfb5f5 76 m->header->endian,
3db0e46b 77 m->header->flags,
ca7b42c8
LP
78 m->header->version,
79 (long long) m->priority);
a009c158
LS
80
81 /* Display synthetic message serial number in a more readable
82 * format than (uint32_t) -1 */
693eb9a2
LP
83 if (BUS_MESSAGE_COOKIE(m) == 0xFFFFFFFFULL)
84 fprintf(f, " Cookie=-1");
a009c158 85 else
42c4ebcb 86 fprintf(f, " Cookie=%" PRIu64, BUS_MESSAGE_COOKIE(m));
3db0e46b 87
693eb9a2 88 if (m->reply_cookie != 0)
42c4ebcb 89 fprintf(f, " ReplyCookie=%" PRIu64, m->reply_cookie);
3db0e46b
LP
90
91 fputs("\n", f);
92
93 if (m->sender)
94 fprintf(f, " Sender=%s%s%s", ansi_highlight(), m->sender, ansi_highlight_off());
95 if (m->destination)
96 fprintf(f, " Destination=%s%s%s", ansi_highlight(), m->destination, ansi_highlight_off());
97 if (m->path)
98 fprintf(f, " Path=%s%s%s", ansi_highlight(), m->path, ansi_highlight_off());
99 if (m->interface)
100 fprintf(f, " Interface=%s%s%s", ansi_highlight(), m->interface, ansi_highlight_off());
101 if (m->member)
102 fprintf(f, " Member=%s%s%s", ansi_highlight(), m->member, ansi_highlight_off());
103
104 if (m->sender || m->destination || m->path || m->interface || m->member)
105 fputs("\n", f);
106
107 if (sd_bus_error_is_set(&m->error))
108 fprintf(f,
109 " ErrorName=%s%s%s"
110 " ErrorMessage=%s\"%s\"%s\n",
111 ansi_highlight_red(), strna(m->error.name), ansi_highlight_off(),
112 ansi_highlight_red(), strna(m->error.message), ansi_highlight_off());
113
3db0e46b 114 if (m->monotonic != 0)
de0671ee 115 fprintf(f, " Monotonic="USEC_FMT, m->monotonic);
3db0e46b 116 if (m->realtime != 0)
de0671ee 117 fprintf(f, " Realtime="USEC_FMT, m->realtime);
6a0e376c 118 if (m->seqnum != 0)
de0671ee 119 fprintf(f, " SequenceNumber=%"PRIu64, m->seqnum);
3db0e46b 120
6a0e376c 121 if (m->monotonic != 0 || m->realtime != 0 || m->seqnum != 0)
3db0e46b
LP
122 fputs("\n", f);
123
5b12334d 124 bus_creds_dump(&m->creds, f);
3db0e46b
LP
125 }
126
d55192ad 127 r = sd_bus_message_rewind(m, !(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY));
3db0e46b
LP
128 if (r < 0) {
129 log_error("Failed to rewind: %s", strerror(-r));
130 return r;
131 }
132
d55192ad
LP
133 if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY))
134 fprintf(f, "%sMESSAGE \"%s\" {\n", indent(0, flags), strempty(m->root_container.signature));
3db0e46b 135
f168c273 136 for (;;) {
3db0e46b
LP
137 _cleanup_free_ char *prefix = NULL;
138 const char *contents = NULL;
139 char type;
140 union {
141 uint8_t u8;
142 uint16_t u16;
143 int16_t s16;
144 uint32_t u32;
145 int32_t s32;
146 uint64_t u64;
147 int64_t s64;
148 double d64;
149 const char *string;
150 int i;
151 } basic;
152
153 r = sd_bus_message_peek_type(m, &type, &contents);
154 if (r < 0) {
155 log_error("Failed to peek type: %s", strerror(-r));
156 return r;
157 }
158
159 if (r == 0) {
160 if (level <= 1)
161 break;
162
163 r = sd_bus_message_exit_container(m);
164 if (r < 0) {
165 log_error("Failed to exit container: %s", strerror(-r));
166 return r;
167 }
168
169 level--;
170
d55192ad 171 prefix = indent(level, flags);
3db0e46b
LP
172 if (!prefix)
173 return log_oom();
174
175 fprintf(f, "%s};\n", prefix);
176 continue;
177 }
178
d55192ad 179 prefix = indent(level, flags);
3db0e46b
LP
180 if (!prefix)
181 return log_oom();
182
183 if (bus_type_is_container(type) > 0) {
184 r = sd_bus_message_enter_container(m, type, contents);
185 if (r < 0) {
186 log_error("Failed to enter container: %s", strerror(-r));
187 return r;
188 }
189
190 if (type == SD_BUS_TYPE_ARRAY)
191 fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
192 else if (type == SD_BUS_TYPE_VARIANT)
193 fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents);
194 else if (type == SD_BUS_TYPE_STRUCT)
195 fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents);
196 else if (type == SD_BUS_TYPE_DICT_ENTRY)
197 fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
198
199 level ++;
200
201 continue;
202 }
203
204 r = sd_bus_message_read_basic(m, type, &basic);
205 if (r < 0) {
206 log_error("Failed to get basic: %s", strerror(-r));
207 return r;
208 }
209
210 assert(r > 0);
211
212 switch (type) {
213
214 case SD_BUS_TYPE_BYTE:
215 fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off());
216 break;
217
218 case SD_BUS_TYPE_BOOLEAN:
5232c42e 219 fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off());
3db0e46b
LP
220 break;
221
222 case SD_BUS_TYPE_INT16:
223 fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off());
224 break;
225
226 case SD_BUS_TYPE_UINT16:
227 fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off());
228 break;
229
230 case SD_BUS_TYPE_INT32:
231 fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off());
232 break;
233
234 case SD_BUS_TYPE_UINT32:
235 fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off());
236 break;
237
238 case SD_BUS_TYPE_INT64:
de0671ee 239 fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_highlight_off());
3db0e46b
LP
240 break;
241
242 case SD_BUS_TYPE_UINT64:
de0671ee 243 fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_highlight_off());
3db0e46b
LP
244 break;
245
246 case SD_BUS_TYPE_DOUBLE:
247 fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off());
248 break;
249
250 case SD_BUS_TYPE_STRING:
251 fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
252 break;
253
254 case SD_BUS_TYPE_OBJECT_PATH:
255 fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
256 break;
257
258 case SD_BUS_TYPE_SIGNATURE:
259 fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
260 break;
261
262 case SD_BUS_TYPE_UNIX_FD:
263 fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off());
264 break;
265
266 default:
267 assert_not_reached("Unknown basic type.");
268 }
269 }
270
d55192ad
LP
271 if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY))
272 fprintf(f, "%s};\n\n", indent(0, flags));
273
3db0e46b
LP
274 return 0;
275}
5b12334d
LP
276
277static void dump_capabilities(
278 sd_bus_creds *c,
279 FILE *f,
280 const char *name,
281 int (*has)(sd_bus_creds *c, int capability)) {
282
283 unsigned long i, last_cap;
284 unsigned n = 0;
285 int r;
286
287 assert(c);
288 assert(f);
289 assert(name);
290 assert(has);
291
292 i = 0;
293 r = has(c, i);
294 if (r < 0)
295 return;
296
297 fprintf(f, " %s=", name);
298 last_cap = cap_last_cap();
299
300 for (;;) {
301 if (r > 0) {
5ce70e5b
ZJS
302 _cleanup_cap_free_charp_ char *t;
303
5b12334d
LP
304 if (n > 0)
305 fputc(' ', f);
306 if (n % 4 == 3)
307 fputs("\n ", f);
308
5ce70e5b
ZJS
309 t = cap_to_name(i);
310 fprintf(f, "%s", t);
5b12334d
LP
311 n++;
312 }
313
314 i++;
315
316 if (i > last_cap)
317 break;
318
319 r = has(c, i);
320 }
321
322 fputs("\n", f);
323}
324
325int bus_creds_dump(sd_bus_creds *c, FILE *f) {
326 bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
327 const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
328 uid_t owner, audit_loginuid;
329 uint32_t audit_sessionid;
49b832c5 330 char **cmdline = NULL, **well_known = NULL;
5b12334d
LP
331 int r;
332
333 assert(c);
334
335 if (!f)
336 f = stdout;
337
338 if (c->mask & SD_BUS_CREDS_PID)
de0671ee 339 fprintf(f, " PID="PID_FMT, c->pid);
5b12334d 340 if (c->mask & SD_BUS_CREDS_PID_STARTTIME)
de0671ee 341 fprintf(f, " PIDStartTime="USEC_FMT, c->pid_starttime);
5b12334d 342 if (c->mask & SD_BUS_CREDS_TID)
de0671ee 343 fprintf(f, " TID="PID_FMT, c->tid);
5b12334d 344 if (c->mask & SD_BUS_CREDS_UID)
de0671ee 345 fprintf(f, " UID="UID_FMT, c->uid);
5b12334d
LP
346 r = sd_bus_creds_get_owner_uid(c, &owner);
347 if (r >= 0)
de0671ee 348 fprintf(f, " OwnerUID="UID_FMT, owner);
5b12334d 349 if (c->mask & SD_BUS_CREDS_GID)
de0671ee 350 fprintf(f, " GID="GID_FMT, c->gid);
5b12334d
LP
351
352 if ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID)) || r >= 0)
353 fputs("\n", f);
354
355 if (c->mask & SD_BUS_CREDS_EXE)
356 fprintf(f, " Exe=%s", c->exe);
357 if (c->mask & SD_BUS_CREDS_COMM)
358 fprintf(f, " Comm=%s", c->comm);
359 if (c->mask & SD_BUS_CREDS_TID_COMM)
360 fprintf(f, " TIDComm=%s", c->tid_comm);
14008e4e
LP
361
362 if (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM))
363 fputs("\n", f);
364
5b12334d
LP
365 if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
366 fprintf(f, " Label=%s", c->label);
455971c1
LP
367 if (c->mask & SD_BUS_CREDS_DESCRIPTION)
368 fprintf(f, " Description=%s", c->description);
5b12334d 369
455971c1 370 if (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION))
5b12334d
LP
371 fputs("\n", f);
372
373 if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
374 char **i;
375
49b832c5 376 fputs(" CommandLine={", f);
5b12334d
LP
377 STRV_FOREACH(i, cmdline) {
378 if (i != cmdline)
379 fputc(' ', f);
380
381 fputs(*i, f);
382 }
383
49b832c5 384 fputs("}\n", f);
5b12334d
LP
385 }
386
387 if (c->mask & SD_BUS_CREDS_CGROUP)
388 fprintf(f, " CGroup=%s", c->cgroup);
389 sd_bus_creds_get_unit(c, &u);
390 if (u)
391 fprintf(f, " Unit=%s", u);
392 sd_bus_creds_get_user_unit(c, &uu);
393 if (uu)
394 fprintf(f, " UserUnit=%s", uu);
395 sd_bus_creds_get_slice(c, &sl);
396 if (sl)
397 fprintf(f, " Slice=%s", sl);
398 sd_bus_creds_get_session(c, &s);
399 if (s)
400 fprintf(f, " Session=%s", s);
401
402 if ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s)
403 fputs("\n", f);
404
405 if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
406 audit_loginuid_is_set = true;
de0671ee 407 fprintf(f, " AuditLoginUID="UID_FMT, audit_loginuid);
5b12334d
LP
408 }
409 if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
410 audit_sessionid_is_set = true;
de0671ee 411 fprintf(f, " AuditSessionID=%"PRIu32, audit_sessionid);
5b12334d
LP
412 }
413
414 if (audit_loginuid_is_set || audit_sessionid_is_set)
415 fputs("\n", f);
416
49b832c5
LP
417 if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
418 fprintf(f, " UniqueName=%s", c->unique_name);
419
420 if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
421 char **i;
422
423 fputs(" WellKnownNames={", f);
424 STRV_FOREACH(i, well_known) {
425 if (i != well_known)
426 fputc(' ', f);
427
428 fputs(*i, f);
429 }
430
3310dfd5 431 fputc('}', f);
49b832c5
LP
432 }
433
3310dfd5
LP
434 if (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known)
435 fputc('\n', f);
436
5b12334d
LP
437 dump_capabilities(c, f, "EffectiveCapabilities", sd_bus_creds_has_effective_cap);
438 dump_capabilities(c, f, "PermittedCapabilities", sd_bus_creds_has_permitted_cap);
439 dump_capabilities(c, f, "InheritableCapabilities", sd_bus_creds_has_inheritable_cap);
440 dump_capabilities(c, f, "BoundingCapabilities", sd_bus_creds_has_bounding_cap);
441
442 return 0;
443}
1f70b087
LP
444
445/*
446 * For details about the file format, see:
447 *
448 * http://wiki.wireshark.org/Development/LibpcapFileFormat
449 */
450
451typedef struct _packed_ pcap_hdr_s {
452 uint32_t magic_number; /* magic number */
453 uint16_t version_major; /* major version number */
454 uint16_t version_minor; /* minor version number */
455 int32_t thiszone; /* GMT to local correction */
456 uint32_t sigfigs; /* accuracy of timestamps */
457 uint32_t snaplen; /* max length of captured packets, in octets */
458 uint32_t network; /* data link type */
459} pcap_hdr_t ;
460
461typedef struct _packed_ pcaprec_hdr_s {
462 uint32_t ts_sec; /* timestamp seconds */
463 uint32_t ts_usec; /* timestamp microseconds */
464 uint32_t incl_len; /* number of octets of packet saved in file */
465 uint32_t orig_len; /* actual length of packet */
466} pcaprec_hdr_t;
467
468int bus_pcap_header(size_t snaplen, FILE *f) {
469
470 pcap_hdr_t hdr = {
471 .magic_number = 0xa1b2c3d4U,
472 .version_major = 2,
473 .version_minor = 4,
474 .thiszone = 0, /* UTC */
475 .sigfigs = 0,
476 .network = 231, /* D-Bus */
477 };
478
479 if (!f)
480 f = stdout;
481
482 assert(snaplen > 0);
483 assert((size_t) (uint32_t) snaplen == snaplen);
484
485 hdr.snaplen = (uint32_t) snaplen;
486
487 fwrite(&hdr, 1, sizeof(hdr), f);
488 fflush(f);
489
490 return 0;
491}
492
493int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
494 struct bus_body_part *part;
495 pcaprec_hdr_t hdr = {};
496 struct timeval tv;
497 unsigned i;
498 size_t w;
499
500 if (!f)
501 f = stdout;
502
503 assert(m);
504 assert(snaplen > 0);
505 assert((size_t) (uint32_t) snaplen == snaplen);
506
507 if (m->realtime != 0)
508 timeval_store(&tv, m->realtime);
509 else
510 assert_se(gettimeofday(&tv, NULL) >= 0);
511
512 hdr.ts_sec = tv.tv_sec;
513 hdr.ts_usec = tv.tv_usec;
514 hdr.orig_len = BUS_MESSAGE_SIZE(m);
515 hdr.incl_len = MIN(hdr.orig_len, snaplen);
516
517 /* write the pcap header */
518 fwrite(&hdr, 1, sizeof(hdr), f);
519
520 /* write the dbus header */
521 w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
522 fwrite(m->header, 1, w, f);
523 snaplen -= w;
524
525 /* write the dbus body */
526 MESSAGE_FOREACH_PART(part, i, m) {
527 if (snaplen <= 0)
528 break;
529
530 w = MIN(part->size, snaplen);
531 fwrite(part->data, 1, w, f);
532 snaplen -= w;
533 }
534
535 fflush(f);
536
537 return 0;
538}