chiark / gitweb /
9165dd7d5a71ac3dee9bb13ec2024c358d28d54e
[elogind.git] / src / libelogind / 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         bool audit_sessionid_is_set = false, audit_loginuid_is_set = false;
335         const char *u = NULL, *uu = NULL, *s = NULL, *sl = NULL;
336         uid_t owner, audit_loginuid;
337         uint32_t audit_sessionid;
338         char **cmdline = NULL, **well_known = NULL;
339         const char *prefix, *color, *suffix;
340         int r;
341
342         assert(c);
343
344         if (!f)
345                 f = stdout;
346
347         if (terse) {
348                 prefix = "  ";
349                 suffix = "";
350                 color = "";
351         } else {
352                 const char *off;
353
354                 prefix = "";
355                 color = ansi_highlight();
356
357                 off = ansi_highlight_off();
358                 suffix = strjoina(off, "\n");
359         }
360
361         if (c->mask & SD_BUS_CREDS_PID)
362                 fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
363         if (c->mask & SD_BUS_CREDS_TID)
364                 fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
365
366         if (terse && ((c->mask & (SD_BUS_CREDS_PID|SD_BUS_CREDS_TID))))
367                 fputs("\n", f);
368
369         if (c->mask & SD_BUS_CREDS_UID)
370                 fprintf(f, "%sUID=%s"UID_FMT"%s", prefix, color, c->uid, suffix);
371         if (c->mask & SD_BUS_CREDS_EUID)
372                 fprintf(f, "%sEUID=%s"UID_FMT"%s", prefix, color, c->euid, suffix);
373         if (c->mask & SD_BUS_CREDS_SUID)
374                 fprintf(f, "%sSUID=%s"UID_FMT"%s", prefix, color, c->suid, suffix);
375         if (c->mask & SD_BUS_CREDS_FSUID)
376                 fprintf(f, "%sFSUID=%s"UID_FMT"%s", prefix, color, c->fsuid, suffix);
377         r = sd_bus_creds_get_owner_uid(c, &owner);
378         if (r >= 0)
379                 fprintf(f, "%sOwnerUID=%s"UID_FMT"%s", prefix, color, owner, suffix);
380         if (c->mask & SD_BUS_CREDS_GID)
381                 fprintf(f, "%sGID=%s"GID_FMT"%s", prefix, color, c->gid, suffix);
382         if (c->mask & SD_BUS_CREDS_EGID)
383                 fprintf(f, "%sEGID=%s"GID_FMT"%s", prefix, color, c->egid, suffix);
384         if (c->mask & SD_BUS_CREDS_SGID)
385                 fprintf(f, "%sSGID=%s"GID_FMT"%s", prefix, color, c->sgid, suffix);
386         if (c->mask & SD_BUS_CREDS_FSGID)
387                 fprintf(f, "%sFSGID=%s"GID_FMT"%s", prefix, color, c->fsgid, suffix);
388
389         if (c->mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS) {
390                 unsigned i;
391
392                 fprintf(f, "%sSupplementaryGIDs=%s", prefix, color);
393                 for (i = 0; i < c->n_supplementary_gids; i++)
394                         fprintf(f, "%s" GID_FMT, i > 0 ? " " : "", c->supplementary_gids[i]);
395                 fprintf(f, "%s", suffix);
396         }
397
398         if (terse && ((c->mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
399                                   SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
400                                   SD_BUS_CREDS_SUPPLEMENTARY_GIDS)) || r >= 0))
401                 fputs("\n", f);
402
403         if (c->mask & SD_BUS_CREDS_COMM)
404                 fprintf(f, "%sComm=%s%s%s", prefix, color, c->comm, suffix);
405         if (c->mask & SD_BUS_CREDS_TID_COMM)
406                 fprintf(f, "%sTIDComm=%s%s%s", prefix, color, c->tid_comm, suffix);
407         if (c->mask & SD_BUS_CREDS_EXE)
408                 fprintf(f, "%sExe=%s%s%s", prefix, color, c->exe, suffix);
409
410         if (terse && (c->mask & (SD_BUS_CREDS_EXE|SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)))
411                 fputs("\n", f);
412
413         if (sd_bus_creds_get_cmdline(c, &cmdline) >= 0) {
414                 char **i;
415
416                 fprintf(f, "%sCommandLine=%s", prefix, color);
417                 STRV_FOREACH(i, cmdline) {
418                         if (i != cmdline)
419                                 fputc(' ', f);
420
421                         fputs(*i, f);
422                 }
423
424                 fprintf(f, "%s", suffix);
425         }
426
427         if (c->mask & SD_BUS_CREDS_SELINUX_CONTEXT)
428                 fprintf(f, "%sLabel=%s%s%s", prefix, color, c->label, suffix);
429         if (c->mask & SD_BUS_CREDS_DESCRIPTION)
430                 fprintf(f, "%sDescription=%s%s%s", prefix, color, c->description, suffix);
431
432         if (terse && (c->mask & (SD_BUS_CREDS_SELINUX_CONTEXT|SD_BUS_CREDS_DESCRIPTION)))
433                 fputs("\n", f);
434
435         if (c->mask & SD_BUS_CREDS_CGROUP)
436                 fprintf(f, "%sCGroup=%s%s%s", prefix, color, c->cgroup, suffix);
437         (void) sd_bus_creds_get_unit(c, &u);
438         if (u)
439                 fprintf(f, "%sUnit=%s%s%s", prefix, color, u, suffix);
440         (void) sd_bus_creds_get_user_unit(c, &uu);
441         if (uu)
442                 fprintf(f, "%sUserUnit=%s%s%s", prefix, color, uu, suffix);
443         (void) sd_bus_creds_get_slice(c, &sl);
444         if (sl)
445                 fprintf(f, "%sSlice=%s%s%s", prefix, color, sl, suffix);
446         (void) sd_bus_creds_get_session(c, &s);
447         if (s)
448                 fprintf(f, "%sSession=%s%s%s", prefix, color, s, suffix);
449
450         if (terse && ((c->mask & SD_BUS_CREDS_CGROUP) || u || uu || sl || s))
451                 fputs("\n", f);
452
453         if (sd_bus_creds_get_audit_login_uid(c, &audit_loginuid) >= 0) {
454                 audit_loginuid_is_set = true;
455                 fprintf(f, "%sAuditLoginUID=%s"UID_FMT"%s", prefix, color, audit_loginuid, suffix);
456         }
457         if (sd_bus_creds_get_audit_session_id(c, &audit_sessionid) >= 0) {
458                 audit_sessionid_is_set = true;
459                 fprintf(f, "%sAuditSessionID=%s%"PRIu32"%s", prefix, color, audit_sessionid, suffix);
460         }
461
462         if (terse && (audit_loginuid_is_set || audit_sessionid_is_set))
463                 fputs("\n", f);
464
465         if (c->mask & SD_BUS_CREDS_UNIQUE_NAME)
466                 fprintf(f, "%sUniqueName=%s%s%s", prefix, color, c->unique_name, suffix);
467
468         if (sd_bus_creds_get_well_known_names(c, &well_known) >= 0) {
469                 char **i;
470
471                 fprintf(f, "%sWellKnownNames=%s", prefix, color);
472                 STRV_FOREACH(i, well_known) {
473                         if (i != well_known)
474                                 fputc(' ', f);
475
476                         fputs(*i, f);
477                 }
478
479                 fprintf(f, "%s", suffix);
480         }
481
482         if (terse && (c->mask & SD_BUS_CREDS_UNIQUE_NAME || well_known))
483                 fputc('\n', f);
484
485         dump_capabilities(c, f, "EffectiveCapabilities", terse, sd_bus_creds_has_effective_cap);
486         dump_capabilities(c, f, "PermittedCapabilities", terse, sd_bus_creds_has_permitted_cap);
487         dump_capabilities(c, f, "InheritableCapabilities", terse, sd_bus_creds_has_inheritable_cap);
488         dump_capabilities(c, f, "BoundingCapabilities", terse, sd_bus_creds_has_bounding_cap);
489
490         return 0;
491 }
492
493 /*
494  * For details about the file format, see:
495  *
496  * http://wiki.wireshark.org/Development/LibpcapFileFormat
497  */
498
499 typedef struct _packed_ pcap_hdr_s {
500         uint32_t magic_number;   /* magic number */
501         uint16_t version_major;  /* major version number */
502         uint16_t version_minor;  /* minor version number */
503         int32_t  thiszone;       /* GMT to local correction */
504         uint32_t sigfigs;        /* accuracy of timestamps */
505         uint32_t snaplen;        /* max length of captured packets, in octets */
506         uint32_t network;        /* data link type */
507 } pcap_hdr_t ;
508
509 typedef struct  _packed_ pcaprec_hdr_s {
510         uint32_t ts_sec;         /* timestamp seconds */
511         uint32_t ts_usec;        /* timestamp microseconds */
512         uint32_t incl_len;       /* number of octets of packet saved in file */
513         uint32_t orig_len;       /* actual length of packet */
514 } pcaprec_hdr_t;
515
516 int bus_pcap_header(size_t snaplen, FILE *f) {
517
518         pcap_hdr_t hdr = {
519                 .magic_number = 0xa1b2c3d4U,
520                 .version_major = 2,
521                 .version_minor = 4,
522                 .thiszone = 0, /* UTC */
523                 .sigfigs = 0,
524                 .network = 231, /* D-Bus */
525         };
526
527         if (!f)
528                 f = stdout;
529
530         assert(snaplen > 0);
531         assert((size_t) (uint32_t) snaplen == snaplen);
532
533         hdr.snaplen = (uint32_t) snaplen;
534
535         fwrite(&hdr, 1, sizeof(hdr), f);
536         fflush(f);
537
538         return 0;
539 }
540
541 int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
542         struct bus_body_part *part;
543         pcaprec_hdr_t hdr = {};
544         struct timeval tv;
545         unsigned i;
546         size_t w;
547
548         if (!f)
549                 f = stdout;
550
551         assert(m);
552         assert(snaplen > 0);
553         assert((size_t) (uint32_t) snaplen == snaplen);
554
555         if (m->realtime != 0)
556                 timeval_store(&tv, m->realtime);
557         else
558                 assert_se(gettimeofday(&tv, NULL) >= 0);
559
560         hdr.ts_sec = tv.tv_sec;
561         hdr.ts_usec = tv.tv_usec;
562         hdr.orig_len = BUS_MESSAGE_SIZE(m);
563         hdr.incl_len = MIN(hdr.orig_len, snaplen);
564
565         /* write the pcap header */
566         fwrite(&hdr, 1, sizeof(hdr), f);
567
568         /* write the dbus header */
569         w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
570         fwrite(m->header, 1, w, f);
571         snaplen -= w;
572
573         /* write the dbus body */
574         MESSAGE_FOREACH_PART(part, i, m) {
575                 if (snaplen <= 0)
576                         break;
577
578                 w = MIN(part->size, snaplen);
579                 fwrite(part->data, 1, w, f);
580                 snaplen -= w;
581         }
582
583         fflush(f);
584
585         return 0;
586 }