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