diff --git a/meson.build b/meson.build index 287456ad6e..95d95c43cd 100644 --- a/meson.build +++ b/meson.build @@ -1181,6 +1181,7 @@ libmicrohttpd = dependency('libmicrohttpd', version : '>= 0.9.33', required : get_option('microhttpd')) conf.set10('HAVE_MICROHTTPD', libmicrohttpd.found()) +libmicrohttpd_cflags = libmicrohttpd.partial_dependency(includes: true, compile_args: true) libcryptsetup = get_option('libcryptsetup') libcryptsetup_plugins = get_option('libcryptsetup-plugins') @@ -1252,6 +1253,7 @@ libgnutls = dependency('gnutls', version : '>= 3.1.4', required : get_option('gnutls')) conf.set10('HAVE_GNUTLS', libgnutls.found()) +libgnutls_cflags = libgnutls.partial_dependency(includes: true, compile_args: true) libopenssl = dependency('openssl', version : '>= 3.0.0', diff --git a/mkosi/mkosi.conf.d/centos-fedora/mkosi.conf b/mkosi/mkosi.conf.d/centos-fedora/mkosi.conf index dd00fa737c..fc9ffd58c9 100644 --- a/mkosi/mkosi.conf.d/centos-fedora/mkosi.conf +++ b/mkosi/mkosi.conf.d/centos-fedora/mkosi.conf @@ -43,6 +43,7 @@ Packages= kernel-core knot libcap-ng-utils + libmicrohttpd libucontext man-db nmap-ncat diff --git a/mkosi/mkosi.conf.d/opensuse/mkosi.conf b/mkosi/mkosi.conf.d/opensuse/mkosi.conf index b0593e3f1a..1198d2c15c 100644 --- a/mkosi/mkosi.conf.d/opensuse/mkosi.conf +++ b/mkosi/mkosi.conf.d/opensuse/mkosi.conf @@ -57,6 +57,7 @@ Packages= libcap-progs libdw-devel libdw1 + libmicrohttpd12 libtss2-tcti-device0 libz1 man diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 7cb8846224..42e3f6df29 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -311,7 +311,7 @@ static int request_parse_accept( assert(m); assert(connection); - header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Accept"); + header = sym_MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Accept"); if (!header) return 0; @@ -459,7 +459,7 @@ static int request_parse_range( assert(m); assert(connection); - range = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Range"); + range = sym_MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Range"); if (!range) return 0; @@ -566,7 +566,7 @@ static int request_parse_arguments( assert(connection); m->argument_parse_error = 0; - MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, request_parse_arguments_iterator, m); + sym_MHD_get_connection_values(connection, MHD_GET_ARGUMENT_KIND, request_parse_arguments_iterator, m); return m->argument_parse_error; } @@ -616,14 +616,14 @@ static int request_handler_entries( if (r < 0) return mhd_respond(connection, MHD_HTTP_BAD_REQUEST, "Failed to seek in journal."); - response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 4*1024, request_reader_entries, m, NULL); + response = sym_MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 4*1024, request_reader_entries, m, NULL); if (!response) return respond_oom(connection); - if (MHD_add_response_header(response, "Content-Type", mime_types[m->mode]) == MHD_NO) + if (sym_MHD_add_response_header(response, "Content-Type", mime_types[m->mode]) == MHD_NO) return respond_oom(connection); - return MHD_queue_response(connection, MHD_HTTP_OK, response); + return sym_MHD_queue_response(connection, MHD_HTTP_OK, response); } static int output_field(FILE *f, OutputMode m, const char *d, size_t l) { @@ -744,14 +744,14 @@ static int request_handler_fields( if (r < 0) return mhd_respond(connection, MHD_HTTP_BAD_REQUEST, "Failed to query unique fields."); - response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 4*1024, request_reader_fields, m, NULL); + response = sym_MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 4*1024, request_reader_fields, m, NULL); if (!response) return respond_oom(connection); - if (MHD_add_response_header(response, "Content-Type", mime_types[m->mode == OUTPUT_JSON ? OUTPUT_JSON : OUTPUT_SHORT]) == MHD_NO) + if (sym_MHD_add_response_header(response, "Content-Type", mime_types[m->mode == OUTPUT_JSON ? OUTPUT_JSON : OUTPUT_SHORT]) == MHD_NO) return respond_oom(connection); - return MHD_queue_response(connection, MHD_HTTP_OK, response); + return sym_MHD_queue_response(connection, MHD_HTTP_OK, response); } static int request_handler_redirect( @@ -767,16 +767,16 @@ static int request_handler_redirect( if (asprintf(&page, "
Please continue to the journal browser.", target) < 0) return respond_oom(connection); - response = MHD_create_response_from_buffer(strlen(page), page, MHD_RESPMEM_MUST_FREE); + response = sym_MHD_create_response_from_buffer(strlen(page), page, MHD_RESPMEM_MUST_FREE); if (!response) return respond_oom(connection); TAKE_PTR(page); - if (MHD_add_response_header(response, "Content-Type", "text/html") == MHD_NO || - MHD_add_response_header(response, "Location", target) == MHD_NO) + if (sym_MHD_add_response_header(response, "Content-Type", "text/html") == MHD_NO || + sym_MHD_add_response_header(response, "Location", target) == MHD_NO) return respond_oom(connection); - return MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY, response); + return sym_MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY, response); } static int request_handler_file( @@ -799,15 +799,15 @@ static int request_handler_file( if (fstat(fd, &st) < 0) return mhd_respondf(connection, errno, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to stat file: %m"); - response = MHD_create_response_from_fd_at_offset64(st.st_size, fd, 0); + response = sym_MHD_create_response_from_fd_at_offset64(st.st_size, fd, 0); if (!response) return respond_oom(connection); TAKE_FD(fd); - if (MHD_add_response_header(response, "Content-Type", mime_type) == MHD_NO) + if (sym_MHD_add_response_header(response, "Content-Type", mime_type) == MHD_NO) return respond_oom(connection); - return MHD_queue_response(connection, MHD_HTTP_OK, response); + return sym_MHD_queue_response(connection, MHD_HTTP_OK, response); } static int get_virtualization(char **v) { @@ -899,15 +899,15 @@ static int request_handler_machine( if (r < 0) return respond_oom(connection); - response = MHD_create_response_from_buffer(strlen(json), json, MHD_RESPMEM_MUST_FREE); + response = sym_MHD_create_response_from_buffer(strlen(json), json, MHD_RESPMEM_MUST_FREE); if (!response) return respond_oom(connection); TAKE_PTR(json); - if (MHD_add_response_header(response, "Content-Type", "application/json") == MHD_NO) + if (sym_MHD_add_response_header(response, "Content-Type", "application/json") == MHD_NO) return respond_oom(connection); - return MHD_queue_response(connection, MHD_HTTP_OK, response); + return sym_MHD_queue_response(connection, MHD_HTTP_OK, response); } static int output_boot(FILE *f, LogId boot, int boot_display_index) { @@ -1026,14 +1026,14 @@ static int request_handler_boots( if (r < 0) return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to seek in journal: %m"); - response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 4*1024, request_reader_boots, m, NULL); + response = sym_MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 4*1024, request_reader_boots, m, NULL); if (!response) return respond_oom(connection); - if (MHD_add_response_header(response, "Content-Type", "application/json-seq") == MHD_NO) + if (sym_MHD_add_response_header(response, "Content-Type", "application/json-seq") == MHD_NO) return respond_oom(connection); - return MHD_queue_response(connection, MHD_HTTP_OK, response); + return sym_MHD_queue_response(connection, MHD_HTTP_OK, response); } static mhd_result request_handler( @@ -1290,6 +1290,10 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; + r = dlopen_microhttpd(LOG_ERR); + if (r < 0) + return r; + journal_browse_prepare(); assert_se(sigaction(SIGTERM, &sigterm, NULL) >= 0); @@ -1323,11 +1327,16 @@ static int run(int argc, char *argv[]) { { MHD_OPTION_HTTPS_MEM_TRUST, 0, arg_trust_pem }; } - d = MHD_start_daemon(flags, 19531, - NULL, NULL, - request_handler, NULL, - MHD_OPTION_ARRAY, opts, - MHD_OPTION_END); + d = sym_MHD_start_daemon( + flags, + /* port= */ 19531, + /* acp= */ NULL, + /* acp_cls= */ NULL, + request_handler, + /* dh_cls= */ NULL, + MHD_OPTION_ARRAY, + opts, + MHD_OPTION_END); if (!d) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to start daemon!"); diff --git a/src/journal-remote/journal-remote-main.c b/src/journal-remote/journal-remote-main.c index 4867bf3609..1fbcc27815 100644 --- a/src/journal-remote/journal-remote-main.c +++ b/src/journal-remote/journal-remote-main.c @@ -108,7 +108,7 @@ static MHDDaemonWrapper* MHDDaemonWrapper_free(MHDDaemonWrapper *d) { d->timer_event = sd_event_source_unref(d->timer_event); if (d->daemon) - MHD_stop_daemon(d->daemon); + sym_MHD_stop_daemon(d->daemon); return mfree(d); } @@ -361,7 +361,7 @@ static mhd_result request_handler( if (*connection_cls) { RemoteSource *source = *connection_cls; - header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Encoding"); + header = sym_MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Encoding"); if (header) { Compression c = compression_from_string_harder(header); if (c <= 0 || !compression_supported(c)) @@ -382,12 +382,12 @@ static mhd_result request_handler( if (!streq(url, "/upload")) return mhd_respond(connection, MHD_HTTP_NOT_FOUND, "Not found."); - header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Type"); + header = sym_MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Type"); if (!header || !streq(header, "application/vnd.fdo.journal")) return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE, "Content-Type: application/vnd.fdo.journal is required."); - header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Transfer-Encoding"); + header = sym_MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Transfer-Encoding"); if (header) { if (!strcaseeq(header, "chunked")) return mhd_respondf(connection, 0, MHD_HTTP_BAD_REQUEST, @@ -396,7 +396,7 @@ static mhd_result request_handler( chunked = true; } - header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Length"); + header = sym_MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Length"); if (header) { size_t len; @@ -420,8 +420,8 @@ static mhd_result request_handler( { const union MHD_ConnectionInfo *ci; - ci = MHD_get_connection_info(connection, - MHD_CONNECTION_INFO_CONNECTION_FD); + ci = sym_MHD_get_connection_info(connection, + MHD_CONNECTION_INFO_CONNECTION_FD); if (!ci) { log_error("MHD_get_connection_info failed: cannot get remote fd"); return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, @@ -464,6 +464,12 @@ static int setup_microhttpd_server(RemoteServer *s, const char *trust) { #if HAVE_MICROHTTPD + int r; + + r = dlopen_microhttpd(LOG_ERR); + if (r < 0) + return r; + struct MHD_OptionItem opts[] = { { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger}, { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free}, @@ -483,7 +489,7 @@ static int setup_microhttpd_server(RemoteServer *s, _cleanup_(MHDDaemonWrapper_freep) MHDDaemonWrapper *d = NULL; const union MHD_DaemonInfo *info; - int r, epoll_fd; + int epoll_fd; assert(fd >= 0); @@ -526,18 +532,23 @@ static int setup_microhttpd_server(RemoteServer *s, d->fd = (uint64_t) fd; - d->daemon = MHD_start_daemon(flags, 0, - NULL, NULL, - request_handler, NULL, - MHD_OPTION_ARRAY, opts, - MHD_OPTION_END); + d->daemon = sym_MHD_start_daemon( + flags, + /* port= */ 0, + /* acp= */ NULL, + /* acp_cls= */ NULL, + request_handler, + /* dh_cls= */ NULL, + MHD_OPTION_ARRAY, + opts, + MHD_OPTION_END); if (!d->daemon) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to start μhttp daemon"); log_debug("Started MHD %s daemon on fd:%d (wrapper @ %p)", key ? "HTTPS" : "HTTP", fd, d); - info = MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY); + info = sym_MHD_get_daemon_info(d->daemon, MHD_DAEMON_INFO_EPOLL_FD_LINUX_ONLY); if (!info) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "μhttp returned NULL daemon info"); @@ -609,12 +620,12 @@ static int dispatch_http_event(sd_event_source *event, int r; MHD_UNSIGNED_LONG_LONG timeout = ULLONG_MAX; - r = MHD_run(d->daemon); + r = sym_MHD_run(d->daemon); if (r == MHD_NO) // FIXME: unregister daemon return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "MHD_run failed!"); - if (MHD_get_timeout(d->daemon, &timeout) == MHD_NO) + if (sym_MHD_get_timeout(d->daemon, &timeout) == MHD_NO) timeout = ULLONG_MAX; r = sd_event_source_set_time(d->timer_event, timeout); diff --git a/src/journal-remote/meson.build b/src/journal-remote/meson.build index c8d97526d3..f6aa71349c 100644 --- a/src/journal-remote/meson.build +++ b/src/journal-remote/meson.build @@ -3,9 +3,6 @@ systemd_journal_gatewayd_sources = files( 'journal-gatewayd.c', ) -systemd_journal_gatewayd_extract_sources = files( - 'microhttpd-util.c', -) systemd_journal_remote_sources = files('journal-remote-main.c') systemd_journal_remote_extract_sources = files( @@ -24,7 +21,7 @@ systemd_journal_upload_extract_sources = files( ) common_deps = [ - libgnutls, + libgnutls_cflags, liblz4_cflags, libxz_cflags, libzstd_cflags, @@ -40,8 +37,7 @@ executables += [ 'HAVE_MICROHTTPD', ], 'sources' : systemd_journal_gatewayd_sources, - 'extract' : systemd_journal_gatewayd_extract_sources, - 'dependencies' : common_deps + [libmicrohttpd], + 'dependencies' : common_deps + [libmicrohttpd_cflags], }, libexec_template + { 'name' : 'systemd-journal-remote', @@ -52,8 +48,7 @@ executables += [ 'install' : conf.get('ENABLE_REMOTE') == 1, 'sources' : systemd_journal_remote_sources, 'extract' : systemd_journal_remote_extract_sources, - 'objects' : conf.get('HAVE_MICROHTTPD') == 1 ? ['systemd-journal-gatewayd'] : [], - 'dependencies' : common_deps + [libmicrohttpd], + 'dependencies' : common_deps + [libmicrohttpd_cflags], }, libexec_template + { 'name' : 'systemd-journal-upload', @@ -75,7 +70,7 @@ executables += [ fuzz_template + { 'sources' : files('fuzz-journal-remote.c'), 'objects' : ['systemd-journal-remote'], - 'dependencies' : common_deps + [libmicrohttpd], + 'dependencies' : common_deps + [libmicrohttpd_cflags], }, ] diff --git a/src/shared/gnutls-util.c b/src/shared/gnutls-util.c new file mode 100644 index 0000000000..1f17c4f5a1 --- /dev/null +++ b/src/shared/gnutls-util.c @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "sd-dlopen.h" + +#include "gnutls-util.h" +#include "log.h" /* IWYU pragma: keep */ + +#if HAVE_GNUTLS +static void *gnutls_dl = NULL; + +DLSYM_PROTOTYPE(gnutls_certificate_get_peers) = NULL; +DLSYM_PROTOTYPE(gnutls_certificate_type_get) = NULL; +DLSYM_PROTOTYPE(gnutls_certificate_verification_status_print) = NULL; +DLSYM_PROTOTYPE(gnutls_certificate_verify_peers2) = NULL; +DLSYM_PROTOTYPE(gnutls_free) = NULL; +DLSYM_PROTOTYPE(gnutls_global_set_log_function) = NULL; +DLSYM_PROTOTYPE(gnutls_global_set_log_level) = NULL; +DLSYM_PROTOTYPE(gnutls_x509_crt_deinit) = NULL; +DLSYM_PROTOTYPE(gnutls_x509_crt_get_dn) = NULL; +DLSYM_PROTOTYPE(gnutls_x509_crt_import) = NULL; +DLSYM_PROTOTYPE(gnutls_x509_crt_init) = NULL; +#endif + +int dlopen_gnutls(int log_level) { +#if HAVE_GNUTLS + SD_ELF_NOTE_DLOPEN( + "gnutls", + "Support for TLS via GnuTLS", + SD_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED, + "libgnutls.so.30"); + + return dlopen_many_sym_or_warn( + &gnutls_dl, + "libgnutls.so.30", + log_level, + DLSYM_ARG(gnutls_certificate_get_peers), + DLSYM_ARG(gnutls_certificate_type_get), + DLSYM_ARG(gnutls_certificate_verification_status_print), + DLSYM_ARG(gnutls_certificate_verify_peers2), + DLSYM_ARG(gnutls_free), + DLSYM_ARG(gnutls_global_set_log_function), + DLSYM_ARG(gnutls_global_set_log_level), + DLSYM_ARG(gnutls_x509_crt_deinit), + DLSYM_ARG(gnutls_x509_crt_get_dn), + DLSYM_ARG(gnutls_x509_crt_import), + DLSYM_ARG(gnutls_x509_crt_init)); +#else + return log_full_errno(log_level, SYNTHETIC_ERRNO(EOPNOTSUPP), + "gnutls support is not compiled in."); +#endif +} diff --git a/src/shared/gnutls-util.h b/src/shared/gnutls-util.h new file mode 100644 index 0000000000..a110b437c3 --- /dev/null +++ b/src/shared/gnutls-util.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "shared-forward.h" + +int dlopen_gnutls(int log_level); + +#if HAVE_GNUTLS +# include