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