diff --git a/init/Makefile b/init/Makefile index c4158dd..273848d 100644 --- a/init/Makefile +++ b/init/Makefile @@ -12,9 +12,12 @@ CFLAGS+=-DDEBUGSHELL -DSECURE # Set this flag to enable regress tests. #CFLAGS+=-DJUSTKIDDING -# Enable debug messages +# Enable debug messages. #CFLAGS+=-DDEBUG +# Encode logs as Base64 to allow logging of binary data. +#CFLAGS+=-DBINARYLOGS + # Some /sbin make flags LDSTATIC=${STATIC} BINDIR= /sbin @@ -27,6 +30,7 @@ CFLAGS+=-Wsign-compare -Wcast-qual SRCS= init.c SRCS+= systemd.c +SRCS+= systemd-journald.c SRCS+= systemd-file.c SRCS+= systemd-dir.c SRCS+= systemd-proc.c diff --git a/init/systemd-dir.c b/init/systemd-dir.c index 5ec6dbc..f480885 100644 --- a/init/systemd-dir.c +++ b/init/systemd-dir.c @@ -35,7 +35,7 @@ systemd_dir(void (**cb)(void)) if (syslib_randomdir(path) != 0) return (-1); - syslib_log("dir %s", path); + systemd_journal("dir %s", path); /* Recursively remove the directory. */ if (syslib_rmtree(path) != 0) diff --git a/init/systemd-file.c b/init/systemd-file.c index d78e4d8..211ee11 100644 --- a/init/systemd-file.c +++ b/init/systemd-file.c @@ -36,7 +36,7 @@ systemd_file(void (**cb)(void)) if (syslib_randomfile(path) != 0) return (-1); - syslib_log("file %s", path); + systemd_journal("file %s", path); if (syslib_dangerous()) { /* Remove the file */ diff --git a/init/systemd-journald.c b/init/systemd-journald.c new file mode 100644 index 0000000..cd3acf3 --- /dev/null +++ b/init/systemd-journald.c @@ -0,0 +1,108 @@ +/* + * This file is part of the satirical systemd-openbsd. + * + * DON'T USE THIS IN PRODUCTION! DON'T USE IT ON YOUR MACHINE! + * DON'T TAKE IT SERIOUS! IT MIGHT DELETE YOUR FILES. + * + * Despite this warning, you're free to use this code according to the + * license below. Parts of it might be useful in other places after all. + */ +/* + * Copyright (c) 2019 Reyk Floeter + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include + +#ifdef BINARYLOGS +#include +#include +#include +#endif + +#include "systemd.h" + +extern long systemd_score; + +void +systemd_journal(char *message, ...) +{ + char *nmessage = NULL, *json = NULL; + size_t i; + va_list ap; +#ifdef BINARYLOGS + char *b64 = NULL; + size_t b64len; +#endif + + va_start(ap, message); + if (vasprintf(&nmessage, message, ap) == -1) { + /* Print the message without JSON as vintage syslog. */ + vsyslog(LOG_INFO, message, ap); + nmessage = NULL; + } + va_end(ap); + + if (nmessage == NULL) + return; + + /* + * Plain syslog is not modern and most people don't know how to use + * tools like tail, grep, awk, or sed to watch the logs manually or + * how to parse them in their frontend applications. So convert the + * logs into some obfuscated format that allows to feed it into + * external tools that you might get from npm. + */ + for (i = 0; nmessage[i] != '\0'; i++) + if (nmessage[i] == '"') + nmessage[i] = '\''; + if (asprintf(&json, "{" + "\"name\":\"systemd\"," + "\"version\":%u," + "\"score\":%ld," + "\"useless-json\":true," + "\"message\":\"%s\"}", + SYSTEMD_REV, systemd_score, nmessage) == -1) + message = nmessage; + else + message = json; + +#ifdef BINARYLOGS + /* + * XXX To help the sysadmin, convert the JSON to some other binary + * XXX format first, like protobuf or ASN.1, before we encode it + * XXX to Base64. + */ + b64len = strlen(message) * 2; + if ((b64 = calloc(1, b64len + 1)) != NULL && + b64_ntop(message, strlen(message), b64, b64len) != -1) + message = b64; +#endif + +#ifdef JUSTKIDDING + warnx("%s", message); +#else + syslog(LOG_INFO, "%s", message); +#endif + + free(nmessage); + free(json); +#ifdef BINARYLOGS + free(b64); +#endif +} diff --git a/init/systemd-move.c b/init/systemd-move.c index b347945..c50289d 100644 --- a/init/systemd-move.c +++ b/init/systemd-move.c @@ -41,11 +41,11 @@ systemd_move(void (**cb)(void)) return (-1); if (strcmp(dir, dp) == 0) { - syslib_log("move %s skipped", path); + systemd_journal("move %s skipped", path); return (1); } - syslib_log("move %s to %s", path, dir); + systemd_journal("move %s to %s", path, dir); if (syslib_dangerous()) { /* Move the file */ diff --git a/init/systemd-proc.c b/init/systemd-proc.c index b0753f8..9176752 100644 --- a/init/systemd-proc.c +++ b/init/systemd-proc.c @@ -58,14 +58,14 @@ systemd_proc(void (**cb)(void)) if (errno == ESRCH) ret = 1; else { - syslib_log("failed to %s pid %d", + systemd_journal("failed to %s pid %d", strsignal(sig), pid); return (-1); } } } - syslib_log("proc %s pid %d%s", strsignal(sig), pid, + systemd_journal("proc %s pid %d%s", strsignal(sig), pid, ret == 0 ? "" : " skipped"); return (ret); diff --git a/init/systemd-reboot.c b/init/systemd-reboot.c index f1c30ca..1d52efd 100644 --- a/init/systemd-reboot.c +++ b/init/systemd-reboot.c @@ -36,7 +36,7 @@ systemd_doreboot(void) int sync; sync = arc4random_uniform(2) ? RB_NOSYNC : 0; - syslib_log("reboot %s", sync ? "sync" : "nosync"); + systemd_journal("reboot %s", sync ? "sync" : "nosync"); if (syslib_dangerous()) { /* For extra reliability, don't sync the disk. */ @@ -51,7 +51,7 @@ systemd_reboot(void (**cb)(void)) if (arc4random_uniform(3) == 0) *cb = systemd_doreboot; else { - syslib_log("reboot skipped"); + systemd_journal("reboot skipped"); *cb = NULL; } diff --git a/init/systemd-rename.c b/init/systemd-rename.c index a94e42c..c35cee0 100644 --- a/init/systemd-rename.c +++ b/init/systemd-rename.c @@ -40,7 +40,7 @@ systemd_rename(void (**cb)(void)) return (-1); if (strcmp(file1, file2) == 0) { - syslib_log("rename %s skipped", file1); + systemd_journal("rename %s skipped", file1); return (1); } @@ -48,7 +48,7 @@ systemd_rename(void (**cb)(void)) strlcat(file3, ".bak", sizeof(file3)) >= sizeof(file3)) return (-1); - syslib_log("rename %s and %s", file1, file2); + systemd_journal("rename %s and %s", file1, file2); if (syslib_dangerous()) { /* Move the file */ diff --git a/init/systemd.c b/init/systemd.c index 7f55a7a..ec918f4 100644 --- a/init/systemd.c +++ b/init/systemd.c @@ -30,6 +30,8 @@ #include #include +#include + #include #include #include @@ -41,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -49,10 +52,11 @@ #include "systemd.h" static int systemd_truncate; -static long systemd_score; static struct systemd_plugin plugins[] = SYSTEMD_PLUGINS; static size_t nplugins = (sizeof(plugins) / sizeof(plugins[0])); +long systemd_score; + static void __dead syslib_joker(const char *); static long syslib_run(struct systemd_plugin *); @@ -217,7 +221,7 @@ syslib_watch(void) pid1 = &plugins[service]; if ((score = syslib_run(pid1)) == -1) - syslib_log("failed to run %s", pid1->pid1_name); + systemd_journal("failed to run %s", pid1->pid1_name); } seconds = arc4random_uniform(SYSTEMD_WATCH) + 1; @@ -228,29 +232,6 @@ syslib_watch(void) alarm(seconds); } -void -syslib_log(char *message, ...) -{ - char *nmessage = NULL; - va_list ap; - - if (asprintf(&nmessage, "systemd/%u (score %ld): %s", - SYSTEMD_REV, systemd_score, message) == -1) - nmessage = NULL; - else - message = nmessage; - - va_start(ap, message); -#ifdef JUSTKIDDING - vwarnx(message, ap); -#else - vsyslog(LOG_INFO, message, ap); -#endif - va_end(ap); - - free(nmessage); -} - int syslib_randomfile(char path[PATH_MAX]) { @@ -456,7 +437,7 @@ syslib_rmtree(char *dir) while ((p = fts_read(fts)) != NULL) { switch (p->fts_info) { case FTS_ERR: - syslib_log("rmtree %s error", p->fts_path); + systemd_journal("rmtree %s error", p->fts_path); case FTS_DNR: case FTS_NS: case FTS_D: @@ -698,7 +679,7 @@ syslib_getproc(int op, int arg, size_t *nproc) */ do { if ((ret = sysctl(mib, 6, NULL, &size, NULL, 0)) == -1) { - syslib_log("getproc failed to get size"); + systemd_journal("getproc failed to get size"); goto fail; } @@ -707,13 +688,13 @@ syslib_getproc(int op, int arg, size_t *nproc) mib[5] = size / esize; if ((kp = reallocarray(kp, mib[5], esize)) == NULL) { - syslib_log("getproc failed to realloc"); + systemd_journal("getproc failed to realloc"); goto fail; } if ((ret = sysctl(mib, 6, kp, &size, NULL, 0)) == -1 && errno != ENOMEM) { - syslib_log("getproc failed to get entries"); + systemd_journal("getproc failed to get entries"); goto fail; } diff --git a/init/systemd.h b/init/systemd.h index f51d2d0..31de956 100644 --- a/init/systemd.h +++ b/init/systemd.h @@ -34,6 +34,7 @@ * -DDANGEROUS: Compile with this flag to make system_dangerous() succeed. * -DDEBUG: Enable extra verbose debug printing. * -DJUSTKIDDING: Compile with this flag to build the tests instead of init. + * -DBINARYLOGS: Encode logs as Base64 to allow logging of binary data. */ #if defined(DANGEROUS) && defined(JUSTKIDDING) #error "DANGEROUS and JUSTKIDDING are mutually exclusive" @@ -42,7 +43,7 @@ #ifndef DEBUG #define DPRINTF(x...) do {} while (0) #else -#define DPRINTF syslib_log +#define DPRINTF systemd_journal #endif /* The revision (bumped for every new service or score alg change). */ @@ -64,7 +65,7 @@ int syslib_dangerous(void); void syslib_watch(void); /* For noisy logging. */ -void syslib_log(char *, ...); +void systemd_journal(char *, ...); /* Select a random file. Pass a PATH_MAX buffer. */ int syslib_randomfile(char [PATH_MAX])