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