LCOV - code coverage report
Current view: top level - journal - journald-audit.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 245 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 10 0.0 %

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

Generated by: LCOV version 1.11