for option syntax and details.</para>
</refsect1>
+ <refsect1>
+ <title>Credentials</title>
+
+ <para><command>systemd-network-generator</command> supports the service credentials logic as implemented
+ by
+ <varname>ImportCredential=</varname>/<varname>LoadCredential=</varname>/<varname>SetCredential=</varname>
+ (see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ details). The following credentials are used when passed in:</para>
+
+ <variablelist class='system-credentials'>
+ <varlistentry>
+ <term><varname>network.netdev.*</varname></term>
+ <term><varname>network.link.*</varname></term>
+ <term><varname>network.network.*</varname></term>
+
+ <listitem><para>These credentials should contain valid
+ <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ configuration data. From each matching credential a separate file is created. Example: a passed
+ credential <filename>network.link.50-foobar</filename> will be copied into a configuration file
+ <filename>50-foobar.link</filename>.</para>
+
+ <para>Note that the resulting files are created world-readable, it's hence recommended to not include
+ secrets in these credentials, but supply them via separate credentials directly to
+ <filename>systemd-networkd.service</filename>.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/></listitem>
+ </varlistentry>
+ </variablelist>
+
+ <para>Note that by default the <filename>systemd-network-generator.service</filename> unit file is set up
+ to inherit the these credentials from the service manager.</para>
+ </refsect1>
+
<refsect1>
<title>See Also</title>
<para><simplelist type="inline">
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>network.netdev.*</varname></term>
+ <term><varname>network.link.*</varname></term>
+ <term><varname>network.network.*</varname></term>
+ <listitem>
+ <para>Configures network devices. Read by
+ <citerefentry><refentrytitle>systemd-network-generator.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>. These
+ credentials directly translate to a matching <filename>*.netdev</filename>,
+ <filename>*.link</filename> or <filename>*.network</filename> file. Example: the contents of a
+ credential <filename>network.link.50-foobar</filename> will be copied into a file
+ <filename>50-foobar.link</filename>. See
+ <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for details.</para>
+
+ <para>Note that the resulting files are created world-readable, it's hence recommended to not include
+ secrets in these credentials, but supply them via separate credentials directly to
+ <filename>systemd-networkd.service</filename>.</para>
+
+ <xi:include href="version-info.xml" xpointer="v256"/>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><varname>passwd.hashed-password.root</varname></term>
<term><varname>passwd.plaintext-password.root</varname></term>
#include <getopt.h>
#include "build.h"
+#include "copy.h"
+#include "creds-util.h"
#include "fd-util.h"
#include "fs-util.h"
#include "generator.h"
#include "network-generator.h"
#include "path-util.h"
#include "proc-cmdline.h"
+#include "recurse-dir.h"
#define NETWORKD_UNIT_DIRECTORY "/run/systemd/network"
return r;
}
+static int pick_up_credentials(void) {
+ _cleanup_close_ int credential_dir_fd = -EBADF;
+ int r, ret = 0;
+
+ credential_dir_fd = open_credentials_dir();
+ if (IN_SET(credential_dir_fd, -ENXIO, -ENOENT)) /* Credential env var not set, or dir doesn't exist. */
+ return 0;
+ if (credential_dir_fd < 0)
+ return log_error_errno(credential_dir_fd, "Failed to open credentials directory: %m");
+
+ _cleanup_free_ DirectoryEntries *des = NULL;
+ r = readdir_all(credential_dir_fd, RECURSE_DIR_SORT|RECURSE_DIR_IGNORE_DOT|RECURSE_DIR_ENSURE_TYPE, &des);
+ if (r < 0)
+ return log_error_errno(r, "Failed to enumerate credentials: %m");
+
+ FOREACH_ARRAY(i, des->entries, des->n_entries) {
+ static const struct {
+ const char *credential_prefix;
+ const char *filename_suffix;
+ } table[] = {
+ { "network.link.", ".link" },
+ { "network.netdev.", ".netdev" },
+ { "network.network.", ".network" },
+ };
+
+ _cleanup_free_ char *fn = NULL;
+ struct dirent *de = *i;
+
+ if (de->d_type != DT_REG)
+ continue;
+
+ FOREACH_ARRAY(t, table, ELEMENTSOF(table)) {
+ const char *e = startswith(de->d_name, t->credential_prefix);
+
+ if (e) {
+ fn = strjoin(e, t->filename_suffix);
+ if (!fn)
+ return log_oom();
+
+ break;
+ }
+ }
+
+ if (!fn)
+ continue;
+
+ if (!filename_is_valid(fn)) {
+ log_warning("Passed credential '%s' would result in invalid filename '%s', ignoring.", de->d_name, fn);
+ continue;
+ }
+
+ _cleanup_free_ char *output = path_join(NETWORKD_UNIT_DIRECTORY, fn);
+ if (!output)
+ return log_oom();
+
+ r = copy_file_at(
+ credential_dir_fd, de->d_name,
+ AT_FDCWD, output,
+ /* open_flags= */ 0,
+ 0644,
+ /* flags= */ 0);
+ if (r < 0)
+ RET_GATHER(ret, log_warning_errno(r, "Failed to copy credential %s → file %s: %m", de->d_name, output));
+ else
+ log_info("Installed %s from credential.", output);
+ }
+
+ return ret;
+}
+
static int help(void) {
printf("%s [OPTIONS...] [-- KERNEL_CMDLINE]\n"
" -h --help Show this help\n"
static int run(int argc, char *argv[]) {
_cleanup_(context_clear) Context context = {};
- int r;
+ int r, ret = 0;
log_setup();
if (r < 0)
return log_warning_errno(r, "Failed to merge multiple command line options: %m");
- return context_save(&context);
+ RET_GATHER(ret, context_save(&context));
+ RET_GATHER(ret, pick_up_credentials());
+
+ return ret;
}
DEFINE_MAIN_FUNCTION(run);
--- /dev/null
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+# shellcheck disable=SC2016
+set -eux
+set -o pipefail
+
+at_exit() {
+ rm -f /run/credstore/network.network.50-testme
+ rm -f /run/systemd/system/systemd-network-generator.service.d/50-testme.conf
+}
+
+trap at_exit EXIT
+
+mkdir -p /run/credstore
+cat > /run/credstore/network.network.50-testme <<EOF
+[Match]
+Property=IDONTEXIST
+EOF
+
+systemctl edit systemd-network-generator.service --stdin --drop-in=50-testme.conf <<EOF
+[Service]
+LoadCredential=network.network.50-testme
+EOF
+
+systemctl restart systemd-network-generator
+
+test -f /run/systemd/network/50-testme.network
Type=oneshot
RemainAfterExit=yes
ExecStart={{LIBEXECDIR}}/systemd-network-generator
+ImportCredential=network.netdev.*
+ImportCredential=network.link.*
+ImportCredential=network.network.*
[Install]
WantedBy=sysinit.target