chiark / gitweb /
util: when using basename() for creating temporary files, verify the resulting name...
[elogind.git] / src / journal / journald-audit.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 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 "missing.h"
23 #include "journald-audit.h"
24
25 typedef struct MapField {
26         const char *audit_field;
27         const char *journal_field;
28         int (*map)(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov);
29 } MapField;
30
31 static int map_simple_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
32         _cleanup_free_ char *c = NULL;
33         size_t l = 0, allocated = 0;
34         const char *e;
35
36         assert(field);
37         assert(p);
38         assert(iov);
39         assert(n_iov);
40
41         l = strlen(field);
42         allocated = l + 1;
43         c = malloc(allocated);
44         if (!c)
45                 return -ENOMEM;
46
47         memcpy(c, field, l);
48         for (e = *p; *e != ' ' && *e != 0; e++) {
49                 if (!GREEDY_REALLOC(c, allocated, l+2))
50                         return -ENOMEM;
51
52                 c[l++] = *e;
53         }
54
55         c[l] = 0;
56
57         if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
58                 return -ENOMEM;
59
60         (*iov)[*n_iov].iov_base = c;
61         (*iov)[*n_iov].iov_len = l;
62         (*n_iov) ++;
63
64         *p = e;
65         c = NULL;
66
67         return 1;
68 }
69
70 static int map_string_field_internal(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov, bool filter_printable) {
71         _cleanup_free_ char *c = NULL;
72         const char *s, *e;
73         size_t l;
74
75         assert(field);
76         assert(p);
77         assert(iov);
78         assert(n_iov);
79
80         /* The kernel formats string fields in one of two formats. */
81
82         if (**p == '"') {
83                 /* Normal quoted syntax */
84                 s = *p + 1;
85                 e = strchr(s, '"');
86                 if (!e)
87                         return 0;
88
89                 l = strlen(field) + (e - s);
90                 c = malloc(l+1);
91                 if (!c)
92                         return -ENOMEM;
93
94                 *((char*) mempcpy(stpcpy(c, field), s, e - s)) = 0;
95
96                 e += 1;
97
98         } else if (unhexchar(**p) >= 0) {
99                 /* Hexadecimal escaping */
100                 size_t allocated = 0;
101
102                 l = strlen(field);
103                 allocated = l + 2;
104                 c = malloc(allocated);
105                 if (!c)
106                         return -ENOMEM;
107
108                 memcpy(c, field, l);
109                 for (e = *p; *e != ' ' && *e != 0; e += 2) {
110                         int a, b;
111                         uint8_t x;
112
113                         a = unhexchar(e[0]);
114                         if (a < 0)
115                                 return 0;
116
117                         b = unhexchar(e[1]);
118                         if (b < 0)
119                                 return 0;
120
121                         x = ((uint8_t) a << 4 | (uint8_t) b);
122
123                         if (filter_printable && x < (uint8_t) ' ')
124                                 x = (uint8_t) ' ';
125
126                         if (!GREEDY_REALLOC(c, allocated, l+2))
127                                 return -ENOMEM;
128
129                         c[l++] = (char) x;
130                 }
131
132                 c[l] = 0;
133         } else
134                 return 0;
135
136         if (!GREEDY_REALLOC(*iov, *n_iov_allocated, *n_iov + 1))
137                 return -ENOMEM;
138
139         (*iov)[*n_iov].iov_base = c;
140         (*iov)[*n_iov].iov_len = l;
141         (*n_iov) ++;
142
143         *p = e;
144         c = NULL;
145
146         return 1;
147 }
148
149 static int map_string_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
150         return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, false);
151 }
152
153 static int map_string_field_printable(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
154         return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, true);
155 }
156
157 static int map_generic_field(const char *prefix, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) {
158         const char *e, *f;
159         char *c, *t;
160         int r;
161
162         /* Implements fallback mappings for all fields we don't know */
163
164         for (e = *p; e < *p + 16; e++) {
165
166                 if (*e == 0 || *e == ' ')
167                         return 0;
168
169                 if (*e == '=')
170                         break;
171
172                 if (!((*e >= 'a' && *e <= 'z') ||
173                       (*e >= 'A' && *e <= 'Z') ||
174                       (*e >= '0' && *e <= '9') ||
175                       *e == '_' || *e == '-'))
176                         return 0;
177         }
178
179         if (e <= *p || e >= *p + 16)
180                 return 0;
181
182         c = alloca(strlen(prefix) + (e - *p) + 2);
183
184         t = stpcpy(c, prefix);
185         for (f = *p; f < e; f++) {
186                 char x;
187
188                 if (*f >= 'a' && *f <= 'z')
189                         x = (*f - 'a') + 'A'; /* uppercase */
190                 else if (*f == '-')
191                         x = '_'; /* dashes â†’ underscores */
192                 else
193                         x = *f;
194
195                 *(t++) = x;
196         }
197         strcpy(t, "=");
198
199         e ++;
200
201         r = map_simple_field(c, &e, iov, n_iov_allocated, n_iov);
202         if (r < 0)
203                 return r;
204
205         *p = e;
206         return r;
207 }
208
209 /* Kernel fields are those occuring in the audit string before
210  * msg='. All of these fields are trusted, hence carry the "_" prefix.
211  * We try to translate the fields we know into our native names. The
212  * other's are generically mapped to _AUDIT_FIELD_XYZ= */
213 static const MapField map_fields_kernel[] = {
214
215         /* First, we map certain well-known audit fields into native
216          * well-known fields */
217         { "pid=",       "_PID=",                   map_simple_field },
218         { "ppid=",      "_PPID=",                  map_simple_field },
219         { "uid=",       "_UID=",                   map_simple_field },
220         { "euid=",      "_EUID=",                  map_simple_field },
221         { "fsuid=",     "_FSUID=",                 map_simple_field },
222         { "gid=",       "_GID=",                   map_simple_field },
223         { "egid=",      "_EGID=",                  map_simple_field },
224         { "fsgid=",     "_FSGID=",                 map_simple_field },
225         { "tty=",       "_TTY=",                   map_simple_field },
226         { "ses=",       "_AUDIT_SESSION=",         map_simple_field },
227         { "auid=",      "_AUDIT_LOGINUID=",        map_simple_field },
228         { "subj=",      "_SELINUX_CONTEXT=",       map_simple_field },
229         { "comm=",      "_COMM=",                  map_string_field },
230         { "exe=",       "_EXE=",                   map_string_field },
231         { "proctitle=", "_CMDLINE=",               map_string_field_printable },
232
233         /* Some fields don't map to native well-known fields. However,
234          * we know that they are string fields, hence let's undo
235          * string field escaping for them, though we stick to the
236          * generic field names. */
237         { "path=",      "_AUDIT_FIELD_PATH=",      map_string_field },
238         { "dev=",       "_AUDIT_FIELD_DEV=",       map_string_field },
239         { "name=",      "_AUDIT_FIELD_NAME=",      map_string_field },
240         {}
241 };
242
243 /* Userspace fields are thos occuring in the audit string after
244  * msg='. All of these fields are untrusted, hence carry no "_"
245  * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */
246 static const MapField map_fields_userspace[] = {
247         { "cwd=",       "AUDIT_FIELD_CWD=",  map_string_field },
248         { "cmd=",       "AUDIT_FIELD_CMD=",  map_string_field },
249         { "acct=",      "AUDIT_FIELD_ACCT=", map_string_field },
250         { "exe=",       "AUDIT_FIELD_EXE=",  map_string_field },
251         { "comm=",      "AUDIT_FIELD_COMM=", map_string_field },
252         {}
253 };
254
255 static int map_all_fields(
256                 const char *p,
257                 const MapField map_fields[],
258                 const char *prefix,
259                 bool handle_msg,
260                 struct iovec **iov,
261                 size_t *n_iov_allocated,
262                 unsigned *n_iov) {
263
264         int r;
265
266         assert(p);
267         assert(iov);
268         assert(n_iov_allocated);
269         assert(n_iov);
270
271         for (;;) {
272                 bool mapped = false;
273                 const MapField *m;
274                 const char *v;
275
276                 p += strspn(p, WHITESPACE);
277
278                 if (*p == 0)
279                         return 0;
280
281                 if (handle_msg) {
282                         v = startswith(p, "msg='");
283                         if (v) {
284                                 const char *e;
285                                 char *c;
286
287                                 /* Userspace message. It's enclosed in
288                                    simple quotation marks, is not
289                                    escaped, but the last field in the
290                                    line, hence let's remove the
291                                    quotation mark, and apply the
292                                    userspace mapping instead of the
293                                    kernel mapping. */
294
295                                 e = endswith(v, "'");
296                                 if (!e)
297                                         return 0; /* don't continue splitting up if the final quotation mark is missing */
298
299                                 c = strndupa(v, e - v);
300                                 return map_all_fields(c, map_fields_userspace, "AUDIT_FIELD_", false, iov, n_iov_allocated, n_iov);
301                         }
302                 }
303
304                 /* Try to map the kernel fields to our own names */
305                 for (m = map_fields; m->audit_field; m++) {
306                         v = startswith(p, m->audit_field);
307                         if (!v)
308                                 continue;
309
310                         r = m->map(m->journal_field, &v, iov, n_iov_allocated, n_iov);
311                         if (r < 0)
312                                 return log_debug_errno(r, "Failed to parse audit array: %m");
313
314                         if (r > 0) {
315                                 mapped = true;
316                                 p = v;
317                                 break;
318                         }
319                 }
320
321                 if (!mapped) {
322                         r = map_generic_field(prefix, &p, iov, n_iov_allocated, n_iov);
323                         if (r < 0)
324                                 return log_debug_errno(r, "Failed to parse audit array: %m");
325
326                         if (r == 0) {
327                                 /* Couldn't process as generic field, let's just skip over it */
328                                 p += strcspn(p, WHITESPACE);
329                         }
330                 }
331         }
332 }
333
334 static void process_audit_string(Server *s, int type, const char *data, size_t size) {
335         _cleanup_free_ struct iovec *iov = NULL;
336         size_t n_iov_allocated = 0;
337         unsigned n_iov = 0, k;
338         uint64_t seconds, msec, id;
339         const char *p;
340         unsigned z;
341         char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)],
342              type_field[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)],
343              source_time_field[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)];
344         char *m;
345
346         assert(s);
347
348         if (size <= 0)
349                 return;
350
351         if (!data)
352                 return;
353
354         /* Note that the input buffer is NUL terminated, but let's
355          * check whether there is a spurious NUL byte */
356         if (memchr(data, 0, size))
357                 return;
358
359         p = startswith(data, "audit");
360         if (!p)
361                 return;
362
363         if (sscanf(p, "(%" PRIi64 ".%" PRIi64 ":%" PRIi64 "):%n",
364                    &seconds,
365                    &msec,
366                    &id,
367                    &k) != 3)
368                 return;
369
370         p += k;
371         p += strspn(p, WHITESPACE);
372
373         if (isempty(p))
374                 return;
375
376         n_iov_allocated = N_IOVEC_META_FIELDS + 5;
377         iov = new(struct iovec, n_iov_allocated);
378         if (!iov) {
379                 log_oom();
380                 return;
381         }
382
383         IOVEC_SET_STRING(iov[n_iov++], "_TRANSPORT=audit");
384
385         sprintf(source_time_field, "_SOURCE_REALTIME_TIMESTAMP=%" PRIu64,
386                 (usec_t) seconds * USEC_PER_SEC + (usec_t) msec * USEC_PER_MSEC);
387         IOVEC_SET_STRING(iov[n_iov++], source_time_field);
388
389         sprintf(type_field, "_AUDIT_TYPE=%i", type);
390         IOVEC_SET_STRING(iov[n_iov++], type_field);
391
392         sprintf(id_field, "_AUDIT_ID=%" PRIu64, id);
393         IOVEC_SET_STRING(iov[n_iov++], id_field);
394
395         m = alloca(strlen("MESSAGE=<audit-") + DECIMAL_STR_MAX(int) + strlen("> ") + strlen(p) + 1);
396         sprintf(m, "MESSAGE=<audit-%i> %s", type, p);
397         IOVEC_SET_STRING(iov[n_iov++], m);
398
399         z = n_iov;
400
401         map_all_fields(p, map_fields_kernel, "_AUDIT_FIELD_", true, &iov, &n_iov_allocated, &n_iov);
402
403         if (!GREEDY_REALLOC(iov, n_iov_allocated, n_iov + N_IOVEC_META_FIELDS)) {
404                 log_oom();
405                 goto finish;
406         }
407
408         server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, NULL, NULL, 0, NULL, LOG_NOTICE, 0);
409
410 finish:
411         /* free() all entries that map_all_fields() added. All others
412          * are allocated on the stack or are constant. */
413
414         for (; z < n_iov; z++)
415                 free(iov[z].iov_base);
416 }
417
418 void server_process_audit_message(
419                 Server *s,
420                 const void *buffer,
421                 size_t buffer_size,
422                 const struct ucred *ucred,
423                 const union sockaddr_union *sa,
424                 socklen_t salen) {
425
426         const struct nlmsghdr *nl = buffer;
427
428         assert(s);
429
430         if (buffer_size < ALIGN(sizeof(struct nlmsghdr)))
431                 return;
432
433         assert(buffer);
434
435         /* Filter out fake data */
436         if (!sa ||
437             salen != sizeof(struct sockaddr_nl) ||
438             sa->nl.nl_family != AF_NETLINK ||
439             sa->nl.nl_pid != 0) {
440                 log_debug("Audit netlink message from invalid sender.");
441                 return;
442         }
443
444         if (!ucred || ucred->pid != 0) {
445                 log_debug("Audit netlink message with invalid credentials.");
446                 return;
447         }
448
449         if (!NLMSG_OK(nl, buffer_size)) {
450                 log_error("Audit netlink message truncated.");
451                 return;
452         }
453
454         /* Ignore special Netlink messages */
455         if (IN_SET(nl->nlmsg_type, NLMSG_NOOP, NLMSG_ERROR))
456                 return;
457
458         /* Below AUDIT_FIRST_USER_MSG theer are only control messages, let's ignore those */
459         if (nl->nlmsg_type < AUDIT_FIRST_USER_MSG)
460                 return;
461
462         process_audit_string(s, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr)));
463 }
464
465 static int enable_audit(int fd, bool b) {
466         struct {
467                 union {
468                         struct nlmsghdr header;
469                         uint8_t header_space[NLMSG_HDRLEN];
470                 };
471                 struct audit_status body;
472         } _packed_ request = {
473                 .header.nlmsg_len = NLMSG_LENGTH(sizeof(struct audit_status)),
474                 .header.nlmsg_type = AUDIT_SET,
475                 .header.nlmsg_flags = NLM_F_REQUEST,
476                 .header.nlmsg_seq = 1,
477                 .header.nlmsg_pid = 0,
478                 .body.mask = AUDIT_STATUS_ENABLED,
479                 .body.enabled = b,
480         };
481         union sockaddr_union sa = {
482                 .nl.nl_family = AF_NETLINK,
483                 .nl.nl_pid = 0,
484         };
485         struct iovec iovec = {
486                 .iov_base = &request,
487                 .iov_len = NLMSG_LENGTH(sizeof(struct audit_status)),
488         };
489         struct msghdr mh = {
490                 .msg_iov = &iovec,
491                 .msg_iovlen = 1,
492                 .msg_name = &sa.sa,
493                 .msg_namelen = sizeof(sa.nl),
494         };
495
496         ssize_t n;
497
498         n = sendmsg(fd, &mh, MSG_NOSIGNAL);
499         if (n < 0)
500                 return -errno;
501         if (n != NLMSG_LENGTH(sizeof(struct audit_status)))
502                 return -EIO;
503
504         /* We don't wait for the result here, we can't do anything
505          * about it anyway */
506
507         return 0;
508 }
509
510 int server_open_audit(Server *s) {
511         static const int one = 1;
512         int r;
513
514         if (s->audit_fd < 0) {
515                 static const union sockaddr_union sa = {
516                         .nl.nl_family = AF_NETLINK,
517                         .nl.nl_pid    = 0,
518                         .nl.nl_groups = AUDIT_NLGRP_READLOG,
519                 };
520
521                 s->audit_fd = socket(AF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT);
522                 if (s->audit_fd < 0) {
523                         if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT)
524                                 log_debug("Audit not supported in the kernel.");
525                         else
526                                 log_warning_errno(errno, "Failed to create audit socket, ignoring: %m");
527
528                         return 0;
529                 }
530
531                 r = bind(s->audit_fd, &sa.sa, sizeof(sa.nl));
532                 if (r < 0)
533                         return log_error_errno(errno, "Failed to join audit multicast group: %m");
534         } else
535                 fd_nonblock(s->audit_fd, 1);
536
537         r = setsockopt(s->audit_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
538         if (r < 0)
539                 return log_error_errno(errno, "Failed to set SO_PASSCRED on audit socket: %m");
540
541         r = sd_event_add_io(s->event, &s->audit_event_source, s->audit_fd, EPOLLIN, process_datagram, s);
542         if (r < 0)
543                 return log_error_errno(r, "Failed to add audit fd to event loop: %m");
544
545         /* We are listening now, try to enable audit */
546         r = enable_audit(s->audit_fd, true);
547         if (r < 0)
548                 log_warning_errno(r, "Failed to issue audit enable call: %m");
549
550         return 0;
551 }