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