X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fjournal%2Fjournald-audit.c;h=20936f4bed7109f58d90acf53f551674e0042442;hp=0e1e8bd5d07ea6bb939552b2c56f3d0c6fba48a1;hb=f131770b1465fbf423881f16ba85523a05f846fe;hpb=4d9ced9956755901238fede6fc5a3d7e4e816aa6 diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index 0e1e8bd5d..20936f4be 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -67,7 +67,7 @@ static int map_simple_field(const char *field, const char **p, struct iovec **io return 1; } -static int map_string_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) { +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) { _cleanup_free_ char *c = NULL; const char *s, *e; size_t l; @@ -108,6 +108,7 @@ static int map_string_field(const char *field, const char **p, struct iovec **io memcpy(c, field, l); for (e = *p; *e != ' ' && *e != 0; e += 2) { int a, b; + uint8_t x; a = unhexchar(e[0]); if (a < 0) @@ -117,10 +118,15 @@ static int map_string_field(const char *field, const char **p, struct iovec **io if (b < 0) return 0; + x = ((uint8_t) a << 4 | (uint8_t) b); + + if (filter_printable && x < (uint8_t) ' ') + x = (uint8_t) ' '; + if (!GREEDY_REALLOC(c, allocated, l+2)) return -ENOMEM; - c[l++] = (char) ((uint8_t) a << 4 | (uint8_t) b); + c[l++] = (char) x; } c[l] = 0; @@ -140,6 +146,14 @@ static int map_string_field(const char *field, const char **p, struct iovec **io return 1; } +static int map_string_field(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) { + return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, false); +} + +static int map_string_field_printable(const char *field, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) { + return map_string_field_internal(field, p, iov, n_iov_allocated, n_iov, true); +} + static int map_generic_field(const char *prefix, const char **p, struct iovec **iov, size_t *n_iov_allocated, unsigned *n_iov) { const char *e, *f; char *c, *t; @@ -158,7 +172,7 @@ static int map_generic_field(const char *prefix, const char **p, struct iovec ** if (!((*e >= 'a' && *e <= 'z') || (*e >= 'A' && *e <= 'Z') || (*e >= '0' && *e <= '9') || - (*e == '_'))) + *e == '_' || *e == '-')) return 0; } @@ -168,8 +182,18 @@ static int map_generic_field(const char *prefix, const char **p, struct iovec ** c = alloca(strlen(prefix) + (e - *p) + 2); t = stpcpy(c, prefix); - for (f = *p; f < e; f++) - *(t++) = *f >= 'a' && *f <= 'z' ? ((*f - 'a') + 'A') : *f; + for (f = *p; f < e; f++) { + char x; + + if (*f >= 'a' && *f <= 'z') + x = (*f - 'a') + 'A'; /* uppercase */ + else if (*f == '-') + x = '_'; /* dashes → underscores */ + else + x = *f; + + *(t++) = x; + } strcpy(t, "="); e ++; @@ -182,7 +206,7 @@ static int map_generic_field(const char *prefix, const char **p, struct iovec ** return r; } -/* Kernel fields are those occuring in the audit string before +/* Kernel fields are those occurring in the audit string before * msg='. All of these fields are trusted, hence carry the "_" prefix. * We try to translate the fields we know into our native names. The * other's are generically mapped to _AUDIT_FIELD_XYZ= */ @@ -204,7 +228,7 @@ static const MapField map_fields_kernel[] = { { "subj=", "_SELINUX_CONTEXT=", map_simple_field }, { "comm=", "_COMM=", map_string_field }, { "exe=", "_EXE=", map_string_field }, - { "proctitle=", "_CMDLINE=", map_string_field }, + { "proctitle=", "_CMDLINE=", map_string_field_printable }, /* Some fields don't map to native well-known fields. However, * we know that they are string fields, hence let's undo @@ -216,7 +240,7 @@ static const MapField map_fields_kernel[] = { {} }; -/* Userspace fields are thos occuring in the audit string after +/* Userspace fields are those occurring in the audit string after * msg='. All of these fields are untrusted, hence carry no "_" * prefix. We map the fields we don't know to AUDIT_FIELD_XYZ= */ static const MapField map_fields_userspace[] = { @@ -284,10 +308,8 @@ static int map_all_fields( continue; r = m->map(m->journal_field, &v, iov, n_iov_allocated, n_iov); - if (r < 0) { - log_debug("Failed to parse audit array: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_debug_errno(r, "Failed to parse audit array: %m"); if (r > 0) { mapped = true; @@ -298,10 +320,8 @@ static int map_all_fields( if (!mapped) { r = map_generic_field(prefix, &p, iov, n_iov_allocated, n_iov); - if (r < 0) { - log_debug("Failed to parse audit array: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_debug_errno(r, "Failed to parse audit array: %m"); if (r == 0) { /* Couldn't process as generic field, let's just skip over it */ @@ -311,7 +331,7 @@ static int map_all_fields( } } -static void process_audit_string(Server *s, int type, const char *data, size_t size, const struct timeval *tv) { +static void process_audit_string(Server *s, int type, const char *data, size_t size) { _cleanup_free_ struct iovec *iov = NULL; size_t n_iov_allocated = 0; unsigned n_iov = 0, k; @@ -321,7 +341,7 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s char id_field[sizeof("_AUDIT_ID=") + DECIMAL_STR_MAX(uint64_t)], type_field[sizeof("_AUDIT_TYPE=") + DECIMAL_STR_MAX(int)], source_time_field[sizeof("_SOURCE_REALTIME_TIMESTAMP=") + DECIMAL_STR_MAX(usec_t)]; - const char *m; + char *m; assert(s); @@ -340,7 +360,7 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s if (!p) return; - if (sscanf(p, "(%" PRIi64 ".%" PRIi64 ":%" PRIi64 "): %n", + if (sscanf(p, "(%" PRIi64 ".%" PRIi64 ":%" PRIi64 "):%n", &seconds, &msec, &id, @@ -348,6 +368,10 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s return; p += k; + p += strspn(p, WHITESPACE); + + if (isempty(p)) + return; n_iov_allocated = N_IOVEC_META_FIELDS + 5; iov = new(struct iovec, n_iov_allocated); @@ -368,7 +392,8 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s sprintf(id_field, "_AUDIT_ID=%" PRIu64, id); IOVEC_SET_STRING(iov[n_iov++], id_field); - m = strappenda("MESSAGE=", data); + m = alloca(strlen("MESSAGE= ") + strlen(p) + 1); + sprintf(m, "MESSAGE= %s", type, p); IOVEC_SET_STRING(iov[n_iov++], m); z = n_iov; @@ -380,7 +405,7 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s goto finish; } - server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, tv, NULL, 0, NULL, LOG_NOTICE, 0); + server_dispatch_message(s, iov, n_iov, n_iov_allocated, NULL, NULL, NULL, 0, NULL, LOG_NOTICE, 0); finish: /* free() all entries that map_all_fields() added. All others @@ -395,7 +420,6 @@ void server_process_audit_message( const void *buffer, size_t buffer_size, const struct ucred *ucred, - const struct timeval *tv, const union sockaddr_union *sa, socklen_t salen) { @@ -435,7 +459,7 @@ void server_process_audit_message( if (nl->nlmsg_type < AUDIT_FIRST_USER_MSG) return; - process_audit_string(s, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr)), tv); + process_audit_string(s, nl->nlmsg_type, NLMSG_DATA(nl), nl->nlmsg_len - ALIGN(sizeof(struct nlmsghdr))); } static int enable_audit(int fd, bool b) { @@ -499,35 +523,29 @@ int server_open_audit(Server *s) { if (errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) log_debug("Audit not supported in the kernel."); else - log_warning("Failed to create audit socket, ignoring: %m"); + log_warning_errno(errno, "Failed to create audit socket, ignoring: %m"); return 0; } r = bind(s->audit_fd, &sa.sa, sizeof(sa.nl)); - if (r < 0) { - log_error("Failed to join audit multicast group: %m"); - return -errno; - } + if (r < 0) + return log_error_errno(errno, "Failed to join audit multicast group: %m"); } else fd_nonblock(s->audit_fd, 1); r = setsockopt(s->audit_fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)); - if (r < 0) { - log_error("Failed to set SO_PASSCRED on audit socket: %m"); - return -errno; - } + if (r < 0) + return log_error_errno(errno, "Failed to set SO_PASSCRED on audit socket: %m"); r = sd_event_add_io(s->event, &s->audit_event_source, s->audit_fd, EPOLLIN, process_datagram, s); - if (r < 0) { - log_error("Failed to add audit fd to event loop: %s", strerror(-r)); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to add audit fd to event loop: %m"); /* We are listening now, try to enable audit */ r = enable_audit(s->audit_fd, true); if (r < 0) - log_warning("Failed to issue audit enable call: %s", strerror(-r)); + log_warning_errno(r, "Failed to issue audit enable call: %m"); return 0; }