journal: split user logs into their own journal files

This commit is contained in:
Lennart Poettering 2011-10-07 23:03:07 +02:00
parent 260a2be455
commit f4b4781191
9 changed files with 264 additions and 100 deletions

View 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 = \

68
src/acl-util.c Normal file
View file

@ -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;
}

27
src/acl-util.h Normal file
View file

@ -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

View file

@ -29,6 +29,31 @@
#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);

View file

@ -25,21 +25,109 @@
#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();

View file

@ -43,33 +43,6 @@
#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;
};

View file

@ -27,46 +27,7 @@
#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;

View 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;

View 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);