1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-25 18:50:18 +03:00

udev/net: introduce WakeOnLanPassword=

Closes #20913.
This commit is contained in:
Yu Watanabe 2021-10-06 21:49:58 +09:00
parent 9bd3ecdd8d
commit d3867133f0
5 changed files with 186 additions and 3 deletions

View File

@ -537,8 +537,17 @@
<varlistentry>
<term><option>secureon</option></term>
<listitem>
<para>Enable secureon(tm) password for MagicPacket(tm).
</para>
<para>Enable SecureOn password for MagicPacket. Implied when
<varname>WakeOnLanPassword=</varname> is specified. If specified without
<varname>WakeOnLanPassword=</varname> option, then the password is read from the
credential <literal><replaceable>LINK</replaceable>.link.wol.password</literal> (e.g.,
<literal>60-foo.link.wol.password</literal>), and if the credential not found, then
read from <literal>wol.password</literal>. See
<varname>LoadCredential=</varname>/<varname>SetCredential=</varname> in
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>1</manvolnum></citerefentry>
for details. The password in the credential, must be 6 bytes in hex format with each
byte separated by a colon (<literal>:</literal>) like an Ethernet MAC address, e.g.,
<literal>aa:bb:cc:dd:ee:ff</literal>.</para>
</listitem>
</varlistentry>
</variablelist>
@ -548,6 +557,19 @@
cleared.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>WakeOnLanPassword=</varname></term>
<listitem>
<para>Specifies the SecureOn password for MagicPacket. Takes an absolute path to a regular
file or an <constant>AF_UNIX</constant> stream socket, or the plain password. When a path to
a regular file is specified, the password is read from it. When an
<constant>AF_UNIX</constant> stream socket is specified, a connection is made to it and the
password is read from it. The password must be 6 bytes in hex format with each byte separated
by a colon (<literal>:</literal>) like an Ethernet MAC address, e.g.,
<literal>aa:bb:cc:dd:ee:ff</literal>. This implies <varname>WakeOnLan=secureon</varname>.
Defaults to unset, and the current value will not be changed.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Port=</varname></term>
<listitem>

View File

@ -49,6 +49,7 @@ Link.BitsPerSecond, config_parse_si_uint64,
Link.Duplex, config_parse_duplex, 0, offsetof(LinkConfig, duplex)
Link.AutoNegotiation, config_parse_tristate, 0, offsetof(LinkConfig, autonegotiation)
Link.WakeOnLan, config_parse_wol, 0, offsetof(LinkConfig, wol)
Link.WakeOnLanPassword, config_parse_wol_password, 0, 0
Link.Port, config_parse_port, 0, offsetof(LinkConfig, port)
Link.ReceiveChecksumOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_RXCSUM])
Link.TransmitChecksumOffload, config_parse_tristate, 0, offsetof(LinkConfig, features[NET_DEV_FEAT_TXCSUM])

View File

