chiark / gitweb /
journal: if the syslog forwarder socket is full, then don't block
[elogind.git] / src / journal / journald.c
index 0194a1b8c9e60b32d3ecc03a9543f3442b4e2472..f924c9353b96a5bb0d4db1af2561b97691ebda56 100644 (file)
 #include "acl-util.h"
 #endif
 
+#ifdef HAVE_SELINUX
+#include <selinux/selinux.h>
+#endif
+
 #define USER_JOURNALS_MAX 1024
 #define STDOUT_STREAMS_MAX 4096
 
@@ -64,7 +68,7 @@
 
 #define SYSLOG_TIMEOUT_USEC (250*USEC_PER_MSEC)
 
-#define N_IOVEC_META_FIELDS 16
+#define N_IOVEC_META_FIELDS 17
 
 typedef enum StdoutStreamState {
         STDOUT_STREAM_IDENTIFIER,
@@ -183,7 +187,26 @@ finish:
         return avail;
 }
 
-static void fix_perms(JournalFile *f, uid_t uid) {
+static void server_read_file_gid(Server *s) {
+        const char *adm = "adm";
+        int r;
+
+        assert(s);
+
+        if (s->file_gid_valid)
+                return;
+
+        r = get_group_creds(&adm, &s->file_gid);
+        if (r < 0)
+                log_warning("Failed to resolve 'adm' group: %s", strerror(-r));
+
+        /* if we couldn't read the gid, then it will be 0, but that's
+         * fine and we shouldn't try to resolve the group again, so
+         * let's just pretend it worked right-away. */
+        s->file_gid_valid = true;
+}
+
+static void server_fix_perms(Server *s, JournalFile *f, uid_t uid) {
         int r;
 #ifdef HAVE_ACL
         acl_t acl;
@@ -193,7 +216,9 @@ static void fix_perms(JournalFile *f, uid_t uid) {
 
         assert(f);
 
-        r = fchmod_and_fchown(f->fd, 0640, 0, 0);
+        server_read_file_gid(s);
+
+        r = fchmod_and_fchown(f->fd, 0640, 0, s->file_gid);
         if (r < 0)
                 log_warning("Failed to fix access mode/rights on %s, ignoring: %s", f->path, strerror(-r));
 
@@ -277,7 +302,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {
         if (r < 0)
                 return s->system_journal;
 
-        fix_perms(f, uid);
+        server_fix_perms(s, f, uid);
         f->metrics = s->system_metrics;
         f->compress = s->compress;
 
@@ -415,7 +440,7 @@ static void dispatch_message_real(Server *s,
                 *comm = NULL, *cmdline = NULL, *hostname = NULL,
                 *audit_session = NULL, *audit_loginuid = NULL,
                 *exe = NULL, *cgroup = NULL, *session = NULL,
-                *owner_uid = NULL, *unit = NULL;
+                *owner_uid = NULL, *unit = NULL, *selinux_context = NULL;
 
         char idbuf[33];
         sd_id128_t id;
@@ -433,6 +458,9 @@ static void dispatch_message_real(Server *s,
         if (ucred) {
                 uint32_t audit;
                 uid_t owner;
+#ifdef HAVE_SELINUX
+                security_context_t con;
+#endif
 
                 realuid = ucred->uid;
 
@@ -510,6 +538,16 @@ static void dispatch_message_real(Server *s,
                 if (sd_pid_get_owner_uid(ucred->uid, &owner) >= 0)
                         if (asprintf(&owner_uid, "_SYSTEMD_OWNER_UID=%lu", (unsigned long) owner) >= 0)
                                 IOVEC_SET_STRING(iovec[n++], owner_uid);
+
+#ifdef HAVE_SELINUX
+                if (getpidcon(ucred->pid, &con) >= 0) {
+                        selinux_context = strappend("_SELINUX_CONTEXT=", con);
+                        if (selinux_context)
+                                IOVEC_SET_STRING(iovec[n++], selinux_context);
+
+                        freecon(con);
+                }
+#endif
         }
 
         if (tv) {
@@ -581,6 +619,7 @@ retry:
         free(session);
         free(owner_uid);
         free(unit);
+        free(selinux_context);
 }
 
 static void driver_message(Server *s, sd_id128_t message_id, const char *format, ...) {
@@ -713,6 +752,11 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
         if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
                 return;
 
+        /* The socket is full? I guess the syslog implementation is
+         * too slow, and we shouldn't wait for that... */
+        if (errno == EAGAIN)
+                return;
+
         if (ucred && errno == ESRCH) {
                 struct ucred u;
 
@@ -726,6 +770,9 @@ static void forward_syslog_iovec(Server *s, const struct iovec *iovec, unsigned
 
                 if (sendmsg(s->syslog_fd, &msghdr, MSG_NOSIGNAL) >= 0)
                         return;
+
+                if (errno == EAGAIN)
+                        return;
         }
 
         log_debug("Failed to forward syslog message: %m");
@@ -1733,7 +1780,7 @@ static int system_journal_open(Server *s) {
                         s->system_journal->metrics = s->system_metrics;
                         s->system_journal->compress = s->compress;
 
-                        fix_perms(s->system_journal, 0);
+                        server_fix_perms(s, s->system_journal, 0);
                 } else if (r < 0) {
 
                         if (r != -ENOENT && r != -EROFS)
@@ -1786,7 +1833,7 @@ static int system_journal_open(Server *s) {
                         s->runtime_journal->metrics = s->runtime_metrics;
                         s->runtime_journal->compress = s->compress;
 
-                        fix_perms(s->runtime_journal, 0);
+                        server_fix_perms(s, s->runtime_journal, 0);
                 }
         }