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