@ -10,11 +10,13 @@
#include "alloc-util.h"
#include "conf-files.h"
#include "conf-parser.h"
#include "creds-util.h"
#include "def.h"
#include "device-private.h"
#include "device-util.h"
#include "ethtool-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "link-config.h"
#include "log.h"
#include "memory-util.h"
@ -56,6 +58,8 @@ static LinkConfig* link_config_free(LinkConfig *link) {
strv_free(link->alternative_names);
free(link->alternative_names_policy);
free(link->alias);
free(link->wol_password_file);
erase_and_free(link->wol_password);
return mfree(link);
}
@ -101,6 +105,108 @@ int link_config_ctx_new(LinkConfigContext **ret) {
return 0;
}
static int link_parse_wol_password(LinkConfig *link, const char *str) {
_cleanup_(erase_and_freep) uint8_t *p = NULL;
int r;
assert(link);
assert(str);
assert_cc(sizeof(struct ether_addr) == SOPASS_MAX);
p = new(uint8_t, SOPASS_MAX);
if (!p)
return -ENOMEM;
/* Reuse ether_addr_from_string(), as their formats are equivalent. */
r = ether_addr_from_string(str, (struct ether_addr*) p);
if (r < 0)
return r;
erase_and_free(link->wol_password);
link->wol_password = TAKE_PTR(p);
return 0;
}
static int link_read_wol_password_from_file(LinkConfig *link) {
_cleanup_(erase_and_freep) char *password = NULL;
int r;
assert(link);
if (!link->wol_password_file)
return 0;
r = read_full_file_full(
AT_FDCWD, link->wol_password_file, UINT64_MAX, SIZE_MAX,
READ_FULL_FILE_SECURE | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET,
NULL, &password, NULL);
if (r < 0)
return r;
return link_parse_wol_password(link, password);
}
static int link_read_wol_password_from_cred(LinkConfig *link) {
_cleanup_free_ char *base = NULL, *cred_name = NULL;
_cleanup_(erase_and_freep) char *password = NULL;
int r;
assert(link);
assert(link->filename);
if (link->wol == UINT32_MAX)
return 0; /* WakeOnLan= is not specified. */
if (!FLAGS_SET(link->wol, WAKE_MAGICSECURE))
return 0; /* secureon is not specified in WakeOnLan=. */
if (link->wol_password)
return 0; /* WakeOnLanPassword= is specified. */
if (link->wol_password_file)
return 0; /* a file name is specified in WakeOnLanPassword=, but failed to read it. */
r = path_extract_filename(link->filename, &base);
if (r < 0)
return r;
cred_name = strjoin(base, ".wol.password");
if (!cred_name)
return -ENOMEM;
r = read_credential(cred_name, (void**) &password, NULL);
if (r == -ENOENT)
r = read_credential("wol.password", (void**) &password, NULL);
if (r < 0)
return r;
return link_parse_wol_password(link, password);
}
static int link_adjust_wol_options(LinkConfig *link) {
int r;
assert(link);
r = link_read_wol_password_from_file(link);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
log_warning_errno(r, "Failed to read WakeOnLan password from %s, ignoring: %m", link->wol_password_file);
r = link_read_wol_password_from_cred(link);
if (r == -ENOMEM)
return log_oom();
if (r < 0)
log_warning_errno(r, "Failed to read WakeOnLan password from credential, ignoring: %m");
if (link->wol != UINT32_MAX && link->wol_password)
/* Enable WAKE_MAGICSECURE flag when WakeOnLanPassword=. Note that when
* WakeOnLanPassword= is set without WakeOnLan=, then ethtool_set_wol() enables
* WAKE_MAGICSECURE flag and other flags are not changed. */
link->wol |= WAKE_MAGICSECURE;
return 0;
}
int link_load_one(LinkConfigContext *ctx, const char *filename) {
_cleanup_(link_config_freep) LinkConfig *link = NULL;
_cleanup_free_ char *name = NULL;
@ -177,6 +283,10 @@ int link_load_one(LinkConfigContext *ctx, const char *filename) {
link->mac = mfree(link->mac);
}
r = link_adjust_wol_options(link);
if (r < 0)
return r;
log_debug("Parsed configuration file %s", filename);
LIST_PREPEND(links, ctx->links, TAKE_PTR(link));
@ -329,7 +439,7 @@ static int link_config_apply_ethtool_settings(int *ethtool_fd, const LinkConfig
port_to_string(config->port));
}
r = ethtool_set_wol(ethtool_fd, name, config->wol, NULL);
r = ethtool_set_wol(ethtool_fd, name, config->wol, config->wol_password);
if (r < 0) {
_cleanup_free_ char *str = NULL;
@ -782,6 +892,52 @@ int config_parse_txqueuelen(
return 0;
}
int config_parse_wol_password(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
LinkConfig *link = userdata;
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(userdata);
if (isempty(rvalue)) {
link->wol_password = erase_and_free(link->wol_password);
link->wol_password_file = mfree(link->wol_password_file);
return 0;
}
if (path_is_absolute(rvalue) && path_is_safe(rvalue)) {
link->wol_password = erase_and_free(link->wol_password);
return free_and_strdup_warn(&link->wol_password_file, rvalue);
}
warn_file_is_world_accessible(filename, NULL, unit, line);
r = link_parse_wol_password(link, rvalue);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse %s=, ignoring assignment: %s.", lvalue, rvalue);
return 0;
}
link->wol_password_file = mfree(link->wol_password_file);
return 0;
}
static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
[MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
[MAC_ADDRESS_POLICY_RANDOM] = "random",

View File

@ -58,6 +58,8 @@ struct LinkConfig {
int autonegotiation;
uint32_t advertise[N_ADVERTISE];
uint32_t wol;
char *wol_password_file;
uint8_t *wol_password;
NetDevPort port;
int features[_NET_DEV_FEAT_MAX];
netdev_channels channels;
@ -97,6 +99,7 @@ const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, GPERF_LEN
CONFIG_PARSER_PROTOTYPE(config_parse_ifalias);
CONFIG_PARSER_PROTOTYPE(config_parse_rx_tx_queues);
CONFIG_PARSER_PROTOTYPE(config_parse_txqueuelen);
CONFIG_PARSER_PROTOTYPE(config_parse_wol_password);
CONFIG_PARSER_PROTOTYPE(config_parse_mac_address_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_name_policy);
CONFIG_PARSER_PROTOTYPE(config_parse_alternative_names_policy);

View File

@ -28,6 +28,7 @@ BitsPerSecond=
Duplex=
AutoNegotiation=
WakeOnLan=
WakeOnLanPassword=
Port=
ReceiveChecksumOffload=
TransmitChecksumOffload=