journal-remote.c revision 70f1b2ddc6b94d3fa5539eb8503887b465f7fcc7
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt/***
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt This file is part of systemd.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Copyright 2012 Zbigniew Jędrzejewski-Szmek
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is free software; you can redistribute it and/or modify it
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt under the terms of the GNU Lesser General Public License as published by
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt the Free Software Foundation; either version 2.1 of the License, or
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt (at your option) any later version.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt systemd is distributed in the hope that it will be useful, but
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt WITHOUT ANY WARRANTY; without even the implied warranty of
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt Lesser General Public License for more details.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt You should have received a copy of the GNU Lesser General Public License
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt along with systemd; If not, see <http://www.gnu.org/licenses/>.
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt***/
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <errno.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <fcntl.h>
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt#include <stdio.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <stdlib.h>
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include <string.h>
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include <sys/prctl.h>
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include <sys/socket.h>
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen#include <sys/stat.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <sys/types.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <unistd.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <getopt.h>
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "sd-daemon.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "journal-file.h"
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include "journald-native.h"
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt#include "socket-util.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "mkdir.h"
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen#include "build.h"
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen#include "macro.h"
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen#include "strv.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "fileio.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "conf-parser.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include "siphash24.h"
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#ifdef HAVE_GNUTLS
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#include <gnutls/gnutls.h>
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#endif
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt#include "journal-remote.h"
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#include "journal-remote-write.h"
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt#define REMOTE_JOURNAL_PATH "/var/log/journal/remote"
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt#define PRIV_KEY_FILE CERTIFICATE_ROOT "/private/journal-remote.pem"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt#define CERT_FILE CERTIFICATE_ROOT "/certs/journal-remote.pem"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt#define TRUST_FILE CERTIFICATE_ROOT "/ca/trusted.pem"
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic char* arg_url = NULL;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic char* arg_getter = NULL;
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersenstatic char* arg_listen_raw = NULL;
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersenstatic char* arg_listen_http = NULL;
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersenstatic char* arg_listen_https = NULL;
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersenstatic char** arg_files = NULL;
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersenstatic int arg_compress = true;
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersenstatic int arg_seal = false;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic int http_socket = -1, https_socket = -1;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic char** arg_gnutls_log = NULL;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic JournalWriteSplitMode arg_split_mode = JOURNAL_WRITE_SPLIT_HOST;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic char* arg_output = NULL;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic char *arg_key = NULL;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic char *arg_cert = NULL;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic char *arg_trust = NULL;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic bool arg_trust_all = false;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt/**********************************************************************
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt **********************************************************************
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt **********************************************************************/
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int spawn_child(const char* child, char** argv) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int fd[2];
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt pid_t parent_pid, child_pid;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int r;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (pipe(fd) < 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Failed to create pager pipe: %m");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return -errno;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt parent_pid = getpid();
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt child_pid = fork();
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (child_pid < 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = -errno;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("Failed to fork: %m");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt safe_close_pair(fd);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* In the child */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (child_pid == 0) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = dup2(fd[1], STDOUT_FILENO);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("Failed to dup pipe to stdout: %m");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt _exit(EXIT_FAILURE);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt safe_close_pair(fd);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* Make sure the child goes away when the parent dies */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt _exit(EXIT_FAILURE);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt /* Check whether our parent died before we were able
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt * to set the death signal */
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (getppid() != parent_pid)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt _exit(EXIT_SUCCESS);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt execvp(child, argv);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("Failed to exec child %s: %m", child);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt _exit(EXIT_FAILURE);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = close(fd[1]);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_warning("Failed to close write end of pipe: %m");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return fd[0];
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic int spawn_curl(const char* url) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt char **argv = STRV_MAKE("curl",
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt "-HAccept: application/vnd.fdo.journal",
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt "--silent",
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt "--show-error",
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt url);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt int r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = spawn_child("curl", argv);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("Failed to spawn curl: %m");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int spawn_getter(const char *getter, const char *url) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int r;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt _cleanup_strv_free_ char **words = NULL;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt assert(getter);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt r = strv_split_quoted(&words, getter);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (r < 0) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_error("Failed to split getter option: %s", strerror(-r));
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return r;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt r = strv_extend(&words, url);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_error("Failed to create command line: %s", strerror(-r));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = spawn_child(words[0], words);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("Failed to spawn getter %s: %m", getter);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt#define filename_escape(s) xescape((s), "/ ")
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic int open_output(Writer *w, const char* host) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt _cleanup_free_ char *_output = NULL;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt const char *output;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt int r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt switch (arg_split_mode) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt case JOURNAL_WRITE_SPLIT_NONE:
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt output = arg_output ?: REMOTE_JOURNAL_PATH "/remote.journal";
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt break;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt case JOURNAL_WRITE_SPLIT_HOST: {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt _cleanup_free_ char *name;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt assert(host);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt name = filename_escape(host);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (!name)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return log_oom();
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt r = asprintf(&_output, "%s/remote-%s.journal",
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt arg_output ?: REMOTE_JOURNAL_PATH,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt name);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (r < 0)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return log_oom();
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt output = _output;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt break;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt }
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt default:
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt assert_not_reached("what?");
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt }
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt r = journal_file_open_reliably(output,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt O_RDWR|O_CREAT, 0640,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt arg_compress, arg_seal,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt &w->metrics,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt w->mmap,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt NULL, &w->journal);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (r < 0)
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt log_error("Failed to open output journal %s: %s",
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt output, strerror(-r));
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt else
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt log_info("Opened output file %s", w->journal->path);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return r;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt}
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt/**********************************************************************
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt **********************************************************************
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt **********************************************************************/
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int init_writer_hashmap(RemoteServer *s) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt static const struct hash_ops *hash_ops[] = {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt [JOURNAL_WRITE_SPLIT_NONE] = NULL,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt [JOURNAL_WRITE_SPLIT_HOST] = &string_hash_ops,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt };
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(arg_split_mode >= 0 && arg_split_mode < (int) ELEMENTSOF(hash_ops));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt s->writers = hashmap_new(hash_ops[arg_split_mode]);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (!s->writers)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return log_oom();
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return 0;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt}
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int get_writer(RemoteServer *s, const char *host,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt Writer **writer) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt const void *key;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt _cleanup_writer_unref_ Writer *w = NULL;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt int r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt switch(arg_split_mode) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt case JOURNAL_WRITE_SPLIT_NONE:
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt key = "one and only";
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt break;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt case JOURNAL_WRITE_SPLIT_HOST:
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(host);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt key = host;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt break;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt default:
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert_not_reached("what split mode?");
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt w = hashmap_get(s->writers, key);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (w)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt writer_ref(w);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt else {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt w = writer_new(s);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (!w)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return log_oom();
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt w->hashmap_key = strdup(key);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (!w->hashmap_key)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return log_oom();
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = open_output(w, host);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = hashmap_put(s->writers, w->hashmap_key ?: key, w);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0)
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt *writer = w;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt w = NULL;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return 0;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt}
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt/**********************************************************************
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt **********************************************************************
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt **********************************************************************/
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt/* This should go away as soon as µhttpd allows state to be passed around. */
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic RemoteServer *server;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flyktstatic int dispatch_raw_source_event(sd_event_source *event,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int fd,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt uint32_t revents,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt void *userdata);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int dispatch_blocking_source_event(sd_event_source *event,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt void *userdata);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int dispatch_raw_connection_event(sd_event_source *event,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt int fd,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt uint32_t revents,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt void *userdata);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int dispatch_http_event(sd_event_source *event,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt int fd,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt uint32_t revents,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt void *userdata);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int get_source_for_fd(RemoteServer *s,
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt int fd, char *name, RemoteSource **source) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt Writer *writer;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt int r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(fd >= 0);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(source);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (!GREEDY_REALLOC0(s->sources, s->sources_size, fd + 1))
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return log_oom();
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = get_writer(s, name, &writer);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_warning("Failed to get writer for source %s: %s",
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt name, strerror(-r));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (s->sources[fd] == NULL) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt s->sources[fd] = source_new(fd, false, name, writer);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (!s->sources[fd]) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt writer_unref(writer);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return log_oom();
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt s->active++;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt *source = s->sources[fd];
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return 0;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt}
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flyktstatic int remove_source(RemoteServer *s, int fd) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt RemoteSource *source;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(s);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(fd >= 0 && fd < (ssize_t) s->sources_size);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt source = s->sources[fd];
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (source) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt /* this closes fd too */
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt source_free(source);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt s->sources[fd] = NULL;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt s->active--;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return 0;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt}
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flyktstatic int add_source(RemoteServer *s, int fd, char* name, bool own_name) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt RemoteSource *source;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt int r;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt assert(s);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt assert(fd >= 0);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt assert(name);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (!own_name) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt name = strdup(name);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (!name)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return log_oom();
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt r = get_source_for_fd(s, fd, name, &source);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (r < 0) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_error("Failed to create source for fd:%d (%s): %s",
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt fd, name, strerror(-r));
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return r;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt r = sd_event_add_io(s->events, &source->event,
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt fd, EPOLLIN|EPOLLRDHUP|EPOLLPRI,
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt dispatch_raw_source_event, s);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (r == -EPERM) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_debug("Falling back to sd_event_add_defer for fd:%d (%s)", fd, name);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt r = sd_event_add_defer(s->events, &source->event,
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt dispatch_blocking_source_event, source);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (r == 0)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt sd_event_source_set_enabled(source->event, SD_EVENT_ON);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (r < 0) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt log_error("Failed to register event source for fd:%d: %s",
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt fd, strerror(-r));
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt goto error;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 1; /* work to do */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt error:
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt remove_source(s, fd);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return r;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int add_raw_socket(RemoteServer *s, int fd) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt int r;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = sd_event_add_io(s->events, &s->listen_event,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt fd, EPOLLIN,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt dispatch_raw_connection_event, s);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt close(fd);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return r;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt s->active ++;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int setup_raw_socket(RemoteServer *s, const char *address) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt int fd;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (fd < 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return fd;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return add_raw_socket(s, fd);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt/**********************************************************************
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt **********************************************************************
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt **********************************************************************/
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic RemoteSource *request_meta(void **connection_cls, int fd, char *hostname) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt RemoteSource *source;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt Writer *writer;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt int r;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(connection_cls);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (*connection_cls)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return *connection_cls;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = get_writer(server, hostname, &writer);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_warning("Failed to get writer for source %s: %s",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt hostname, strerror(-r));
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return NULL;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt source = source_new(fd, true, hostname, writer);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!source) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_oom();
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt writer_unref(writer);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return NULL;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_debug("Added RemoteSource as connection metadata %p", source);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt *connection_cls = source;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return source;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic void request_meta_free(void *cls,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct MHD_Connection *connection,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt void **connection_cls,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt enum MHD_RequestTerminationCode toe) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt RemoteSource *s;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(connection_cls);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt s = *connection_cls;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_debug("Cleaning up connection metadata %p", s);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt source_free(s);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt *connection_cls = NULL;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt}
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int process_http_upload(
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct MHD_Connection *connection,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt const char *upload_data,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt size_t *upload_data_size,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt RemoteSource *source) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt bool finished = false;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt size_t remaining;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt int r;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(source);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_debug("request_handler_upload: connection %p, %zu bytes",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt connection, *upload_data_size);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (*upload_data_size) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_debug("Received %zu bytes", *upload_data_size);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = push_data(source, upload_data, *upload_data_size);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return mhd_respond_oom(connection);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt *upload_data_size = 0;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt } else
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt finished = true;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt while (true) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = process_source(source, arg_compress, arg_seal);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r == -EAGAIN || r == -EWOULDBLOCK)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt break;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt else if (r < 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_warning("Failed to process data for connection %p", connection);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r == -E2BIG)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return mhd_respondf(connection,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt MHD_HTTP_REQUEST_ENTITY_TOO_LARGE,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "Entry is too large, maximum is %u bytes.\n",
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt DATA_SIZE_MAX);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt else
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return mhd_respondf(connection,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt MHD_HTTP_UNPROCESSABLE_ENTITY,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "Processing failed: %s.", strerror(-r));
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!finished)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return MHD_YES;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt /* The upload is finished */
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt remaining = source_non_empty(source);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (remaining > 0) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_warning("Premature EOFbyte. %zu bytes lost.", remaining);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return mhd_respondf(connection, MHD_HTTP_EXPECTATION_FAILED,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "Premature EOF. %zu bytes of trailing data not processed.",
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt remaining);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return mhd_respond(connection, MHD_HTTP_ACCEPTED, "OK.\n");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt};
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flyktstatic int request_handler(
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt void *cls,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt struct MHD_Connection *connection,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt const char *url,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt const char *method,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt const char *version,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt const char *upload_data,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt size_t *upload_data_size,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt void **connection_cls) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt const char *header;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt int r, code, fd;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt _cleanup_free_ char *hostname = NULL;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(connection);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(connection_cls);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(url);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(method);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_debug("Handling a connection %s %s %s", method, url, version);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (*connection_cls)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return process_http_upload(connection,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt upload_data, upload_data_size,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt *connection_cls);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!streq(method, "POST"))
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "Unsupported method.\n");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!streq(url, "/upload"))
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return mhd_respond(connection, MHD_HTTP_NOT_FOUND,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "Not found.\n");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt header = MHD_lookup_connection_value(connection,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt MHD_HEADER_KIND, "Content-Type");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!header || !streq(header, "application/vnd.fdo.journal"))
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "Content-Type: application/vnd.fdo.journal"
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt " is required.\n");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt const union MHD_ConnectionInfo *ci;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt ci = MHD_get_connection_info(connection,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt MHD_CONNECTION_INFO_CONNECTION_FD);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (!ci) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt log_error("MHD_get_connection_info failed: cannot get remote fd");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt "Cannot check remote address");
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt fd = ci->connect_fd;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt assert(fd >= 0);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt }
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (server->check_trust) {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = check_permissions(connection, &code, &hostname);
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt if (r < 0)
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt return code;
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt } else {
631bbe71298ec892f77f44f94feb612646fe6853Patrik Flykt r = getnameinfo_pretty(fd, &hostname);
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt if (r < 0) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt "Cannot check remote hostname");
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt assert(hostname);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (!request_meta(connection_cls, fd, hostname))
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return respond_oom(connection);
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt hostname = NULL;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return MHD_YES;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt}
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flyktstatic int setup_microhttpd_server(RemoteServer *s,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int fd,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt const char *key,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt const char *cert,
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt const char *trust) {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt struct MHD_OptionItem opts[] = {
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free},
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger},
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt { MHD_OPTION_LISTEN_SOCKET, fd},
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt { MHD_OPTION_END},
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt { MHD_OPTION_END},
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt { MHD_OPTION_END},
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt { MHD_OPTION_END}};
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int opts_pos = 3;
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt int flags =
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt MHD_USE_DEBUG |
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt MHD_USE_PEDANTIC_CHECKS |
a9aff3615b430f86bd0a824214d95f634efaf894Patrik Flykt MHD_USE_EPOLL_LINUX_ONLY |
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt MHD_USE_DUAL_STACK;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt const union MHD_DaemonInfo *info;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt int r, epoll_fd;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt MHDDaemonWrapper *d;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt assert(fd >= 0);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt r = fd_nonblock(fd, true);
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt if (r < 0) {
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt log_error("Failed to make fd:%d nonblocking: %s", fd, strerror(-r));
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt return r;
d1b0afe3653b4316a6361d204169620726d468a0Patrik Flykt }
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt if (key) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt assert(cert);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt opts[opts_pos++] = (struct MHD_OptionItem)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt {MHD_OPTION_HTTPS_MEM_KEY, 0, (char*) key};
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt opts[opts_pos++] = (struct MHD_OptionItem)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt {MHD_OPTION_HTTPS_MEM_CERT, 0, (char*) cert};
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt flags |= MHD_USE_SSL;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (trust)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt opts[opts_pos++] = (struct MHD_OptionItem)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt {MHD_OPTION_HTTPS_MEM_TRUST, 0, (char*) trust};
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt d = new(MHDDaemonWrapper, 1);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (!d)
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt return log_oom();
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt d->fd = (uint64_t) fd;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt d->daemon = MHD_start_daemon(flags, 0,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt NULL, NULL,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt request_handler, NULL,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt MHD_OPTION_ARRAY, opts,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt MHD_OPTION_END);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (!d->daemon) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("Failed to start µhttp daemon");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = -EINVAL;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt goto error;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)",
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt key ? "HTTPS" : "HTTP", fd, d);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (!info) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("µhttp returned NULL daemon info");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = -ENOTSUP;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt goto error;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt epoll_fd = info->listen_fd;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (epoll_fd < 0) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("µhttp epoll fd is invalid");
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = -EUCLEAN;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt goto error;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = sd_event_add_io(s->events, &d->event,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt epoll_fd, EPOLLIN,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt dispatch_http_event, d);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("Failed to add event callback: %s", strerror(-r));
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt goto error;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_oom();
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt goto error;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt r = hashmap_put(s->daemons, &d->fd, d);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt if (r < 0) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt log_error("Failed to add daemon to hashmap: %s", strerror(-r));
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt goto error;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt }
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt s->active ++;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return 0;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykterror:
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt MHD_stop_daemon(d->daemon);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt free(d->daemon);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt free(d);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic int setup_microhttpd_socket(RemoteServer *s,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt const char *address,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt const char *key,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt const char *cert,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt const char *trust) {
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt int fd;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC);
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen if (fd < 0)
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return fd;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt return setup_microhttpd_server(s, fd, key, cert, trust);
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt}
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic int dispatch_http_event(sd_event_source *event,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt int fd,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt uint32_t revents,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt void *userdata) {
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt MHDDaemonWrapper *d = userdata;
f12abb48fc510b8b349c05e35ba048134debaf25Patrik Flykt int r;
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt assert(d);
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen r = MHD_run(d->daemon);
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen if (r == MHD_NO) {
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen log_error("MHD_run failed!");
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen // XXX: unregister daemon
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen return -EINVAL;
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen }
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen return 1; /* work to do */
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen}
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen/**********************************************************************
a276e6d68606861b552140cbcc003f4af10626fcTom Gundersen **********************************************************************
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt **********************************************************************/
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flyktstatic int dispatch_sigterm(sd_event_source *event,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt const struct signalfd_siginfo *si,
139b011ab81ccea1d51f09e0261a1c390115c6ffPatrik Flykt void *userdata) {
RemoteServer *s = userdata;
assert(s);
log_received_signal(LOG_INFO, si);
sd_event_exit(s->events, 0);
return 0;
}
static int setup_signals(RemoteServer *s) {
sigset_t mask;
int r;
assert(s);
assert_se(sigemptyset(&mask) == 0);
sigset_add_many(&mask, SIGINT, SIGTERM, -1);
assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
r = sd_event_add_signal(s->events, &s->sigterm_event, SIGTERM, dispatch_sigterm, s);
if (r < 0)
return r;
r = sd_event_add_signal(s->events, &s->sigint_event, SIGINT, dispatch_sigterm, s);
if (r < 0)
return r;
return 0;
}
static int fd_fd(const char *spec) {
int fd, r;
r = safe_atoi(spec, &fd);
if (r < 0)
return r;
if (fd < 0)
return -EINVAL;
return fd;
}
static int remoteserver_init(RemoteServer *s,
const char* key,
const char* cert,
const char* trust) {
int r, n, fd;
char **file;
assert(s);
if ((arg_listen_raw || arg_listen_http) && trust) {
log_error("Option --trust makes all non-HTTPS connections untrusted.");
return -EINVAL;
}
r = sd_event_default(&s->events);
if (r < 0) {
log_error("Failed to allocate event loop: %s", strerror(-r));
return r;
}
setup_signals(s);
assert(server == NULL);
server = s;
r = init_writer_hashmap(s);
if (r < 0)
return r;
n = sd_listen_fds(true);
if (n < 0) {
log_error("Failed to read listening file descriptors from environment: %s",
strerror(-n));
return n;
} else
log_info("Received %d descriptors", n);
if (MAX(http_socket, https_socket) >= SD_LISTEN_FDS_START + n) {
log_error("Received fewer sockets than expected");
return -EBADFD;
}
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
if (sd_is_socket(fd, AF_UNSPEC, 0, false)) {
log_info("Received a listening socket (fd:%d)", fd);
if (fd == http_socket)
r = setup_microhttpd_server(s, fd, NULL, NULL, NULL);
else if (fd == https_socket)
r = setup_microhttpd_server(s, fd, key, cert, trust);
else
r = add_raw_socket(s, fd);
} else if (sd_is_socket(fd, AF_UNSPEC, 0, true)) {
char *hostname;
r = getnameinfo_pretty(fd, &hostname);
if (r < 0) {
log_error("Failed to retrieve remote name: %s", strerror(-r));
return r;
}
log_info("Received a connection socket (fd:%d) from %s", fd, hostname);
r = add_source(s, fd, hostname, true);
if (r < 0)
free(hostname);
} else {
log_error("Unknown socket passed on fd:%d", fd);
return -EINVAL;
}
if(r < 0) {
log_error("Failed to register socket (fd:%d): %s",
fd, strerror(-r));
return r;
}
}
if (arg_url) {
const char *url, *hostname;
url = strappenda(arg_url, "/entries");
if (arg_getter) {
log_info("Spawning getter %s...", url);
fd = spawn_getter(arg_getter, url);
} else {
log_info("Spawning curl %s...", url);
fd = spawn_curl(url);
}
if (fd < 0)
return fd;
hostname =
startswith(arg_url, "https://") ?:
startswith(arg_url, "http://") ?:
arg_url;
r = add_source(s, fd, (char*) hostname, false);
if (r < 0)
return r;
}
if (arg_listen_raw) {
log_info("Listening on a socket...");
r = setup_raw_socket(s, arg_listen_raw);
if (r < 0)
return r;
}
if (arg_listen_http) {
r = setup_microhttpd_socket(s, arg_listen_http, NULL, NULL, NULL);
if (r < 0)
return r;
}
if (arg_listen_https) {
r = setup_microhttpd_socket(s, arg_listen_https, key, cert, trust);
if (r < 0)
return r;
}
STRV_FOREACH(file, arg_files) {
const char *output_name;
if (streq(*file, "-")) {
log_info("Using standard input as source.");
fd = STDIN_FILENO;
output_name = "stdin";
} else {
log_info("Reading file %s...", *file);
fd = open(*file, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
if (fd < 0) {
log_error("Failed to open %s: %m", *file);
return -errno;
}
output_name = *file;
}
r = add_source(s, fd, (char*) output_name, false);
if (r < 0)
return r;
}
if (s->active == 0) {
log_error("Zarro sources specified");
return -EINVAL;
}
if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE) {
/* In this case we know what the writer will be
called, so we can create it and verify that we can
create output as expected. */
r = get_writer(s, NULL, &s->_single_writer);
if (r < 0)
return r;
}
return 0;
}
static void server_destroy(RemoteServer *s) {
size_t i;
MHDDaemonWrapper *d;
while ((d = hashmap_steal_first(s->daemons))) {
MHD_stop_daemon(d->daemon);
sd_event_source_unref(d->event);
free(d);
}
hashmap_free(s->daemons);
assert(s->sources_size == 0 || s->sources);
for (i = 0; i < s->sources_size; i++)
remove_source(s, i);
free(s->sources);
writer_unref(s->_single_writer);
hashmap_free(s->writers);
sd_event_source_unref(s->sigterm_event);
sd_event_source_unref(s->sigint_event);
sd_event_source_unref(s->listen_event);
sd_event_unref(s->events);
/* fds that we're listening on remain open... */
}
/**********************************************************************
**********************************************************************
**********************************************************************/
static int dispatch_raw_source_event(sd_event_source *event,
int fd,
uint32_t revents,
void *userdata) {
RemoteServer *s = userdata;
RemoteSource *source;
int r;
assert(fd >= 0 && fd < (ssize_t) s->sources_size);
source = s->sources[fd];
assert(source->fd == fd);
r = process_source(source, arg_compress, arg_seal);
if (source->state == STATE_EOF) {
size_t remaining;
log_info("EOF reached with source fd:%d (%s)",
source->fd, source->name);
remaining = source_non_empty(source);
if (remaining > 0)
log_warning("Premature EOF. %zu bytes lost.", remaining);
remove_source(s, source->fd);
log_info("%zd active sources remaining", s->active);
return 0;
} else if (r == -E2BIG) {
log_error("Entry too big, skipped");
return 1;
} else if (r == -EAGAIN) {
return 0;
} else if (r < 0) {
log_info("Closing connection: %s", strerror(-r));
remove_source(server, fd);
return 0;
} else
return 1;
}
static int dispatch_blocking_source_event(sd_event_source *event,
void *userdata) {
RemoteSource *source = userdata;
return dispatch_raw_source_event(event, source->fd, EPOLLIN, server);
}
static int accept_connection(const char* type, int fd,
SocketAddress *addr, char **hostname) {
int fd2, r;
log_debug("Accepting new %s connection on fd:%d", type, fd);
fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (fd2 < 0) {
log_error("accept() on fd:%d failed: %m", fd);
return -errno;
}
switch(socket_address_family(addr)) {
case AF_INET:
case AF_INET6: {
_cleanup_free_ char *a = NULL;
char *b;
r = socket_address_print(addr, &a);
if (r < 0) {
log_error("socket_address_print(): %s", strerror(-r));
close(fd2);
return r;
}
r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
if (r < 0) {
close(fd2);
return r;
}
log_info("Accepted %s %s connection from %s",
type,
socket_address_family(addr) == AF_INET ? "IP" : "IPv6",
a);
*hostname = b;
return fd2;
};
default:
log_error("Rejected %s connection with unsupported family %d",
type, socket_address_family(addr));
close(fd2);
return -EINVAL;
}
}
static int dispatch_raw_connection_event(sd_event_source *event,
int fd,
uint32_t revents,
void *userdata) {
RemoteServer *s = userdata;
int fd2, r;
SocketAddress addr = {
.size = sizeof(union sockaddr_union),
.type = SOCK_STREAM,
};
char *hostname;
fd2 = accept_connection("raw", fd, &addr, &hostname);
if (fd2 < 0)
return fd2;
r = add_source(s, fd2, hostname, true);
if (r < 0)
free(hostname);
return r;
}
/**********************************************************************
**********************************************************************
**********************************************************************/
static const char* const journal_write_split_mode_table[_JOURNAL_WRITE_SPLIT_MAX] = {
[JOURNAL_WRITE_SPLIT_NONE] = "none",
[JOURNAL_WRITE_SPLIT_HOST] = "host",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(journal_write_split_mode, JournalWriteSplitMode);
static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode,
journal_write_split_mode,
JournalWriteSplitMode,
"Failed to parse split mode setting");
static int parse_config(void) {
const ConfigTableItem items[] = {
{ "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode },
{ "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key },
{ "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert },
{ "Remote", "TrustedCertificateFile", config_parse_path, 0, &arg_trust },
{}};
return config_parse(NULL, PKGSYSCONFDIR "/journal-remote.conf", NULL,
"Remote\0",
config_item_table_lookup, items,
false, false, true, NULL);
}
static void help(void) {
printf("%s [OPTIONS...] {FILE|-}...\n\n"
"Write external journal events to journal file(s).\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --url=URL Read events from systemd-journal-gatewayd at URL\n"
" --getter=COMMAND Read events from the output of COMMAND\n"
" --listen-raw=ADDR Listen for connections at ADDR\n"
" --listen-http=ADDR Listen for HTTP connections at ADDR\n"
" --listen-https=ADDR Listen for HTTPS connections at ADDR\n"
" -o --output=FILE|DIR Write output to FILE or DIR/external-*.journal\n"
" --compress[=BOOL] Use XZ-compression in the output journal (default: yes)\n"
" --seal[=BOOL] Use Event sealing in the output journal (default: no)\n"
" --key=FILENAME Specify key in PEM format (default:\n"
" \"" PRIV_KEY_FILE "\")\n"
" --cert=FILENAME Specify certificate in PEM format (default:\n"
" \"" CERT_FILE "\")\n"
" --trust=FILENAME|all Specify CA certificate or disable checking (default:\n"
" \"" TRUST_FILE "\")\n"
" --gnutls-log=CATEGORY...\n"
" Specify a list of gnutls logging categories\n"
"\n"
"Note: file descriptors from sd_listen_fds() will be consumed, too.\n"
, program_invocation_short_name);
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_URL,
ARG_LISTEN_RAW,
ARG_LISTEN_HTTP,
ARG_LISTEN_HTTPS,
ARG_GETTER,
ARG_SPLIT_MODE,
ARG_COMPRESS,
ARG_SEAL,
ARG_KEY,
ARG_CERT,
ARG_TRUST,
ARG_GNUTLS_LOG,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "url", required_argument, NULL, ARG_URL },
{ "getter", required_argument, NULL, ARG_GETTER },
{ "listen-raw", required_argument, NULL, ARG_LISTEN_RAW },
{ "listen-http", required_argument, NULL, ARG_LISTEN_HTTP },
{ "listen-https", required_argument, NULL, ARG_LISTEN_HTTPS },
{ "output", required_argument, NULL, 'o' },
{ "split-mode", required_argument, NULL, ARG_SPLIT_MODE },
{ "compress", optional_argument, NULL, ARG_COMPRESS },
{ "seal", optional_argument, NULL, ARG_SEAL },
{ "key", required_argument, NULL, ARG_KEY },
{ "cert", required_argument, NULL, ARG_CERT },
{ "trust", required_argument, NULL, ARG_TRUST },
{ "gnutls-log", required_argument, NULL, ARG_GNUTLS_LOG },
{}
};
int c, r;
bool type_a, type_b;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "ho:", options, NULL)) >= 0)
switch(c) {
case 'h':
help();
return 0 /* done */;
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0 /* done */;
case ARG_URL:
if (arg_url) {
log_error("cannot currently set more than one --url");
return -EINVAL;
}
arg_url = optarg;
break;
case ARG_GETTER:
if (arg_getter) {
log_error("cannot currently use --getter more than once");
return -EINVAL;
}
arg_getter = optarg;
break;
case ARG_LISTEN_RAW:
if (arg_listen_raw) {
log_error("cannot currently use --listen-raw more than once");
return -EINVAL;
}
arg_listen_raw = optarg;
break;
case ARG_LISTEN_HTTP:
if (arg_listen_http || http_socket >= 0) {
log_error("cannot currently use --listen-http more than once");
return -EINVAL;
}
r = fd_fd(optarg);
if (r >= 0)
http_socket = r;
else
arg_listen_http = optarg;
break;
case ARG_LISTEN_HTTPS:
if (arg_listen_https || https_socket >= 0) {
log_error("cannot currently use --listen-https more than once");
return -EINVAL;
}
r = fd_fd(optarg);
if (r >= 0)
https_socket = r;
else
arg_listen_https = optarg;
break;
case ARG_KEY:
if (arg_key) {
log_error("Key file specified twice");
return -EINVAL;
}
arg_key = strdup(optarg);
if (!arg_key)
return log_oom();
break;
case ARG_CERT:
if (arg_cert) {
log_error("Certificate file specified twice");
return -EINVAL;
}
arg_cert = strdup(optarg);
if (!arg_cert)
return log_oom();
break;
case ARG_TRUST:
if (arg_trust || arg_trust_all) {
log_error("Confusing trusted CA configuration");
return -EINVAL;
}
if (streq(optarg, "all"))
arg_trust_all = true;
else {
#ifdef HAVE_GNUTLS
arg_trust = strdup(optarg);
if (!arg_trust)
return log_oom();
#else
log_error("Option --trust is not available.");
return -EINVAL;
#endif
}
break;
case 'o':
if (arg_output) {
log_error("cannot use --output/-o more than once");
return -EINVAL;
}
arg_output = optarg;
break;
case ARG_SPLIT_MODE:
arg_split_mode = journal_write_split_mode_from_string(optarg);
if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) {
log_error("Invalid split mode: %s", optarg);
return -EINVAL;
}
break;
case ARG_COMPRESS:
if (optarg) {
r = parse_boolean(optarg);
if (r < 0) {
log_error("Failed to parse --compress= parameter.");
return -EINVAL;
}
arg_compress = !!r;
} else
arg_compress = true;
break;
case ARG_SEAL:
if (optarg) {
r = parse_boolean(optarg);
if (r < 0) {
log_error("Failed to parse --seal= parameter.");
return -EINVAL;
}
arg_seal = !!r;
} else
arg_seal = true;
break;
case ARG_GNUTLS_LOG: {
#ifdef HAVE_GNUTLS
const char *word, *state;
size_t size;
FOREACH_WORD_SEPARATOR(word, size, optarg, ",", state) {
char *cat;
cat = strndup(word, size);
if (!cat)
return log_oom();
if (strv_consume(&arg_gnutls_log, cat) < 0)
return log_oom();
}
break;
#else
log_error("Option --gnutls-log is not available.");
return -EINVAL;
#endif
}
case '?':
return -EINVAL;
default:
assert_not_reached("Unknown option code.");
}
if (optind < argc)
arg_files = argv + optind;
type_a = arg_getter || !strv_isempty(arg_files);
type_b = arg_url
|| arg_listen_raw
|| arg_listen_http || arg_listen_https
|| sd_listen_fds(false) > 0;
if (type_a && type_b) {
log_error("Cannot use file input or --getter with "
"--arg-listen-... or socket activation.");
return -EINVAL;
}
if (type_a) {
if (!arg_output) {
log_error("Option --output must be specified with file input or --getter.");
return -EINVAL;
}
arg_split_mode = JOURNAL_WRITE_SPLIT_NONE;
}
if (arg_split_mode == JOURNAL_WRITE_SPLIT_NONE
&& arg_output && is_dir(arg_output, true) > 0) {
log_error("For SplitMode=none, output must be a file.");
return -EINVAL;
}
if (arg_split_mode == JOURNAL_WRITE_SPLIT_HOST
&& arg_output && is_dir(arg_output, true) <= 0) {
log_error("For SplitMode=host, output must be a directory.");
return -EINVAL;
}
log_debug("Full config: SplitMode=%s Key=%s Cert=%s Trust=%s",
journal_write_split_mode_to_string(arg_split_mode),
strna(arg_key),
strna(arg_cert),
strna(arg_trust));
return 1 /* work to do */;
}
static int load_certificates(char **key, char **cert, char **trust) {
int r;
r = read_full_file(arg_key ?: PRIV_KEY_FILE, key, NULL);
if (r < 0) {
log_error("Failed to read key from file '%s': %s",
arg_key ?: PRIV_KEY_FILE, strerror(-r));
return r;
}
r = read_full_file(arg_cert ?: CERT_FILE, cert, NULL);
if (r < 0) {
log_error("Failed to read certificate from file '%s': %s",
arg_cert ?: CERT_FILE, strerror(-r));
return r;
}
if (arg_trust_all)
log_info("Certificate checking disabled.");
else {
r = read_full_file(arg_trust ?: TRUST_FILE, trust, NULL);
if (r < 0) {
log_error("Failed to read CA certificate file '%s': %s",
arg_trust ?: TRUST_FILE, strerror(-r));
return r;
}
}
return 0;
}
static int setup_gnutls_logger(char **categories) {
if (!arg_listen_http && !arg_listen_https)
return 0;
#ifdef HAVE_GNUTLS
{
char **cat;
int r;
gnutls_global_set_log_function(log_func_gnutls);
if (categories)
STRV_FOREACH(cat, categories) {
r = log_enable_gnutls_category(*cat);
if (r < 0)
return r;
}
else
log_reset_gnutls_level();
}
#endif
return 0;
}
int main(int argc, char **argv) {
RemoteServer s = {};
int r;
_cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL;
log_show_color(true);
log_parse_environment();
r = parse_config();
if (r < 0)
return EXIT_FAILURE;
r = parse_argv(argc, argv);
if (r <= 0)
return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
r = setup_gnutls_logger(arg_gnutls_log);
if (r < 0)
return EXIT_FAILURE;
if (arg_listen_https || https_socket >= 0)
if (load_certificates(&key, &cert, &trust) < 0)
return EXIT_FAILURE;
if (remoteserver_init(&s, key, cert, trust) < 0)
return EXIT_FAILURE;
sd_event_set_watchdog(s.events, true);
log_debug("%s running as pid "PID_FMT,
program_invocation_short_name, getpid());
sd_notify(false,
"READY=1\n"
"STATUS=Processing requests...");
while (s.active) {
r = sd_event_get_state(s.events);
if (r < 0)
break;
if (r == SD_EVENT_FINISHED)
break;
r = sd_event_run(s.events, -1);
if (r < 0) {
log_error("Failed to run event loop: %s", strerror(-r));
break;
}
}
sd_notifyf(false,
"STOPPING=1\n"
"STATUS=Shutting down after writing %" PRIu64 " entries...", s.event_count);
log_info("Finishing after writing %" PRIu64 " entries", s.event_count);
server_destroy(&s);
free(arg_key);
free(arg_cert);
free(arg_trust);
return r >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}