]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-dump.c
bus: change creds dumping order to be more close to internal storage order
[thirdparty/systemd.git] / src / libsystemd / sd-bus / bus-dump.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 "util.h"
23 #include "capability.h"
24 #include "strv.h"
25 #include "audit.h"
26 #include "macro.h"
27
28 #include "bus-message.h"
29 #include "bus-internal.h"
30 #include "bus-type.h"
31 #include "bus-dump.h"
32
33 static char *indent(unsigned level, unsigned flags) {
34 char *p;
35 unsigned n, i = 0;
36
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);
46 if (!p)
47 return NULL;
48
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;
56
57 return p;
58 }
59
60 int bus_message_dump(sd_bus_message *m, FILE *f, unsigned flags) {
61 unsigned level = 1;
62 int r;
63
64 assert(m);
65
66 if (!f)
67 f = stdout;
68
69 if (flags & BUS_MESSAGE_DUMP_WITH_HEADER) {
70 fprintf(f,
71 "%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u Priority=%lli",
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(),
75 ansi_highlight(), bus_message_type_to_string(m->header->type), ansi_highlight_off(),
76 m->header->endian,
77 m->header->flags,
78 m->header->version,
79 (long long) m->priority);
80
81 /* Display synthetic message serial number in a more readable
82 * format than (uint32_t) -1 */
83 if (BUS_MESSAGE_COOKIE(m) == 0xFFFFFFFFULL)
84 fprintf(f, " Cookie=-1");
85 else
86 fprintf(f, " Cookie=%" PRIu64, BUS_MESSAGE_COOKIE(m));
87
88 if (m->reply_cookie != 0)
89 fprintf(f, " ReplyCookie=%" PRIu64, m->reply_cookie);
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
114 if (m->monotonic != 0)
115 fprintf(f, " Monotonic="USEC_FMT, m->monotonic);
116 if (m->realtime != 0)
117 fprintf(f, " Realtime="USEC_FMT, m->realtime);
118 if (m->seqnum != 0)
119 fprintf(f, " SequenceNumber=%"PRIu64, m->seqnum);
120
121 if (m->monotonic != 0 || m->realtime != 0 || m->seqnum != 0)
122 fputs("\n", f);
123
124 bus_creds_dump(&m->creds, f, true);
125 }
126
127 r = sd_bus_message_rewind(m, !(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY));
128 if (r < 0) {
129 log_error("Failed to rewind: %s", strerror(-r));
130 return r;
131 }
132
133 if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY))
134 fprintf(f, "%sMESSAGE \"%s\" {\n", indent(0, flags), strempty(m->root_container.signature));
135
136 for (;;) {
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
171 prefix = indent(level, flags);
172 if (!prefix)
173 return log_oom();
174
175 fprintf(f, "%s};\n", prefix);
176 continue;
177 }
178
179 prefix = indent(level, flags);
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:
219 fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off());
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:
239 fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_highlight_off());
240 break;
241
242 case SD_BUS_TYPE_UINT64:
243 fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_highlight_off());
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
271 if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY))
272 fprintf(f, "%s};\n\n", indent(0, flags));
273
274 return 0;
275 }
276
277 static void dump_capabilities(
278 sd_bus_creds *c,
279 FILE *f,
280 const char *name,
281 bool terse,
282 int (*has)(sd_bus_creds *c, int capability)) {
283
284 unsigned long i, last_cap;
285 unsigned n = 0;
286 int r;
287
288 assert(c);
289 assert(f);
290 assert(name);
291 assert(has);
292
293 i = 0;
294 r = has(c, i);
295 if (r < 0)
296 return;
297
298 fprintf(f, "%s%s=%s", terse ? " " : "", name, terse ? "" : ansi_highlight());
299 last_cap = cap_last_cap();
300
301 for (;;) {
302 if (r > 0) {
303 _cleanup_cap_free_charp_ char *t;
304
305 if (n > 0)
306 fputc(' ', f);
307 if (n % 4 == 3)
308 fprintf(f, terse ? "\n " : "\n ");
309
310 t = cap_to_name(i);
311 fprintf(f, "%s", t);
312 n++;
313 }
314
315 i++;
316
317 if (i > last_cap)
318 break;
319
320 r = has(c, i);
321 }
322
323 fputs("\n", f);
324
325 if (!terse)
326 fputs(ansi_highlight_off(), f);
327 }
328
329 int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
330 bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
331 const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
332 uid_t owner, audit_loginuid;
333 uint32_t audit_sessionid;
334 char **cmdline = NULL, **well_known = NULL;
335 const char *prefix, *color, *suffix;
336 int r;
337
338 assert(c);
339
340 if (!f)
341 f = stdout;
342
343 if (terse) {
344 prefix = " ";
345 suffix = "";
346 color = "";
347 } else {
348 const char *off;
349
350 prefix = "";
351 color = ansi_highlight();
352
353 off = ansi_highlight_off();
354 suffix = strappenda(off, "\n");
355 }
356
357 if (c->mask & SD_BUS_CREDS_PID)
358 fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
359 if (c->mask & SD_BUS_CREDS_PID_STARTTIME)
360 fprintf(f, "%sPIDStartTime=%s"USEC_FMT"%s", prefix, color, c->pid_starttime, suffix);
361 if (c->mask & SD_BUS_CREDS_TID)
362 fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
363 if (c->mask & SD_BUS_CREDS_UID)
364 fprintf(f, "%sUID=%s"UID_FMT"%s", prefix, color, c->uid, suffix);
365 r = sd_bus_creds_get_owner_uid(c, &owner);
366 if (r >= 0)
367 fprintf(f, "%sOwnerUID=%s"UID_FMT"%s", prefix, color, owner, suffix);
368 if (c->mask & SD_BUS_CREDS_GID)
369 fprintf(f, "%sGID=%s"GID_FMT"%s", prefix, color, c->gid, suffix);
370
371 if (terse && ((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))
372 fputs("\n", f);
373
374 if (c->mask & SD_BUS_CREDS_COMM)
375 fprintf(f, "%sComm=%s%s%s", prefix, color, c->comm, suffix);
376 if (c->mask & SD_BUS_CREDS_TID_COMM)
377 fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix);
378 if (c->mask & SD_BUS_CREDS_EXE)
379 fprintf(f, "%sExe=%s%s%s", prefix, color, c->exe, suffix);
380
381 if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)))
382 fputs("\n", f);
383
384 if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
385 char **i;
386
387 fprintf(f, "%sCommandLine=%s", prefix, color);
388 STRV_FOREACH(i, cmdline) {
389 if (i != cmdline)
390 fputc(' ', f);
391
392 fputs(*i, f);
393 }
394
395 fprintf(f, "%s", suffix);
396 }
397
398 if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
399 fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
400 if (c->mask & SD_BUS_CREDS_DESCRIPTION)
401 fprintf(f, "%sDescription=%s%s%s", prefix, color, c->description, suffix);
402
403 if (terse && (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION)))
404 fputs("\n", f);
405
406 if (c->mask & SD_BUS_CREDS_CGROUP)
407 fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
408 sd_bus_creds_get_unit(c, &u);
409 if (u)
410 fprintf(f, "%sUnit=%s%s%s", prefix, color, u, suffix);
411 sd_bus_creds_get_user_unit(c, &uu);
412 if (uu)
413 fprintf(f, "%sUserUnit=%s%s%s", prefix, color, uu, suffix);
414 sd_bus_creds_get_slice(c, &sl);
415 if (sl)
416 fprintf(f, "%sSlice=%s%s%s", prefix, color, sl, suffix);
417 sd_bus_creds_get_session(c, &s);
418 if (s)
419 fprintf(f, "%sSession=%s%s%s", prefix, color, s, suffix);
420
421 if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s))
422 fputs("\n", f);
423
424 if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
425 audit_loginuid_is_set = true;
426 fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
427 }
428 if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
429 audit_sessionid_is_set = true;
430 fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
431 }
432
433 if (terse && (audit_loginuid_is_set || audit_sessionid_is_set))
434 fputs("\n", f);
435
436 if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
437 fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix);
438
439 if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
440 char **i;
441
442 fprintf(f, "%sWellKnownNames=%s", prefix, color);
443 STRV_FOREACH(i, well_known) {
444 if (i != well_known)
445 fputc(' ', f);
446
447 fputs(*i, f);
448 }
449
450 fprintf(f, "%s", suffix);
451 }
452
453 if (terse && (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known))
454 fputc('\n', f);
455
456 dump_capabilities(c, f, "EffectiveCapabilities", terse, sd_bus_creds_has_effective_cap);
457 dump_capabilities(c, f, "PermittedCapabilities", terse, sd_bus_creds_has_permitted_cap);
458 dump_capabilities(c, f, "InheritableCapabilities", terse, sd_bus_creds_has_inheritable_cap);
459 dump_capabilities(c, f, "BoundingCapabilities", terse, sd_bus_creds_has_bounding_cap);
460
461 return 0;
462 }
463
464 /*
465 * For details about the file format, see:
466 *
467 * http://wiki.wireshark.org/Development/LibpcapFileFormat
468 */
469
470 typedef struct _packed_ pcap_hdr_s {
471 uint32_t magic_number; /* magic number */
472 uint16_t version_major; /* major version number */
473 uint16_t version_minor; /* minor version number */
474 int32_t thiszone; /* GMT to local correction */
475 uint32_t sigfigs; /* accuracy of timestamps */
476 uint32_t snaplen; /* max length of captured packets, in octets */
477 uint32_t network; /* data link type */
478 } pcap_hdr_t ;
479
480 typedef struct _packed_ pcaprec_hdr_s {
481 uint32_t ts_sec; /* timestamp seconds */
482 uint32_t ts_usec; /* timestamp microseconds */
483 uint32_t incl_len; /* number of octets of packet saved in file */
484 uint32_t orig_len; /* actual length of packet */
485 } pcaprec_hdr_t;
486
487 int bus_pcap_header(size_t snaplen, FILE *f) {
488
489 pcap_hdr_t hdr = {
490 .magic_number = 0xa1b2c3d4U,
491 .version_major = 2,
492 .version_minor = 4,
493 .thiszone = 0, /* UTC */
494 .sigfigs = 0,
495 .network = 231, /* D-Bus */
496 };
497
498 if (!f)
499 f = stdout;
500
501 assert(snaplen > 0);
502 assert((size_t) (uint32_t) snaplen == snaplen);
503
504 hdr.snaplen = (uint32_t) snaplen;
505
506 fwrite(&hdr, 1, sizeof(hdr), f);
507 fflush(f);
508
509 return 0;
510 }
511
512 int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
513 struct bus_body_part *part;
514 pcaprec_hdr_t hdr = {};
515 struct timeval tv;
516 unsigned i;
517 size_t w;
518
519 if (!f)
520 f = stdout;
521
522 assert(m);
523 assert(snaplen > 0);
524 assert((size_t) (uint32_t) snaplen == snaplen);
525
526 if (m->realtime != 0)
527 timeval_store(&tv, m->realtime);
528 else
529 assert_se(gettimeofday(&tv, NULL) >= 0);
530
531 hdr.ts_sec = tv.tv_sec;
532 hdr.ts_usec = tv.tv_usec;
533 hdr.orig_len = BUS_MESSAGE_SIZE(m);
534 hdr.incl_len = MIN(hdr.orig_len, snaplen);
535
536 /* write the pcap header */
537 fwrite(&hdr, 1, sizeof(hdr), f);
538
539 /* write the dbus header */
540 w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
541 fwrite(m->header, 1, w, f);
542 snaplen -= w;
543
544 /* write the dbus body */
545 MESSAGE_FOREACH_PART(part, i, m) {
546 if (snaplen <= 0)
547 break;
548
549 w = MIN(part->size, snaplen);
550 fwrite(part->data, 1, w, f);
551 snaplen -= w;
552 }
553
554 fflush(f);
555
556 return 0;
557 }