chiark / gitweb /
journal: split user logs into their own journal files
authorLennart Poettering <lennart@poettering.net>
Fri, 7 Oct 2011 21:03:07 +0000 (23:03 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 7 Oct 2011 21:03:07 +0000 (23:03 +0200)
Makefile.am
src/acl-util.c [new file with mode: 0644]
src/acl-util.h [new file with mode: 0644]
src/journal/journal-private.h
src/journal/journald.c
src/journal/sd-journal.c
src/logind-acl.c
src/util.c
src/util.h

index 9bf92ad7aca7ccdc4d852174ff6e1d3d6fb0c81a..d43da3c47bb392137aad0add7b8aee6a17d26c86 100644 (file)
@@ -978,14 +978,17 @@ systemd_journald_SOURCES = \
        src/journal/journald.c \
        src/journal/sd-journal.c \
         src/journal/lookup3.c \
-        src/sd-id128.c
+        src/sd-id128.c \
+        src/acl-util.c
 
 systemd_journald_CFLAGS = \
-       $(AM_CFLAGS)
+       $(AM_CFLAGS) \
+        $(ACL_CFLAGS)
 
 systemd_journald_LDADD = \
        libsystemd-basic.la \
-        libsystemd-daemon.la
+        libsystemd-daemon.la \
+        $(ACL_LIBS)
 
 systemd_journalctl_SOURCES = \
        src/journal/journalctl.c \
@@ -1143,10 +1146,12 @@ systemd_uaccess_SOURCES = \
 
 if HAVE_ACL
 systemd_logind_SOURCES += \
-       src/logind-acl.c
+       src/logind-acl.c \
+        src/acl-util.c
 
 systemd_uaccess_SOURCES += \
-       src/logind-acl.c
+       src/logind-acl.c \
+        src/acl-util.c
 endif
 
 systemd_uaccess_CFLAGS = \
diff --git a/src/acl-util.c b/src/acl-util.c
new file mode 100644 (file)
index 0000000..a2a9f9a
--- /dev/null
@@ -0,0 +1,68 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <sys/acl.h>
+#include <acl/libacl.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include "acl-util.h"
+
+int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) {
+        acl_entry_t i;
+        int found;
+
+        assert(acl);
+        assert(entry);
+
+        for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
+             found > 0;
+             found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
+
+                acl_tag_t tag;
+                uid_t *u;
+                bool b;
+
+                if (acl_get_tag_type(i, &tag) < 0)
+                        return -errno;
+
+                if (tag != ACL_USER)
+                        continue;
+
+                u = acl_get_qualifier(i);
+                if (!u)
+                        return -errno;
+
+                b = *u == uid;
+                acl_free(u);
+
+                if (b) {
+                        *entry = i;
+                        return 1;
+                }
+        }
+
+        if (found < 0)
+                return -errno;
+
+        return 0;
+}
diff --git a/src/acl-util.h b/src/acl-util.h
new file mode 100644 (file)
index 0000000..798ce43
--- /dev/null
@@ -0,0 +1,27 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef fooaclutilhfoo
+#define fooaclutilhfoo
+
+/***
+  This file is part of systemd.
+
+  Copyright 2011 Lennart Poettering
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  systemd is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry);
+
+#endif
index 914b73a40b801c89cd76578200663cad120041f3..3277d2954277626e38e5ae0fe77dc0b13f660037 100644 (file)
 #include "util.h"
 #include "sd-id128.h"
 
+typedef struct JournalFile {
+        int fd;
+        char *path;
+        struct stat last_stat;
+        int prot;
+        bool writable;
+
+        Header *header;
+
+        HashItem *hash_table;
+        void *hash_table_window;
+        uint64_t hash_table_window_size;
+
+        uint64_t *bisect_table;
+        void *bisect_table_window;
+        uint64_t bisect_table_window_size;
+
+        void *window;
+        uint64_t window_offset;
+        uint64_t window_size;
+
+        Object *current;
+        uint64_t current_offset;
+} JournalFile;
+
 typedef struct JournalCoursor {
         sd_id128_t file_id;
         sd_id128_t boot_id;
@@ -38,8 +63,6 @@ typedef struct JournalCoursor {
         uint64_t xor_hash;
 } JournalCoursor;
 
-typedef struct JournalFile JournalFile;
-
 int journal_file_open(const char *fname, int flags, mode_t mode, JournalFile **ret);
 
 void journal_file_close(JournalFile *j);
index 818e146f94aeb30ce0d9384465f5faef4f9ec734..e9ac3a832e7b19d93037c0d74b314d22d2fa14d8 100644 (file)
 #include <sys/signalfd.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/acl.h>
+#include <acl/libacl.h>
 
 #include "hashmap.h"
 #include "journal-private.h"
 #include "sd-daemon.h"
 #include "socket-util.h"
+#include "acl-util.h"
 
 typedef struct Server {
         int syslog_fd;
         int epoll_fd;
         int signal_fd;
 
+        JournalFile *runtime_journal;
         JournalFile *system_journal;
         Hashmap *user_journals;
 } Server;
 
+static void fix_perms(JournalFile *f, uid_t uid) {
+        acl_t acl;
+        acl_entry_t entry;
+        acl_permset_t permset;
+        int r;
+
+        assert(f);
+
+        r = fchmod_and_fchown(f->fd, 0640, 0, 0);
+        if (r < 0)
+                log_warning("Failed to fix access mode/rights on %s, ignoring: %s", f->path, strerror(-r));
+
+        if (uid <= 0)
+                return;
+
+        acl = acl_get_fd(f->fd);
+        if (!acl) {
+                log_warning("Failed to read ACL on %s, ignoring: %m", f->path);
+                return;
+        }
+
+        r = acl_find_uid(acl, uid, &entry);
+        if (r <= 0) {
+
+                if (acl_create_entry(&acl, &entry) < 0 ||
+                    acl_set_tag_type(entry, ACL_USER) < 0 ||
+                    acl_set_qualifier(entry, &uid) < 0) {
+                        log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
+                        goto finish;
+                }
+        }
+
+        if (acl_get_permset(entry, &permset) < 0 ||
+            acl_add_perm(permset, ACL_READ) < 0 ||
+            acl_calc_mask(&acl) < 0) {
+                log_warning("Failed to patch ACL on %s, ignoring: %m", f->path);
+                goto finish;
+        }
+
+        if (acl_set_fd(f->fd, acl) < 0)
+                log_warning("Failed to set ACL on %s, ignoring: %m", f->path);
+
+finish:
+        acl_free(acl);
+}
+
+static JournalFile* find_journal(Server *s, uid_t uid) {
+        char *p;
+        int r;
+        JournalFile *f;
+
+        assert(s);
+
+        /* We split up user logs only on /var, not on /run */
+        if (!s->system_journal)
+                return s->runtime_journal;
+
+        if (uid <= 0)
+                return s->system_journal;
+
+        f = hashmap_get(s->user_journals, UINT32_TO_PTR(uid));
+        if (f)
+                return f;
+
+        if (asprintf(&p, "/var/log/journal/%lu.journal", (unsigned long) uid) < 0)
+                return s->system_journal;
+
+        r = journal_file_open(p, O_RDWR|O_CREAT, 0640, &f);
+        free(p);
+
+        if (r < 0)
+                return s->system_journal;
+
+        fix_perms(f, uid);
+
+        r = hashmap_put(s->user_journals, UINT32_TO_PTR(uid), f);
+        if (r < 0) {
+                journal_file_close(f);
+                return s->system_journal;
+        }
+
+        return f;
+}
+
 static void process_message(Server *s, const char *buf, struct ucred *ucred, struct timeval *tv) {
         char *message = NULL, *pid = NULL, *uid = NULL, *gid = NULL,
                 *source_time = NULL, *boot_id = NULL, *machine_id = NULL,
@@ -47,7 +135,6 @@ static void process_message(Server *s, const char *buf, struct ucred *ucred, str
                 *audit_session = NULL, *audit_loginuid = NULL,
                 *syslog_priority = NULL, *syslog_facility = NULL,
                 *exe = NULL;
-        dual_timestamp ts;
         struct iovec iovec[15];
         unsigned n = 0;
         char idbuf[33];
@@ -55,8 +142,8 @@ static void process_message(Server *s, const char *buf, struct ucred *ucred, str
         int r;
         char *t;
         int priority = LOG_USER | LOG_INFO;
-
-        dual_timestamp_get(&ts);
+        uid_t loginuid = 0;
+        JournalFile *f;
 
         parse_syslog_priority((char**) &buf, &priority);
         skip_syslog_date((char**) &buf);
@@ -73,7 +160,6 @@ static void process_message(Server *s, const char *buf, struct ucred *ucred, str
 
         if (ucred) {
                 uint32_t session;
-                uid_t loginuid;
 
                 if (asprintf(&pid, "PID=%lu", (unsigned long) ucred->pid) >= 0)
                         IOVEC_SET_STRING(iovec[n++], pid);
@@ -143,10 +229,15 @@ static void process_message(Server *s, const char *buf, struct ucred *ucred, str
                 free(t);
         }
 
-        r = journal_file_append_entry(s->system_journal, &ts, iovec, n, NULL, NULL);
-        if (r < 0)
-                log_error("Failed to write entry: %s", strerror(-r));
+        f = find_journal(s, loginuid);
+        if (!f)
+                log_warning("Dropping message, as we can't find a place to store the data.");
+        else {
+                r = journal_file_append_entry(f, NULL, iovec, n, NULL, NULL);
 
+                if (r < 0)
+                        log_error("Failed to write entry, ignoring: %s", strerror(-r));
+        }
 
         free(message);
         free(pid);
@@ -253,20 +344,6 @@ static int process_event(Server *s, struct epoll_event *ev) {
         return 1;
 }
 
-
-static int open_system_journal(JournalFile **f) {
-        int r;
-
-        r = journal_file_open("/var/log/journal/system.journal", O_RDWR|O_CREAT, 0644, f);
-        if (r == -ENOENT) {
-                mkdir_p("/run/log/journal", 0755);
-
-                r = journal_file_open("/run/log/journal/system.journal", O_RDWR|O_CREAT, 0644, f);
-        }
-
-        return r;
-}
-
 static int server_init(Server *s) {
         int n, one, r;
         struct epoll_event ev;
@@ -348,8 +425,18 @@ static int server_init(Server *s) {
                 return -ENOMEM;
         }
 
-        r = open_system_journal(&s->system_journal);
-        if (r < 0) {
+        r = journal_file_open("/var/log/journal/system.journal", O_RDWR|O_CREAT, 0640, &s->system_journal);
+        if (r >= 0)
+                fix_perms(s->system_journal, 0);
+        else if (r == -ENOENT) {
+                mkdir_p("/run/log/journal", 0755);
+
+                r = journal_file_open("/run/log/journal/system.journal", O_RDWR|O_CREAT, 0640, &s->runtime_journal);
+                if (r >= 0)
+                        fix_perms(s->runtime_journal, 0);
+        }
+
+        if (r < 0 && r != -ENOENT) {
                 log_error("Failed to open journal: %s", strerror(-r));
                 return r;
         }
@@ -383,6 +470,9 @@ static void server_done(Server *s) {
         if (s->system_journal)
                 journal_file_close(s->system_journal);
 
+        if (s->runtime_journal)
+                journal_file_close(s->runtime_journal);
+
         while ((f = hashmap_steal_first(s->user_journals)))
                 journal_file_close(f);
 
@@ -412,7 +502,7 @@ int main(int argc, char *argv[]) {
                 return EXIT_FAILURE;
         }
 
-        log_set_target(LOG_TARGET_AUTO);
+        log_set_target(LOG_TARGET_CONSOLE);
         log_parse_environment();
         log_open();
 
index 8bca300f93f4468531b483788d3ca35f47d54c1a..89bf545837ceb811cba68bb95805acd590723bae 100644 (file)
 
 #define DEFAULT_WINDOW_SIZE (128ULL*1024ULL*1024ULL)
 
-struct JournalFile {
-        int fd;
-        char *path;
-        struct stat last_stat;
-        int prot;
-        bool writable;
-
-        Header *header;
-
-        HashItem *hash_table;
-        void *hash_table_window;
-        uint64_t hash_table_window_size;
-
-        uint64_t *bisect_table;
-        void *bisect_table_window;
-        uint64_t bisect_table_window_size;
-
-        void *window;
-        uint64_t window_offset;
-        uint64_t window_size;
-
-        Object *current;
-        uint64_t current_offset;
-
-        LIST_FIELDS(JournalFile, files);
-};
-
 struct sd_journal {
         Hashmap *files;
 };
index 7a06b501d45fbe420caae814abf40f54347e3011..eb8a48d191f03189df4ed1a243dc3d0352811780 100644 (file)
 
 #include "logind-acl.h"
 #include "util.h"
-
-static int find_acl(acl_t acl, uid_t uid, acl_entry_t *entry) {
-        acl_entry_t i;
-        int found;
-
-        assert(acl);
-        assert(entry);
-
-        for (found = acl_get_entry(acl, ACL_FIRST_ENTRY, &i);
-             found > 0;
-             found = acl_get_entry(acl, ACL_NEXT_ENTRY, &i)) {
-
-                acl_tag_t tag;
-                uid_t *u;
-                bool b;
-
-                if (acl_get_tag_type(i, &tag) < 0)
-                        return -errno;
-
-                if (tag != ACL_USER)
-                        continue;
-
-                u = acl_get_qualifier(i);
-                if (!u)
-                        return -errno;
-
-                b = *u == uid;
-                acl_free(u);
-
-                if (b) {
-                        *entry = i;
-                        return 1;
-                }
-        }
-
-        if (found < 0)
-                return -errno;
-
-        return 0;
-}
+#include "acl-util.h"
 
 static int flush_acl(acl_t acl) {
         acl_entry_t i;
@@ -125,7 +86,7 @@ int devnode_acl(const char *path,
         } else if (del && old_uid > 0) {
                 acl_entry_t entry;
 
-                r = find_acl(acl, old_uid, &entry);
+                r = acl_find_uid(acl, old_uid, &entry);
                 if (r < 0)
                         goto finish;
 
@@ -144,7 +105,7 @@ int devnode_acl(const char *path,
                 acl_permset_t permset;
                 int rd, wt;
 
-                r = find_acl(acl, new_uid, &entry);
+                r = acl_find_uid(acl, new_uid, &entry);
                 if (r < 0)
                         goto finish;
 
index 99737e4e63012ba66f33b8b86d679f0b2a39d129..a3cfe864b6e44c5cf38e04c7c0a18386be0364e4 100644 (file)
@@ -3529,6 +3529,22 @@ int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
         return 0;
 }
 
+int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid) {
+        assert(fd >= 0);
+
+        /* Under the assumption that we are running privileged we
+         * first change the access mode and only then hand out
+         * ownership to avoid a window where access is too open. */
+
+        if (fchmod(fd, mode) < 0)
+                return -errno;
+
+        if (fchown(fd, uid, gid) < 0)
+                return -errno;
+
+        return 0;
+}
+
 cpu_set_t* cpu_set_malloc(unsigned *ncpus) {
         cpu_set_t *r;
         unsigned n = 1024;
index 1a2dd5825da45eaa359db7f0f34cb510c02bcdbf..89a7bec61280c89171ab9eda0a5b9e145c0190db 100644 (file)
@@ -366,6 +366,7 @@ int get_ctty_devnr(pid_t pid, dev_t *d);
 int get_ctty(pid_t, dev_t *_devnr, char **r);
 
 int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
+int fchmod_and_fchown(int fd, mode_t mode, uid_t uid, gid_t gid);
 
 int rm_rf(const char *path, bool only_dirs, bool delete_root, bool honour_sticky);