chiark / gitweb /
4bc896549a464eded5e0035baa5f3d94b34aff8c
[elogind.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
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=%"PRIi64,
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                         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                 return log_error_errno(r, "Failed to rewind: %m");
130
131         if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
132                 _cleanup_free_ char *prefix = NULL;
133
134                 prefix = indent(0, flags);
135                 if (!prefix)
136                         return log_oom();
137
138                 fprintf(f, "%sMESSAGE \"%s\" {\n", prefix, strempty(m->root_container.signature));
139         }
140
141         for (;;) {
142                 _cleanup_free_ char *prefix = NULL;
143                 const char *contents = NULL;
144                 char type;
145                 union {
146                         uint8_t u8;
147                         uint16_t u16;
148                         int16_t s16;
149                         uint32_t u32;
150                         int32_t s32;
151                         uint64_t u64;
152                         int64_t s64;
153                         double d64;
154                         const char *string;
155                         int i;
156                 } basic;
157
158                 r = sd_bus_message_peek_type(m, &type, &contents);
159                 if (r < 0)
160                         return log_error_errno(r, "Failed to peek type: %m");
161
162                 if (r == 0) {
163                         if (level <= 1)
164                                 break;
165
166                         r = sd_bus_message_exit_container(m);
167                         if (r < 0)
168                                 return log_error_errno(r, "Failed to exit container: %m");
169
170                         level--;
171
172                         prefix = indent(level, flags);
173                         if (!prefix)
174                                 return log_oom();
175
176                         fprintf(f, "%s};\n", prefix);
177                         continue;
178                 }
179
180                 prefix = indent(level, flags);
181                 if (!prefix)
182                         return log_oom();
183
184                 if (bus_type_is_container(type) > 0) {
185                         r = sd_bus_message_enter_container(m, type, contents);
186                         if (r < 0)
187                                 return log_error_errno(r, "Failed to enter container: %m");
188
189                         if (type == SD_BUS_TYPE_ARRAY)
190                                 fprintf(f, "%sARRAY \"%s\" {\n", prefix, contents);
191                         else if (type == SD_BUS_TYPE_VARIANT)
192                                 fprintf(f, "%sVARIANT \"%s\" {\n", prefix, contents);
193                         else if (type == SD_BUS_TYPE_STRUCT)
194                                 fprintf(f, "%sSTRUCT \"%s\" {\n", prefix, contents);
195                         else if (type == SD_BUS_TYPE_DICT_ENTRY)
196                                 fprintf(f, "%sDICT_ENTRY \"%s\" {\n", prefix, contents);
197
198                         level ++;
199
200                         continue;
201                 }
202
203                 r = sd_bus_message_read_basic(m, type, &basic);
204                 if (r < 0)
205                         return log_error_errno(r, "Failed to get basic: %m");
206
207                 assert(r > 0);
208
209                 switch (type) {
210
211                 case SD_BUS_TYPE_BYTE:
212                         fprintf(f, "%sBYTE %s%u%s;\n", prefix, ansi_highlight(), basic.u8, ansi_highlight_off());
213                         break;
214
215                 case SD_BUS_TYPE_BOOLEAN:
216                         fprintf(f, "%sBOOLEAN %s%s%s;\n", prefix, ansi_highlight(), true_false(basic.i), ansi_highlight_off());
217                         break;
218
219                 case SD_BUS_TYPE_INT16:
220                         fprintf(f, "%sINT16 %s%i%s;\n", prefix, ansi_highlight(), basic.s16, ansi_highlight_off());
221                         break;
222
223                 case SD_BUS_TYPE_UINT16:
224                         fprintf(f, "%sUINT16 %s%u%s;\n", prefix, ansi_highlight(), basic.u16, ansi_highlight_off());
225                         break;
226
227                 case SD_BUS_TYPE_INT32:
228                         fprintf(f, "%sINT32 %s%i%s;\n", prefix, ansi_highlight(), basic.s32, ansi_highlight_off());
229                         break;
230
231                 case SD_BUS_TYPE_UINT32:
232                         fprintf(f, "%sUINT32 %s%u%s;\n", prefix, ansi_highlight(), basic.u32, ansi_highlight_off());
233                         break;
234
235                 case SD_BUS_TYPE_INT64:
236                         fprintf(f, "%sINT64 %s%"PRIi64"%s;\n", prefix, ansi_highlight(), basic.s64, ansi_highlight_off());
237                         break;
238
239                 case SD_BUS_TYPE_UINT64:
240                         fprintf(f, "%sUINT64 %s%"PRIu64"%s;\n", prefix, ansi_highlight(), basic.u64, ansi_highlight_off());
241                         break;
242
243                 case SD_BUS_TYPE_DOUBLE:
244                         fprintf(f, "%sDOUBLE %s%g%s;\n", prefix, ansi_highlight(), basic.d64, ansi_highlight_off());
245                         break;
246
247                 case SD_BUS_TYPE_STRING:
248                         fprintf(f, "%sSTRING \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
249                         break;
250
251                 case SD_BUS_TYPE_OBJECT_PATH:
252                         fprintf(f, "%sOBJECT_PATH \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
253                         break;
254
255                 case SD_BUS_TYPE_SIGNATURE:
256                         fprintf(f, "%sSIGNATURE \"%s%s%s\";\n", prefix, ansi_highlight(), basic.string, ansi_highlight_off());
257                         break;
258
259                 case SD_BUS_TYPE_UNIX_FD:
260                         fprintf(f, "%sUNIX_FD %s%i%s;\n", prefix, ansi_highlight(), basic.i, ansi_highlight_off());
261                         break;
262
263                 default:
264                         assert_not_reached("Unknown basic type.");
265                 }
266         }
267
268         if (!(flags & BUS_MESSAGE_DUMP_SUBTREE_ONLY)) {
269                 _cleanup_free_ char *prefix = NULL;
270
271                 prefix = indent(0, flags);
272                 if (!prefix)
273                         return log_oom();
274
275                 fprintf(f, "%s};\n\n", prefix);
276         }
277
278         return 0;
279 }
280
281 static void dump_capabilities(
282                 sd_bus_creds *c,
283                 FILE *f,
284                 const char *name,
285                 bool terse,
286                 int (*has)(sd_bus_creds *c, int capability)) {
287
288         unsigned long i, last_cap;
289         unsigned n = 0;
290         int r;
291
292         assert(c);
293         assert(f);
294         assert(name);
295         assert(has);
296
297         i = 0;
298         r = has(c, i);
299         if (r < 0)
300                 return;
301
302         fprintf(f, "%s%s=%s", terse ? "  " : "", name, terse ? "" : ansi_highlight());
303         last_cap = cap_last_cap();
304
305         for (;;) {
306                 if (r > 0) {
307
308                         if (n > 0)
309                                 fputc(' ', f);
310                         if (n % 4 == 3)
311                                 fprintf(f, terse ? "\n          " : "\n        ");
312
313                         fprintf(f, "%s", strna(capability_to_name(i)));
314                         n++;
315                 }
316
317                 i++;
318
319                 if (i > last_cap)
320                         break;
321
322                 r = has(c, i);
323         }
324
325         fputs("\n", f);
326
327         if (!terse)
328                 fputs(ansi_highlight_off(), f);
329 }
330
331 int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
332         bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
333         const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
334         uid_t owner, audit_loginuid;
335         uint32_t audit_sessionid;
336         char **cmdline = NULL, **well_known = NULL;
337         const char *prefix, *color, *suffix;
338         int r;
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
364         if (terse && ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID))))
365                 fputs("\n", f);
366
367         if (c->mask & SD_BUS_CREDS_UID)
368                 fprintf(f, "%sUID=%s"UID_FMT"%s", prefix, color, c->uid, suffix);
369         if (c->mask & SD_BUS_CREDS_EUID)
370                 fprintf(f, "%sEUID=%s"UID_FMT"%s", prefix, color, c->euid, suffix);
371         if (c->mask & SD_BUS_CREDS_SUID)
372                 fprintf(f, "%sSUID=%s"UID_FMT"%s", prefix, color, c->suid, suffix);
373         if (c->mask & SD_BUS_CREDS_FSUID)
374                 fprintf(f, "%sFSUID=%s"UID_FMT"%s", prefix, color, c->fsuid, suffix);
375         r = sd_bus_creds_get_owner_uid(c, &owner);
376         if (r >= 0)
377                 fprintf(f, "%sOwnerUID=%s"UID_FMT"%s", prefix, color, owner, suffix);
378         if (c->mask & SD_BUS_CREDS_GID)
379                 fprintf(f, "%sGID=%s"GID_FMT"%s", prefix, color, c->gid, suffix);
380         if (c->mask & SD_BUS_CREDS_EGID)
381                 fprintf(f, "%sEGID=%s"GID_FMT"%s", prefix, color, c->egid, suffix);
382         if (c->mask & SD_BUS_CREDS_SGID)
383                 fprintf(f, "%sSGID=%s"GID_FMT"%s", prefix, color, c->sgid, suffix);
384         if (c->mask & SD_BUS_CREDS_FSGID)
385                 fprintf(f, "%sFSGID=%s"GID_FMT"%s", prefix, color, c->fsgid, suffix);
386
387         if (c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
388                 unsigned i;
389
390                 fprintf(f, "%sSupplementaryGIDs=%s", prefix, color);
391                 for (i = 0; i < c->n_supplementary_gids; i++)
392                         fprintf(f, "%s" GID_FMT, i > 0 ? " " : "", c->supplementary_gids[i]);
393                 fprintf(f, "%s", suffix);
394         }
395
396         if (terse && ((c->mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
397                                   SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
398                                   SD_BUS_CREDS_SUPPLEMENTARY_GIDS)) || r >= 0))
399                 fputs("\n", f);
400
401         if (c->mask & SD_BUS_CREDS_COMM)
402                 fprintf(f, "%sComm=%s%s%s", prefix, color, c->comm, suffix);
403         if (c->mask & SD_BUS_CREDS_TID_COMM)
404                 fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix);
405         if (c->mask & SD_BUS_CREDS_EXE)
406                 fprintf(f, "%sExe=%s%s%s", prefix, color, c->exe, suffix);
407
408         if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)))
409                 fputs("\n", f);
410
411         if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
412                 char **i;
413
414                 fprintf(f, "%sCommandLine=%s", prefix, color);
415                 STRV_FOREACH(i, cmdline) {
416                         if (i != cmdline)
417                                 fputc(' ', f);
418
419                         fputs(*i, f);
420                 }
421
422                 fprintf(f, "%s", suffix);
423         }
424
425         if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
426                 fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
427         if (c->mask & SD_BUS_CREDS_DESCRIPTION)
428                 fprintf(f, "%sDescription=%s%s%s", prefix, color, c->description, suffix);
429
430         if (terse && (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION)))
431                 fputs("\n", f);
432
433         if (c->mask & SD_BUS_CREDS_CGROUP)
434                 fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
435         (void) sd_bus_creds_get_unit(c, &u);
436         if (u)
437                 fprintf(f, "%sUnit=%s%s%s", prefix, color, u, suffix);
438         (void) sd_bus_creds_get_user_unit(c, &uu);
439         if (uu)
440                 fprintf(f, "%sUserUnit=%s%s%s", prefix, color, uu, suffix);
441         (void) sd_bus_creds_get_slice(c, &sl);
442         if (sl)
443                 fprintf(f, "%sSlice=%s%s%s", prefix, color, sl, suffix);
444         (void) sd_bus_creds_get_session(c, &s);
445         if (s)
446                 fprintf(f, "%sSession=%s%s%s", prefix, color, s, suffix);
447
448         if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s))
449                 fputs("\n", f);
450
451         if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
452                 audit_loginuid_is_set = true;
453                 fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
454         }
455         if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
456                 audit_sessionid_is_set = true;
457                 fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
458         }
459
460         if (terse && (audit_loginuid_is_set || audit_sessionid_is_set))
461                 fputs("\n", f);
462
463         if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
464                 fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix);
465
466         if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
467                 char **i;
468
469                 fprintf(f, "%sWellKnownNames=%s", prefix, color);
470                 STRV_FOREACH(i, well_known) {
471                         if (i != well_known)
472                                 fputc(' ', f);
473
474                         fputs(*i, f);
475                 }
476
477                 fprintf(f, "%s", suffix);
478         }
479
480         if (terse && (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known))
481                 fputc('\n', f);
482
483         dump_capabilities(c, f, "EffectiveCapabilities", terse, sd_bus_creds_has_effective_cap);
484         dump_capabilities(c, f, "PermittedCapabilities", terse, sd_bus_creds_has_permitted_cap);
485         dump_capabilities(c, f, "InheritableCapabilities", terse, sd_bus_creds_has_inheritable_cap);
486         dump_capabilities(c, f, "BoundingCapabilities", terse, sd_bus_creds_has_bounding_cap);
487
488         return 0;
489 }
490
491 /*
492  * For details about the file format, see:
493  *
494  * http://wiki.wireshark.org/Development/LibpcapFileFormat
495  */
496
497 typedef struct _packed_ pcap_hdr_s {
498         uint32_t magic_number;   /* magic number */
499         uint16_t version_major;  /* major version number */
500         uint16_t version_minor;  /* minor version number */
501         int32_t  thiszone;       /* GMT to local correction */
502         uint32_t sigfigs;        /* accuracy of timestamps */
503         uint32_t snaplen;        /* max length of captured packets, in octets */
504         uint32_t network;        /* data link type */
505 } pcap_hdr_t ;
506
507 typedef struct  _packed_ pcaprec_hdr_s {
508         uint32_t ts_sec;         /* timestamp seconds */
509         uint32_t ts_usec;        /* timestamp microseconds */
510         uint32_t incl_len;       /* number of octets of packet saved in file */
511         uint32_t orig_len;       /* actual length of packet */
512 } pcaprec_hdr_t;
513
514 int bus_pcap_header(size_t snaplen, FILE *f) {
515
516         pcap_hdr_t hdr = {
517                 .magic_number = 0xa1b2c3d4U,
518                 .version_major = 2,
519                 .version_minor = 4,
520                 .thiszone = 0, /* UTC */
521                 .sigfigs = 0,
522                 .network = 231, /* D-Bus */
523         };
524
525         if (!f)
526                 f = stdout;
527
528         assert(snaplen > 0);
529         assert((size_t) (uint32_t) snaplen == snaplen);
530
531         hdr.snaplen = (uint32_t) snaplen;
532
533         fwrite(&hdr, 1, sizeof(hdr), f);
534         fflush(f);
535
536         return 0;
537 }
538
539 int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
540         struct bus_body_part *part;
541         pcaprec_hdr_t hdr = {};
542         struct timeval tv;
543         unsigned i;
544         size_t w;
545
546         if (!f)
547                 f = stdout;
548
549         assert(m);
550         assert(snaplen > 0);
551         assert((size_t) (uint32_t) snaplen == snaplen);
552
553         if (m->realtime != 0)
554                 timeval_store(&tv, m->realtime);
555         else
556                 assert_se(gettimeofday(&tv, NULL) >= 0);
557
558         hdr.ts_sec = tv.tv_sec;
559         hdr.ts_usec = tv.tv_usec;
560         hdr.orig_len = BUS_MESSAGE_SIZE(m);
561         hdr.incl_len = MIN(hdr.orig_len, snaplen);
562
563         /* write the pcap header */
564         fwrite(&hdr, 1, sizeof(hdr), f);
565
566         /* write the dbus header */
567         w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
568         fwrite(m->header, 1, w, f);
569         snaplen -= w;
570
571         /* write the dbus body */
572         MESSAGE_FOREACH_PART(part, i, m) {
573                 if (snaplen <= 0)
574                         break;
575
576                 w = MIN(part->size, snaplen);
577                 fwrite(part->data, 1, w, f);
578                 snaplen -= w;
579         }
580
581         fflush(f);
582
583         return 0;
584 }