mirror of
https://git.proxmox.com/git/systemd
synced 2025-07-25 10:34:22 +00:00
New upstream version 245.5
This commit is contained in:
parent
7d4b9ad6f6
commit
d0648cfe4f
@ -412,3 +412,26 @@ as the best process to terminate and has been forcibly terminated by the
|
||||
kernel.
|
||||
|
||||
Note that the memory pressure might or might not have been caused by @UNIT@.
|
||||
|
||||
-- b61fdac612e94b9182285b998843061f
|
||||
Subject: Accepting user/group name @USER_GROUP_NAME@, which does not match strict user/group name rules.
|
||||
Defined-By: systemd
|
||||
Support: %SUPPORT_URL%
|
||||
|
||||
The user/group name @USER_GROUP_NAME@ has been specified, which is accepted
|
||||
according the relaxed user/group name rules, but does not qualify under the
|
||||
strict rules.
|
||||
|
||||
The strict user/group name rules written as regular expression are:
|
||||
|
||||
^[a-zA-Z_][a-zA-Z0-9_-]{0,30}$
|
||||
|
||||
The relaxed user/group name rules accept all names, except for the empty
|
||||
string; names containing NUL bytes, control characters, colon or slash
|
||||
characters; names not valid UTF-8; names with leading or trailing whitespace;
|
||||
the strings "." or ".."; fully numeric strings, or strings beginning in a
|
||||
hyphen and otherwise fully numeric.
|
||||
|
||||
For further details on strict and relaxed user/group name rules, see:
|
||||
|
||||
https://systemd.io/USER_NAMES
|
||||
|
@ -205,7 +205,8 @@ object. The following fields are currently defined:
|
||||
UNIX user name. This field is the only mandatory field, all others are
|
||||
optional. Corresponds with the `pw_name` field of of `struct passwd` and the
|
||||
`sp_namp` field of `struct spwd` (i.e. the shadow user record stored in
|
||||
`/etc/shadow`).
|
||||
`/etc/shadow`). See [User/Group Name Syntax](https://systemd.io/USER_NAMES) for
|
||||
the (relaxed) rules the various systemd components enforce on user/group names.
|
||||
|
||||
`realm` → The "realm" a user is defined in. This concept allows distinguishing
|
||||
users with the same name that originate in different organizations or
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -217,6 +217,17 @@
|
||||
will be used. </para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--file=<replaceable>GLOB</replaceable></option></term>
|
||||
|
||||
<listitem><para>Takes a file glob as an argument. If
|
||||
specified, coredumpctl will operate on the specified journal
|
||||
files matching <replaceable>GLOB</replaceable> instead of the
|
||||
default runtime and system journal paths. May be specified
|
||||
multiple times, in which case files will be suitably
|
||||
interleaved.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-D</option> <replaceable>DIR</replaceable></term>
|
||||
<term><option>--directory=</option><replaceable>DIR</replaceable></term>
|
||||
|
@ -677,7 +677,10 @@
|
||||
|
||||
<listitem><para>Create a new home directory/user account of the specified name. Use the various
|
||||
user record property options (as documented above) to control various aspects of the home directory
|
||||
and its user accounts.</para></listitem>
|
||||
and its user accounts.</para>
|
||||
|
||||
<para>The specified user name should follow the strict syntax described on <ulink
|
||||
url="https://systemd.io/USER_NAMES">User/Group Name Syntax</ulink>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -398,8 +398,8 @@
|
||||
<varlistentry>
|
||||
<term><option>--output-fields=</option></term>
|
||||
|
||||
<listitem><para>A comma separated list of the fields which should be included in the output. This only has an
|
||||
effect for the output modes which would normally show all fields (<option>verbose</option>,
|
||||
<listitem><para>A comma separated list of the fields which should be included in the output. This has an
|
||||
effect only for the output modes which would normally show all fields (<option>verbose</option>,
|
||||
<option>export</option>, <option>json</option>, <option>json-pretty</option>, <option>json-sse</option> and
|
||||
<option>json-seq</option>). The <literal>__CURSOR</literal>, <literal>__REALTIME_TIMESTAMP</literal>,
|
||||
<literal>__MONOTONIC_TIMESTAMP</literal>, and <literal>_BOOT_ID</literal> fields are always
|
||||
@ -416,8 +416,13 @@
|
||||
<varlistentry>
|
||||
<term><option>--no-hostname</option></term>
|
||||
|
||||
<listitem><para>Don't show the hostname field of log messages originating from the local host. This switch only
|
||||
has an effect on the <option>short</option> family of output modes (see above).</para></listitem>
|
||||
<listitem><para>Don't show the hostname field of log messages originating from the local host. This
|
||||
switch has an effect only on the <option>short</option> family of output modes (see above).
|
||||
</para>
|
||||
|
||||
<para>Note: this option does not remove occurrences of the hostname from log entries themselves, so
|
||||
it does not prevent the hostname from being visible in the logs.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -146,8 +146,10 @@
|
||||
<varlistentry>
|
||||
<term><option>--slice=</option></term>
|
||||
|
||||
<listitem><para>Make the new <filename>.service</filename> or <filename>.scope</filename> unit part of the
|
||||
specified slice, instead of <filename>system.slice</filename>.</para>
|
||||
<listitem><para>Make the new <filename>.service</filename> or <filename>.scope</filename> unit part
|
||||
of the specified slice, instead of <filename>system.slice</filename> (when running in
|
||||
<option>--system</option> mode) or the root slice (when running in <option>--user</option>
|
||||
mode).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
@ -217,12 +217,15 @@
|
||||
is set, the default group of the user is used. This setting does not affect commands whose command line is
|
||||
prefixed with <literal>+</literal>.</para>
|
||||
|
||||
<para>Note that restrictions on the user/group name syntax are enforced: the specified name must consist only
|
||||
of the characters a-z, A-Z, 0-9, <literal>_</literal> and <literal>-</literal>, except for the first character
|
||||
which must be one of a-z, A-Z or <literal>_</literal> (i.e. numbers and <literal>-</literal> are not permitted
|
||||
as first character). The user/group name must have at least one character, and at most 31. These restrictions
|
||||
are enforced in order to avoid ambiguities and to ensure user/group names and unit files remain portable among
|
||||
Linux systems.</para>
|
||||
<para>Note that this enforces only weak restrictions on the user/group name syntax, but will generate
|
||||
warnings in many cases where user/group names do not adhere to the following rules: the specified
|
||||
name should consist only of the characters a-z, A-Z, 0-9, <literal>_</literal> and
|
||||
<literal>-</literal>, except for the first character which must be one of a-z, A-Z and
|
||||
<literal>_</literal> (i.e. digits and <literal>-</literal> are not permitted as first character). The
|
||||
user/group name must have at least one character, and at most 31. These restrictions are made in
|
||||
order to avoid ambiguities and to ensure user/group names and unit files remain portable among Linux
|
||||
systems. For further details on the names accepted and the names warned about see <ulink
|
||||
url="https://systemd.io/USER_NAMES">User/Group Name Syntax</ulink>.</para>
|
||||
|
||||
<para>When used in conjunction with <varname>DynamicUser=</varname> the user/group name specified is
|
||||
dynamically allocated at the time the service is started, and released at the time the service is
|
||||
|
@ -423,6 +423,9 @@
|
||||
<varname>ExecStart=</varname>, or <varname>ExecStartPost=</varname> fail (and are not prefixed with
|
||||
<literal>-</literal>, see above) or time out before the service is fully up, execution continues with commands
|
||||
specified in <varname>ExecStopPost=</varname>, the commands in <varname>ExecStop=</varname> are skipped.</para>
|
||||
|
||||
<para>Note that the execution of <varname>ExecStartPost=</varname> is taken into account for the purpose of
|
||||
<varname>Before=</varname>/<varname>After=</varname> ordering constraints.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@ -534,7 +537,10 @@
|
||||
service, as well as the main process' exit code and status, set in the <varname>$SERVICE_RESULT</varname>,
|
||||
<varname>$EXIT_CODE</varname> and <varname>$EXIT_STATUS</varname> environment variables, see
|
||||
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
|
||||
details.</para></listitem>
|
||||
details.</para>
|
||||
|
||||
<para>Note that the execution of <varname>ExecStopPost=</varname> is taken into account for the purpose of
|
||||
<varname>Before=</varname>/<varname>After=</varname> ordering constraints.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -750,7 +750,7 @@
|
||||
type when precisely a unit has finished starting up. Most importantly, for service units start-up is
|
||||
considered completed for the purpose of <varname>Before=</varname>/<varname>After=</varname> when all
|
||||
its configured start-up commands have been invoked and they either failed or reported start-up
|
||||
success.</para>
|
||||
success. Note that this does includes ExecStartPost (or ExecStopPost for the shutdown case).</para>
|
||||
|
||||
<para>Note that those settings are independent of and orthogonal to the requirement dependencies as
|
||||
configured by <varname>Requires=</varname>, <varname>Wants=</varname>, <varname>Requisite=</varname>,
|
||||
|
@ -154,6 +154,9 @@ r - 500-900
|
||||
A-Z or <literal>_</literal> (i.e. numbers and <literal>-</literal> are not permitted as first character). The
|
||||
user/group name must have at least one character, and at most 31.</para>
|
||||
|
||||
<para>For further details about the syntax of user/group names, see <ulink
|
||||
url="https://systemd.io/USER_NAMES">User/Group Name Syntax</ulink>.</para>
|
||||
|
||||
<para>It is strongly recommended to pick user and group names that are unlikely to clash with normal users
|
||||
created by the administrator. A good scheme to guarantee this is by prefixing all system and group names with the
|
||||
underscore, and avoiding too generic names.</para>
|
||||
|
@ -124,10 +124,13 @@ static int verify_socket(Unit *u) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int verify_executable(Unit *u, ExecCommand *exec) {
|
||||
int verify_executable(Unit *u, const ExecCommand *exec) {
|
||||
if (!exec)
|
||||
return 0;
|
||||
|
||||
if (exec->flags & EXEC_COMMAND_IGNORE_FAILURE)
|
||||
return 0;
|
||||
|
||||
if (access(exec->path, X_OK) < 0)
|
||||
return log_unit_error_errno(u, errno, "Command %s is not executable: %m", exec->path);
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "execute.h"
|
||||
#include "path-lookup.h"
|
||||
|
||||
int verify_executable(Unit *u, const ExecCommand *exec);
|
||||
int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators);
|
||||
|
19
src/analyze/test-verify.c
Normal file
19
src/analyze/test-verify.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
#include "analyze-verify.h"
|
||||
#include "tests.h"
|
||||
|
||||
static void test_verify_nonexistent(void) {
|
||||
/* Negative cases */
|
||||
assert_se(verify_executable(NULL, &(ExecCommand) {.flags = EXEC_COMMAND_IGNORE_FAILURE, .path = (char*) "/non/existent"}) == 0);
|
||||
assert_se(verify_executable(NULL, &(ExecCommand) {.path = (char*) "/non/existent"}) < 0);
|
||||
|
||||
/* Ordinary cases */
|
||||
assert_se(verify_executable(NULL, &(ExecCommand) {.path = (char*) "/bin/echo"}) == 0);
|
||||
assert_se(verify_executable(NULL, &(ExecCommand) {.flags = EXEC_COMMAND_IGNORE_FAILURE, .path = (char*) "/bin/echo"}) == 0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
test_setup_logging(LOG_DEBUG);
|
||||
|
||||
test_verify_nonexistent();
|
||||
}
|
@ -107,11 +107,13 @@ int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
|
||||
unsigned long i;
|
||||
int r;
|
||||
|
||||
/* Add the capabilities to the ambient set (an possibly also the inheritable set) */
|
||||
|
||||
/* Check that we can use PR_CAP_AMBIENT or quit early. */
|
||||
if (!ambient_capabilities_supported())
|
||||
return 0;
|
||||
|
||||
/* Add the capabilities to the ambient set. */
|
||||
return (set & all_capabilities()) == 0 ?
|
||||
0 : -EOPNOTSUPP; /* if actually no ambient caps are to be set, be silent,
|
||||
* otherwise fail recognizably */
|
||||
|
||||
if (also_inherit) {
|
||||
caps = cap_get_proc();
|
||||
|
@ -81,7 +81,7 @@ int write_string_stream_ts(
|
||||
struct timespec *ts) {
|
||||
|
||||
bool needs_nl;
|
||||
int r;
|
||||
int r, fd;
|
||||
|
||||
assert(f);
|
||||
assert(line);
|
||||
@ -89,6 +89,14 @@ int write_string_stream_ts(
|
||||
if (ferror(f))
|
||||
return -EIO;
|
||||
|
||||
if (ts) {
|
||||
/* If we shall set the timestamp we need the fd. But fmemopen() streams generally don't have
|
||||
* an fd. Let's fail early in that case. */
|
||||
fd = fileno(f);
|
||||
if (fd < 0)
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
needs_nl = !(flags & WRITE_STRING_FILE_AVOID_NEWLINE) && !endswith(line, "\n");
|
||||
|
||||
if (needs_nl && (flags & WRITE_STRING_FILE_DISABLE_BUFFER)) {
|
||||
@ -116,7 +124,7 @@ int write_string_stream_ts(
|
||||
if (ts) {
|
||||
struct timespec twice[2] = {*ts, *ts};
|
||||
|
||||
if (futimens(fileno(f), twice) < 0)
|
||||
if (futimens(fd, twice) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
@ -848,7 +856,7 @@ int fflush_and_check(FILE *f) {
|
||||
}
|
||||
|
||||
int fflush_sync_and_check(FILE *f) {
|
||||
int r;
|
||||
int r, fd;
|
||||
|
||||
assert(f);
|
||||
|
||||
@ -856,10 +864,16 @@ int fflush_sync_and_check(FILE *f) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (fsync(fileno(f)) < 0)
|
||||
/* Not all file streams have an fd associated (think: fmemopen()), let's handle this gracefully and
|
||||
* assume that in that case we need no explicit syncing */
|
||||
fd = fileno(f);
|
||||
if (fd < 0)
|
||||
return 0;
|
||||
|
||||
if (fsync(fd) < 0)
|
||||
return -errno;
|
||||
|
||||
r = fsync_directory_of_file(fileno(f));
|
||||
r = fsync_directory_of_file(fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -957,7 +971,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile);
|
||||
int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
|
||||
size_t n = 0, allocated = 0, count = 0;
|
||||
_cleanup_free_ char *buffer = NULL;
|
||||
int r, tty = -1;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
|
||||
@ -1032,13 +1046,23 @@ int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
|
||||
count++;
|
||||
|
||||
if (eol != EOL_NONE) {
|
||||
/* If we are on a tty, we can't wait for more input. But we expect only
|
||||
* \n as the single EOL marker, so there is no need to wait. We check
|
||||
* this condition last to avoid isatty() check if not necessary. */
|
||||
/* If we are on a tty, we can't shouldn't wait for more input, because that
|
||||
* generally means waiting for the user, interactively. In the case of a TTY
|
||||
* we expect only \n as the single EOL marker, so we are in the lucky
|
||||
* position that there is no need to wait. We check this condition last, to
|
||||
* avoid isatty() check if not necessary. */
|
||||
|
||||
if (tty < 0)
|
||||
tty = isatty(fileno(f));
|
||||
if (tty > 0)
|
||||
if ((flags & (READ_LINE_IS_A_TTY|READ_LINE_NOT_A_TTY)) == 0) {
|
||||
int fd;
|
||||
|
||||
fd = fileno(f);
|
||||
if (fd < 0) /* Maybe an fmemopen() stream? Handle this gracefully,
|
||||
* and don't call isatty() on an invalid fd */
|
||||
flags |= READ_LINE_NOT_A_TTY;
|
||||
else
|
||||
flags |= isatty(fd) ? READ_LINE_IS_A_TTY : READ_LINE_NOT_A_TTY;
|
||||
}
|
||||
if (FLAGS_SET(flags, READ_LINE_IS_A_TTY))
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,9 @@ int read_timestamp_file(const char *fn, usec_t *ret);
|
||||
int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);
|
||||
|
||||
typedef enum ReadLineFlags {
|
||||
READ_LINE_ONLY_NUL = 1 << 0,
|
||||
READ_LINE_ONLY_NUL = 1 << 0,
|
||||
READ_LINE_IS_A_TTY = 1 << 1,
|
||||
READ_LINE_NOT_A_TTY = 1 << 2,
|
||||
} ReadLineFlags;
|
||||
|
||||
int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret);
|
||||
|
@ -113,7 +113,7 @@ static size_t strcspn_escaped(const char *s, const char *reject) {
|
||||
bool escaped = false;
|
||||
int n;
|
||||
|
||||
for (n=0; s[n]; n++) {
|
||||
for (n = 0; s[n] != '\0'; n++) {
|
||||
if (escaped)
|
||||
escaped = false;
|
||||
else if (s[n] == '\\')
|
||||
@ -122,8 +122,7 @@ static size_t strcspn_escaped(const char *s, const char *reject) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* if s ends in \, return index of previous char */
|
||||
return n - escaped;
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Split a string into words. */
|
||||
|
@ -81,31 +81,34 @@ int chvt(int vt) {
|
||||
int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
struct termios old_termios;
|
||||
int r;
|
||||
int r, fd;
|
||||
|
||||
assert(f);
|
||||
assert(ret);
|
||||
|
||||
/* If this is a terminal, then switch canonical mode off, so that we can read a single character */
|
||||
if (tcgetattr(fileno(f), &old_termios) >= 0) {
|
||||
/* If this is a terminal, then switch canonical mode off, so that we can read a single
|
||||
* character. (Note that fmemopen() streams do not have an fd associated with them, let's handle that
|
||||
* nicely.) */
|
||||
fd = fileno(f);
|
||||
if (fd >= 0 && tcgetattr(fd, &old_termios) >= 0) {
|
||||
struct termios new_termios = old_termios;
|
||||
|
||||
new_termios.c_lflag &= ~ICANON;
|
||||
new_termios.c_cc[VMIN] = 1;
|
||||
new_termios.c_cc[VTIME] = 0;
|
||||
|
||||
if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
|
||||
if (tcsetattr(fd, TCSADRAIN, &new_termios) >= 0) {
|
||||
char c;
|
||||
|
||||
if (t != USEC_INFINITY) {
|
||||
if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
|
||||
(void) tcsetattr(fileno(f), TCSADRAIN, &old_termios);
|
||||
if (fd_wait_for_event(fd, POLLIN, t) <= 0) {
|
||||
(void) tcsetattr(fd, TCSADRAIN, &old_termios);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
|
||||
r = safe_fgetc(f, &c);
|
||||
(void) tcsetattr(fileno(f), TCSADRAIN, &old_termios);
|
||||
(void) tcsetattr(fd, TCSADRAIN, &old_termios);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
@ -119,8 +122,13 @@ int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
|
||||
}
|
||||
}
|
||||
|
||||
if (t != USEC_INFINITY) {
|
||||
if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
|
||||
if (t != USEC_INFINITY && fd > 0) {
|
||||
/* Let's wait the specified amount of time for input. When we have no fd we skip this, under
|
||||
* the assumption that this is an fmemopen() stream or so where waiting doesn't make sense
|
||||
* anyway, as the data is either already in the stream or cannot possible be placed there
|
||||
* while we access the stream */
|
||||
|
||||
if (fd_wait_for_event(fd, POLLIN, t) <= 0)
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
@ -778,6 +786,9 @@ const char *default_term_for_tty(const char *tty) {
|
||||
int fd_columns(int fd) {
|
||||
struct winsize ws = {};
|
||||
|
||||
if (fd < 0)
|
||||
return -EBADF;
|
||||
|
||||
if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
|
||||
return -errno;
|
||||
|
||||
@ -812,6 +823,9 @@ unsigned columns(void) {
|
||||
int fd_lines(int fd) {
|
||||
struct winsize ws = {};
|
||||
|
||||
if (fd < 0)
|
||||
return -EBADF;
|
||||
|
||||
if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
|
||||
return -errno;
|
||||
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include <unistd.h>
|
||||
#include <utmp.h>
|
||||
|
||||
#include "sd-messages.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
@ -18,6 +20,7 @@
|
||||
#include "macro.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "path-util.h"
|
||||
#include "random-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
@ -698,92 +701,125 @@ int take_etc_passwd_lock(const char *root) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
bool valid_user_group_name_full(const char *u, bool strict) {
|
||||
bool valid_user_group_name(const char *u, ValidUserFlags flags) {
|
||||
const char *i;
|
||||
long sz;
|
||||
bool warned = false;
|
||||
|
||||
/* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
|
||||
* 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
|
||||
/* Checks if the specified name is a valid user/group name. There are two flavours of this call:
|
||||
* strict mode is the default which is POSIX plus some extra rules; and relaxed mode where we accept
|
||||
* pretty much everything except the really worst offending names.
|
||||
*
|
||||
* - We require that names fit into the appropriate utmp field
|
||||
* - We don't allow empty user names
|
||||
* - No dots in the first character
|
||||
*
|
||||
* If strict==true, additionally:
|
||||
* - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
|
||||
* - We don't allow a digit as the first character
|
||||
*
|
||||
* Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
|
||||
*/
|
||||
* Whenever we synthesize users ourselves we should use the strict mode. But when we process users
|
||||
* created by other stuff, let's be more liberal. */
|
||||
|
||||
if (isempty(u))
|
||||
if (isempty(u)) /* An empty user name is never valid */
|
||||
return false;
|
||||
|
||||
if (!(u[0] >= 'a' && u[0] <= 'z') &&
|
||||
!(u[0] >= 'A' && u[0] <= 'Z') &&
|
||||
!(u[0] >= '0' && u[0] <= '9' && !strict) &&
|
||||
u[0] != '_')
|
||||
return false;
|
||||
if (parse_uid(u, NULL) >= 0) /* Something that parses as numeric UID string is valid exactly when the
|
||||
* flag for it is set */
|
||||
return FLAGS_SET(flags, VALID_USER_ALLOW_NUMERIC);
|
||||
|
||||
bool only_digits_seen = u[0] >= '0' && u[0] <= '9';
|
||||
if (FLAGS_SET(flags, VALID_USER_RELAX)) {
|
||||
|
||||
if (only_digits_seen) {
|
||||
log_warning("User or group name \"%s\" starts with a digit, accepting for compatibility.", u);
|
||||
warned = true;
|
||||
/* In relaxed mode we just check very superficially. Apparently SSSD and other stuff is
|
||||
* extremely liberal (way too liberal if you ask me, even inserting "@" in user names, which
|
||||
* is bound to cause problems for example when used with an MTA), hence only filter the most
|
||||
* obvious cases, or where things would result in an invalid entry if such a user name would
|
||||
* show up in /etc/passwd (or equivalent getent output).
|
||||
*
|
||||
* Note that we stepped far out of POSIX territory here. It's not our fault though, but
|
||||
* SSSD's, Samba's and everybody else who ignored POSIX on this. (I mean, I am happy to step
|
||||
* outside of POSIX' bounds any day, but I must say in this case I probably wouldn't
|
||||
* have...) */
|
||||
|
||||
if (startswith(u, " ") || endswith(u, " ")) /* At least expect whitespace padding is removed
|
||||
* at front and back (accept in the middle, since
|
||||
* that's apparently a thing on Windows). Note
|
||||
* that this also blocks usernames consisting of
|
||||
* whitespace only. */
|
||||
return false;
|
||||
|
||||
if (!utf8_is_valid(u)) /* We want to synthesize JSON from this, hence insist on UTF-8 */
|
||||
return false;
|
||||
|
||||
if (string_has_cc(u, NULL)) /* CC characters are just dangerous (and \n in particular is the
|
||||
* record separator in /etc/passwd), so we can't allow that. */
|
||||
return false;
|
||||
|
||||
if (strpbrk(u, ":/")) /* Colons are the field separator in /etc/passwd, we can't allow
|
||||
* that. Slashes are special to file systems paths and user names
|
||||
* typically show up in the file system as home directories, hence
|
||||
* don't allow slashes. */
|
||||
return false;
|
||||
|
||||
if (in_charset(u, "0123456789")) /* Don't allow fully numeric strings, they might be confused
|
||||
* with with UIDs (note that this test is more broad than
|
||||
* the parse_uid() test above, as it will cover more than
|
||||
* the 32bit range, and it will detect 65535 (which is in
|
||||
* invalid UID, even though in the unsigned 32 bit range) */
|
||||
return false;
|
||||
|
||||
if (u[0] == '-' && in_charset(u + 1, "0123456789")) /* Don't allow negative fully numeric
|
||||
* strings either. After all some people
|
||||
* write 65535 as -1 (even though that's
|
||||
* not even true on 32bit uid_t
|
||||
* anyway) */
|
||||
return false;
|
||||
|
||||
if (dot_or_dot_dot(u)) /* User names typically become home directory names, and these two are
|
||||
* special in that context, don't allow that. */
|
||||
return false;
|
||||
|
||||
/* Compare with strict result and warn if result doesn't match */
|
||||
if (FLAGS_SET(flags, VALID_USER_WARN) && !valid_user_group_name(u, 0))
|
||||
log_struct(LOG_NOTICE,
|
||||
"MESSAGE=Accepting user/group name '%s', which does not match strict user/group name rules.", u,
|
||||
"USER_GROUP_NAME=%s", u,
|
||||
"MESSAGE_ID=" SD_MESSAGE_UNSAFE_USER_NAME_STR);
|
||||
|
||||
/* Note that we make no restrictions on the length in relaxed mode! */
|
||||
} else {
|
||||
long sz;
|
||||
size_t l;
|
||||
|
||||
/* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.437. We are a bit stricter here
|
||||
* however. Specifically we deviate from POSIX rules:
|
||||
*
|
||||
* - We don't allow empty user names (see above)
|
||||
* - We require that names fit into the appropriate utmp field
|
||||
* - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
|
||||
* - We don't allow dashes or digit as the first character
|
||||
*
|
||||
* Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
|
||||
*/
|
||||
|
||||
if (!(u[0] >= 'a' && u[0] <= 'z') &&
|
||||
!(u[0] >= 'A' && u[0] <= 'Z') &&
|
||||
u[0] != '_')
|
||||
return false;
|
||||
|
||||
for (i = u+1; *i; i++)
|
||||
if (!(*i >= 'a' && *i <= 'z') &&
|
||||
!(*i >= 'A' && *i <= 'Z') &&
|
||||
!(*i >= '0' && *i <= '9') &&
|
||||
!IN_SET(*i, '_', '-'))
|
||||
return false;
|
||||
|
||||
l = i - u;
|
||||
|
||||
sz = sysconf(_SC_LOGIN_NAME_MAX);
|
||||
assert_se(sz > 0);
|
||||
|
||||
if (l > (size_t) sz)
|
||||
return false;
|
||||
if (l > FILENAME_MAX)
|
||||
return false;
|
||||
if (l > UT_NAMESIZE - 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = u+1; *i; i++) {
|
||||
if (((*i >= 'a' && *i <= 'z') ||
|
||||
(*i >= 'A' && *i <= 'Z') ||
|
||||
(*i >= '0' && *i <= '9') ||
|
||||
IN_SET(*i, '_', '-'))) {
|
||||
if (!(*i >= '0' && *i <= '9'))
|
||||
only_digits_seen = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*i == '.' && !strict) {
|
||||
if (!warned) {
|
||||
log_warning("Bad user or group name \"%s\", accepting for compatibility.", u);
|
||||
warned = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (only_digits_seen)
|
||||
return false;
|
||||
|
||||
sz = sysconf(_SC_LOGIN_NAME_MAX);
|
||||
assert_se(sz > 0);
|
||||
|
||||
if ((size_t) (i-u) > (size_t) sz)
|
||||
return false;
|
||||
|
||||
if ((size_t) (i-u) > UT_NAMESIZE - 1)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool valid_user_group_name_or_id_full(const char *u, bool strict) {
|
||||
|
||||
/* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the
|
||||
* right range, and not the invalid user ids. */
|
||||
|
||||
if (isempty(u))
|
||||
return false;
|
||||
|
||||
if (parse_uid(u, NULL) >= 0)
|
||||
return true;
|
||||
|
||||
return valid_user_group_name_full(u, strict);
|
||||
}
|
||||
|
||||
bool valid_gecos(const char *d) {
|
||||
|
||||
if (!d)
|
||||
|
@ -97,20 +97,13 @@ static inline bool userns_supported(void) {
|
||||
return access("/proc/self/uid_map", F_OK) >= 0;
|
||||
}
|
||||
|
||||
bool valid_user_group_name_full(const char *u, bool strict);
|
||||
bool valid_user_group_name_or_id_full(const char *u, bool strict);
|
||||
static inline bool valid_user_group_name(const char *u) {
|
||||
return valid_user_group_name_full(u, true);
|
||||
}
|
||||
static inline bool valid_user_group_name_or_id(const char *u) {
|
||||
return valid_user_group_name_or_id_full(u, true);
|
||||
}
|
||||
static inline bool valid_user_group_name_compat(const char *u) {
|
||||
return valid_user_group_name_full(u, false);
|
||||
}
|
||||
static inline bool valid_user_group_name_or_id_compat(const char *u) {
|
||||
return valid_user_group_name_or_id_full(u, false);
|
||||
}
|
||||
typedef enum ValidUserFlags {
|
||||
VALID_USER_RELAX = 1 << 0,
|
||||
VALID_USER_WARN = 1 << 1,
|
||||
VALID_USER_ALLOW_NUMERIC = 1 << 2,
|
||||
} ValidUserFlags;
|
||||
|
||||
bool valid_user_group_name(const char *u, ValidUserFlags flags);
|
||||
bool valid_gecos(const char *d);
|
||||
bool valid_home(const char *p);
|
||||
|
||||
|
@ -462,13 +462,14 @@ int detect_container(void) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
/* "Official" way of detecting WSL https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364 */
|
||||
/* "Official" way of detecting WSL https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364,
|
||||
* ... and a working one, since the official one doesn't actually work ;(
|
||||
*/
|
||||
r = read_one_line_file("/proc/sys/kernel/osrelease", &o);
|
||||
if (r >= 0) {
|
||||
if (strstr(o, "Microsoft") || strstr(o, "WSL")) {
|
||||
r = VIRTUALIZATION_WSL;
|
||||
goto finish;
|
||||
}
|
||||
if (r >= 0 &&
|
||||
(strstr(o, "Microsoft") || strstr(o, "microsoft") || strstr(o, "WSL"))) {
|
||||
r = VIRTUALIZATION_WSL;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (getpid_cached() == 1) {
|
||||
|
@ -795,6 +795,7 @@ const sd_bus_vtable bus_exec_vtable[] = {
|
||||
SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ProtectClock", "b", bus_property_get_bool, offsetof(ExecContext, protect_clock), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ProtectKernelTunables", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_tunables), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ProtectKernelModules", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_modules), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ProtectKernelLogs", "b", bus_property_get_bool, offsetof(ExecContext, protect_kernel_logs), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
@ -1203,10 +1204,10 @@ int bus_exec_context_set_transient_property(
|
||||
flags |= UNIT_PRIVATE;
|
||||
|
||||
if (streq(name, "User"))
|
||||
return bus_set_transient_user_compat(u, name, &c->user, message, flags, error);
|
||||
return bus_set_transient_user_relaxed(u, name, &c->user, message, flags, error);
|
||||
|
||||
if (streq(name, "Group"))
|
||||
return bus_set_transient_user_compat(u, name, &c->group, message, flags, error);
|
||||
return bus_set_transient_user_relaxed(u, name, &c->group, message, flags, error);
|
||||
|
||||
if (streq(name, "TTYPath"))
|
||||
return bus_set_transient_path(u, name, &c->tty_path, message, flags, error);
|
||||
@ -1391,7 +1392,7 @@ int bus_exec_context_set_transient_property(
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(p, l)
|
||||
if (!isempty(*p) && !valid_user_group_name_or_id_compat(*p))
|
||||
if (!isempty(*p) && !valid_user_group_name(*p, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
|
||||
"Invalid supplementary group names");
|
||||
|
||||
|
@ -1643,7 +1643,7 @@ static int method_lookup_dynamic_user_by_name(sd_bus_message *message, void *use
|
||||
|
||||
if (!MANAGER_IS_SYSTEM(m))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance.");
|
||||
if (!valid_user_group_name(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name invalid: %s", name);
|
||||
|
||||
r = dynamic_user_lookup_name(m, name, &uid);
|
||||
|
@ -278,10 +278,10 @@ static int bus_socket_set_transient_property(
|
||||
return bus_set_transient_fdname(u, name, &s->fdname, message, flags, error);
|
||||
|
||||
if (streq(name, "SocketUser"))
|
||||
return bus_set_transient_user_compat(u, name, &s->user, message, flags, error);
|
||||
return bus_set_transient_user_relaxed(u, name, &s->user, message, flags, error);
|
||||
|
||||
if (streq(name, "SocketGroup"))
|
||||
return bus_set_transient_user_compat(u, name, &s->group, message, flags, error);
|
||||
return bus_set_transient_user_relaxed(u, name, &s->group, message, flags, error);
|
||||
|
||||
if (streq(name, "BindIPv6Only"))
|
||||
return bus_set_transient_bind_ipv6_only(u, name, &s->bind_ipv6_only, message, flags, error);
|
||||
|
@ -30,7 +30,12 @@ int bus_property_get_triggered_unit(
|
||||
|
||||
BUS_DEFINE_SET_TRANSIENT(mode_t, "u", uint32_t, mode_t, "%040o");
|
||||
BUS_DEFINE_SET_TRANSIENT(unsigned, "u", uint32_t, unsigned, "%" PRIu32);
|
||||
BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_compat, valid_user_group_name_or_id_compat);
|
||||
|
||||
static inline bool valid_user_group_name_or_id_relaxed(const char *u) {
|
||||
return valid_user_group_name(u, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX);
|
||||
}
|
||||
|
||||
BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(user_relaxed, valid_user_group_name_or_id_relaxed);
|
||||
BUS_DEFINE_SET_TRANSIENT_STRING_WITH_CHECK(path, path_is_absolute);
|
||||
|
||||
int bus_set_transient_string(
|
||||
|
@ -236,7 +236,7 @@ int bus_property_get_triggered_unit(sd_bus *bus, const char *path, const char *i
|
||||
|
||||
int bus_set_transient_mode_t(Unit *u, const char *name, mode_t *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
|
||||
int bus_set_transient_unsigned(Unit *u, const char *name, unsigned *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
|
||||
int bus_set_transient_user_compat(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
|
||||
int bus_set_transient_user_relaxed(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
|
||||
int bus_set_transient_path(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
|
||||
int bus_set_transient_string(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
|
||||
int bus_set_transient_bool(Unit *u, const char *name, bool *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error);
|
||||
|
@ -116,7 +116,7 @@ static int dynamic_user_acquire(Manager *m, const char *name, DynamicUser** ret)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!valid_user_group_name_or_id(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_ALLOW_NUMERIC))
|
||||
return -EINVAL;
|
||||
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, storage_socket) < 0)
|
||||
|
@ -1577,7 +1577,7 @@ static int apply_protect_kernel_logs(const Unit *u, const ExecContext *c) {
|
||||
return seccomp_protect_syslog();
|
||||
}
|
||||
|
||||
static int apply_protect_clock(const Unit *u, const ExecContext *c) {
|
||||
static int apply_protect_clock(const Unit *u, const ExecContext *c) {
|
||||
assert(u);
|
||||
assert(c);
|
||||
|
||||
@ -1646,6 +1646,41 @@ static int apply_lock_personality(const Unit* u, const ExecContext *c) {
|
||||
|
||||
#endif
|
||||
|
||||
static int apply_protect_hostname(const Unit *u, const ExecContext *c, int *ret_exit_status) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(c);
|
||||
|
||||
if (!c->protect_hostname)
|
||||
return 0;
|
||||
|
||||
if (ns_type_supported(NAMESPACE_UTS)) {
|
||||
if (unshare(CLONE_NEWUTS) < 0) {
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) {
|
||||
*ret_exit_status = EXIT_NAMESPACE;
|
||||
return log_unit_error_errno(u, errno, "Failed to set up UTS namespacing: %m");
|
||||
}
|
||||
|
||||
log_unit_warning(u, "ProtectHostname=yes is configured, but UTS namespace setup is prohibited (container manager?), ignoring namespace setup.");
|
||||
}
|
||||
} else
|
||||
log_unit_warning(u, "ProtectHostname=yes is configured, but the kernel does not support UTS namespaces, ignoring namespace setup.");
|
||||
|
||||
#if HAVE_SECCOMP
|
||||
if (skip_seccomp_unavailable(u, "ProtectHostname="))
|
||||
return 0;
|
||||
|
||||
r = seccomp_protect_hostname();
|
||||
if (r < 0) {
|
||||
*ret_exit_status = EXIT_SECCOMP;
|
||||
return log_unit_error_errno(u, r, "Failed to apply hostname restrictions: %m");
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void do_idle_pipe_dance(int idle_pipe[static 4]) {
|
||||
assert(idle_pipe);
|
||||
|
||||
@ -3588,25 +3623,10 @@ static int exec_child(
|
||||
}
|
||||
}
|
||||
|
||||
if (context->protect_hostname) {
|
||||
if (ns_type_supported(NAMESPACE_UTS)) {
|
||||
if (unshare(CLONE_NEWUTS) < 0) {
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) {
|
||||
*exit_status = EXIT_NAMESPACE;
|
||||
return log_unit_error_errno(unit, errno, "Failed to set up UTS namespacing: %m");
|
||||
}
|
||||
|
||||
log_unit_warning(unit, "ProtectHostname=yes is configured, but UTS namespace setup is prohibited (container manager?), ignoring namespace setup.");
|
||||
}
|
||||
} else
|
||||
log_unit_warning(unit, "ProtectHostname=yes is configured, but the kernel does not support UTS namespaces, ignoring namespace setup.");
|
||||
#if HAVE_SECCOMP
|
||||
r = seccomp_protect_hostname();
|
||||
if (r < 0) {
|
||||
*exit_status = EXIT_SECCOMP;
|
||||
return log_unit_error_errno(unit, r, "Failed to apply hostname restrictions: %m");
|
||||
}
|
||||
#endif
|
||||
if (needs_sandboxing) {
|
||||
r = apply_protect_hostname(unit, context, exit_status);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Drop groups as early as possible.
|
||||
|
@ -2068,7 +2068,7 @@ int config_parse_user_group_compat(
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
if (!valid_user_group_name_or_id_compat(k)) {
|
||||
if (!valid_user_group_name(k, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
@ -2122,7 +2122,7 @@ int config_parse_user_group_strv_compat(
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
if (!valid_user_group_name_or_id_compat(k)) {
|
||||
if (!valid_user_group_name(k, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX|VALID_USER_WARN)) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid user/group name or numeric ID: %s", k);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
@ -4278,7 +4278,7 @@ static int user_from_unit_name(Unit *u, char **ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (valid_user_group_name(n)) {
|
||||
if (valid_user_group_name(n, 0)) {
|
||||
*ret = TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "def.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "glob-util.h"
|
||||
#include "journal-internal.h"
|
||||
#include "journal-util.h"
|
||||
#include "log.h"
|
||||
@ -44,6 +45,7 @@ static usec_t arg_since = USEC_INFINITY, arg_until = USEC_INFINITY;
|
||||
static const char* arg_field = NULL;
|
||||
static const char *arg_debugger = NULL;
|
||||
static const char *arg_directory = NULL;
|
||||
static char **arg_file = NULL;
|
||||
static PagerFlags arg_pager_flags = 0;
|
||||
static int arg_no_legend = false;
|
||||
static int arg_one = false;
|
||||
@ -51,6 +53,8 @@ static const char* arg_output = NULL;
|
||||
static bool arg_reverse = false;
|
||||
static bool arg_quiet = false;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_file, strv_freep);
|
||||
|
||||
static int add_match(sd_journal *j, const char *match) {
|
||||
_cleanup_free_ char *p = NULL;
|
||||
const char* prefix, *pattern;
|
||||
@ -111,6 +115,10 @@ static int acquire_journal(sd_journal **ret, char **matches) {
|
||||
r = sd_journal_open_directory(&j, arg_directory, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open journals in directory: %s: %m", arg_directory);
|
||||
} else if (arg_file) {
|
||||
r = sd_journal_open_files(&j, (const char**)arg_file, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to open journal files: %m");
|
||||
} else {
|
||||
r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
|
||||
if (r < 0)
|
||||
@ -164,6 +172,7 @@ static int help(void) {
|
||||
" -r --reverse Show the newest entries first\n"
|
||||
" -F --field=FIELD List all values a certain field takes\n"
|
||||
" -o --output=FILE Write output to FILE\n"
|
||||
" --file=PATH Use journal file\n"
|
||||
" -D --directory=DIR Use journal files from directory\n\n"
|
||||
" -q --quiet Do not show info messages and privilege warning\n"
|
||||
"\nSee the %s for details.\n"
|
||||
@ -182,6 +191,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_NO_PAGER,
|
||||
ARG_NO_LEGEND,
|
||||
ARG_DEBUGGER,
|
||||
ARG_FILE,
|
||||
};
|
||||
|
||||
int c, r;
|
||||
@ -194,6 +204,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "debugger", required_argument, NULL, ARG_DEBUGGER },
|
||||
{ "output", required_argument, NULL, 'o' },
|
||||
{ "field", required_argument, NULL, 'F' },
|
||||
{ "file", required_argument, NULL, ARG_FILE },
|
||||
{ "directory", required_argument, NULL, 'D' },
|
||||
{ "reverse", no_argument, NULL, 'r' },
|
||||
{ "since", required_argument, NULL, 'S' },
|
||||
@ -225,6 +236,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_debugger = optarg;
|
||||
break;
|
||||
|
||||
case ARG_FILE:
|
||||
r = glob_extend(&arg_file, optarg);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add paths: %m");
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
if (arg_output)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
@ -1096,6 +1113,7 @@ static int run(int argc, char *argv[]) {
|
||||
ansi_highlight_red(),
|
||||
units_active, units_active == 1 ? "unit is running" : "units are running",
|
||||
ansi_normal());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ bool suitable_user_name(const char *name) {
|
||||
* restrictive, so that we can change the rules server-side without having to update things
|
||||
* client-side too. */
|
||||
|
||||
if (!valid_user_group_name(name))
|
||||
if (!valid_user_group_name(name, 0))
|
||||
return false;
|
||||
|
||||
/* We generally rely on NSS to tell us which users not to care for, but let's filter out some
|
||||
|
@ -540,7 +540,7 @@ static int inspect_home(int argc, char *argv[], void *userdata) {
|
||||
|
||||
r = parse_uid(*i, &uid);
|
||||
if (r < 0) {
|
||||
if (!valid_user_group_name(*i)) {
|
||||
if (!valid_user_group_name(*i, 0)) {
|
||||
log_error("Invalid user name '%s'.", *i);
|
||||
if (ret == 0)
|
||||
ret = -EINVAL;
|
||||
@ -1395,7 +1395,7 @@ static int create_home(int argc, char *argv[], void *userdata) {
|
||||
if (argc >= 2) {
|
||||
/* If a username was specified, use it */
|
||||
|
||||
if (valid_user_group_name(argv[1]))
|
||||
if (valid_user_group_name(argv[1], 0))
|
||||
r = json_variant_set_field_string(&arg_identity_extra, "userName", argv[1]);
|
||||
else {
|
||||
_cleanup_free_ char *un = NULL, *rr = NULL;
|
||||
@ -3357,7 +3357,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (!valid_user_group_name(word))
|
||||
if (!valid_user_group_name(word, 0))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid group name %s.", word);
|
||||
|
||||
mo = json_variant_ref(json_variant_by_key(arg_identity_extra, "memberOf"));
|
||||
|
@ -81,7 +81,7 @@ static int method_get_home_by_name(
|
||||
r = sd_bus_message_read(message, "s", &user_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!valid_user_group_name(user_name))
|
||||
if (!valid_user_group_name(user_name, 0))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name);
|
||||
|
||||
h = hashmap_get(m->homes_by_name, user_name);
|
||||
@ -212,7 +212,7 @@ static int method_get_user_record_by_name(
|
||||
r = sd_bus_message_read(message, "s", &user_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (!valid_user_group_name(user_name))
|
||||
if (!valid_user_group_name(user_name, 0))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name);
|
||||
|
||||
h = hashmap_get(m->homes_by_name, user_name);
|
||||
@ -287,7 +287,7 @@ static int generic_home_method(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!valid_user_group_name(user_name))
|
||||
if (!valid_user_group_name(user_name, 0))
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name %s is not valid", user_name);
|
||||
|
||||
h = hashmap_get(m->homes_by_name, user_name);
|
||||
|
@ -45,9 +45,12 @@ static int parse_argv(
|
||||
else if (please_suspend)
|
||||
*please_suspend = k;
|
||||
|
||||
} else if (streq(argv[i], "debug")) {
|
||||
if (debug)
|
||||
*debug = true;
|
||||
|
||||
} else if ((v = startswith(argv[i], "debug="))) {
|
||||
int k;
|
||||
|
||||
k = parse_boolean(v);
|
||||
if (k < 0)
|
||||
pam_syslog(handle, LOG_WARNING, "Failed to parse debug= argument, ignoring: %s", v);
|
||||
@ -88,7 +91,7 @@ static int acquire_user_record(
|
||||
|
||||
/* Let's bypass all IPC complexity for the two user names we know for sure we don't manage, and for
|
||||
* user names we don't consider valid. */
|
||||
if (STR_IN_SET(username, "root", NOBODY_USER_NAME) || !valid_user_group_name(username))
|
||||
if (STR_IN_SET(username, "root", NOBODY_USER_NAME) || !valid_user_group_name(username, 0))
|
||||
return PAM_USER_UNKNOWN;
|
||||
|
||||
/* Let's check if a previous run determined that this user is not managed by homed. If so, let's exit early */
|
||||
|
@ -786,7 +786,7 @@ static int help(void) {
|
||||
" --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] XZ-compress the output journal (default: yes)\n"
|
||||
" --compress[=BOOL] Use compression in the output journal (default: yes)\n"
|
||||
" --seal[=BOOL] Use event sealing (default: no)\n"
|
||||
" --key=FILENAME SSL key in PEM format (default:\n"
|
||||
" \"" PRIV_KEY_FILE "\")\n"
|
||||
|
@ -488,7 +488,7 @@ static int import_file(struct trie *trie, const char *filename, uint16_t file_pr
|
||||
size_t len;
|
||||
char *pos;
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
r = read_line_full(f, LONG_LINE_MAX, READ_LINE_NOT_A_TTY, &line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
|
@ -3170,6 +3170,12 @@ static int method_set_wall_message(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Short-circuit the operation if the desired state is already in place, to
|
||||
* avoid an unnecessary polkit permission check. */
|
||||
if (streq_ptr(m->wall_message, empty_to_null(wall_message)) &&
|
||||
m->enable_wall_messages == enable_wall_messages)
|
||||
goto done;
|
||||
|
||||
r = bus_verify_polkit_async(message,
|
||||
CAP_SYS_ADMIN,
|
||||
"org.freedesktop.login1.set-wall-message",
|
||||
@ -3189,6 +3195,7 @@ static int method_set_wall_message(
|
||||
|
||||
m->enable_wall_messages = enable_wall_messages;
|
||||
|
||||
done:
|
||||
return sd_bus_reply_method_return(message, NULL);
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,10 @@ int config_parse_ip_protocol(
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
uint8_t *protocol = data;
|
||||
uint8_t *ret = data;
|
||||
unsigned protocol;
|
||||
/* linux/fou.h defines the netlink field as one byte, so we need to reject protocols numbers that
|
||||
* don't fit in one byte. */
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
@ -158,19 +161,26 @@ int config_parse_ip_protocol(
|
||||
assert(rvalue);
|
||||
assert(data);
|
||||
|
||||
assert_cc(IPPROTO_MAX-1 <= UINT8_MAX);
|
||||
|
||||
r = parse_ip_protocol(rvalue);
|
||||
if (r < 0) {
|
||||
r = safe_atou8(rvalue, protocol);
|
||||
if (r >= 0)
|
||||
protocol = r;
|
||||
else {
|
||||
r = safe_atou(rvalue, &protocol);
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Failed to parse IP protocol '%s' for Foo over UDP tunnel, "
|
||||
"Failed to parse IP protocol '%s' for FooOverUDP tunnel, "
|
||||
"ignoring assignment: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*protocol = r;
|
||||
if (protocol > UINT8_MAX) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, 0,
|
||||
"IP protocol '%s' for FooOverUDP tunnel out of range, "
|
||||
"ignoring assignment: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
*ret = protocol;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -203,7 +213,7 @@ int config_parse_fou_tunnel_address(
|
||||
r = in_addr_from_string_auto(rvalue, f, addr);
|
||||
if (r < 0)
|
||||
log_syntax(unit, LOG_ERR, filename, line, r,
|
||||
"Foo over UDP tunnel '%s' address is invalid, ignoring assignment: %s",
|
||||
"FooOverUDP tunnel '%s' address is invalid, ignoring assignment: %s",
|
||||
lvalue, rvalue);
|
||||
|
||||
return 0;
|
||||
|
@ -95,7 +95,7 @@ enum nss_status _nss_systemd_getpwnam_r(
|
||||
/* If the username is not valid, then we don't know it. Ideally libc would filter these for us
|
||||
* anyway. We don't generate EINVAL here, because it isn't really out business to complain about
|
||||
* invalid user names. */
|
||||
if (!valid_user_group_name(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
/* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
|
||||
@ -192,7 +192,7 @@ enum nss_status _nss_systemd_getgrnam_r(
|
||||
assert(gr);
|
||||
assert(errnop);
|
||||
|
||||
if (!valid_user_group_name(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
/* Synthesize records for root and nobody, in case they are missing from /etc/group */
|
||||
@ -559,7 +559,7 @@ enum nss_status _nss_systemd_initgroups_dyn(
|
||||
assert(groupsp);
|
||||
assert(errnop);
|
||||
|
||||
if (!valid_user_group_name(user_name))
|
||||
if (!valid_user_group_name(user_name, VALID_USER_RELAX))
|
||||
return NSS_STATUS_NOTFOUND;
|
||||
|
||||
/* Don't allow extending these two special users, the same as we won't resolve them via getpwnam() */
|
||||
|
@ -37,6 +37,8 @@ void etc_hosts_free(EtcHosts *hosts) {
|
||||
void manager_etc_hosts_flush(Manager *m) {
|
||||
etc_hosts_free(&m->etc_hosts);
|
||||
m->etc_hosts_mtime = USEC_INFINITY;
|
||||
m->etc_hosts_ino = 0;
|
||||
m->etc_hosts_dev = 0;
|
||||
}
|
||||
|
||||
static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) {
|
||||
@ -224,8 +226,9 @@ static int manager_etc_hosts_read(Manager *m) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Did the mtime change? If not, there's no point in re-reading the file. */
|
||||
if (timespec_load(&st.st_mtim) == m->etc_hosts_mtime)
|
||||
/* Did the mtime or ino/dev change? If not, there's no point in re-reading the file. */
|
||||
if (timespec_load(&st.st_mtim) == m->etc_hosts_mtime &&
|
||||
st.st_ino == m->etc_hosts_ino && st.st_dev == m->etc_hosts_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -249,6 +252,8 @@ static int manager_etc_hosts_read(Manager *m) {
|
||||
return r;
|
||||
|
||||
m->etc_hosts_mtime = timespec_load(&st.st_mtim);
|
||||
m->etc_hosts_ino = st.st_ino;
|
||||
m->etc_hosts_dev = st.st_dev;
|
||||
m->etc_hosts_last = ts;
|
||||
|
||||
return 1;
|
||||
|
@ -591,6 +591,8 @@ int manager_new(Manager **ret) {
|
||||
.need_builtin_fallbacks = true,
|
||||
.etc_hosts_last = USEC_INFINITY,
|
||||
.etc_hosts_mtime = USEC_INFINITY,
|
||||
.etc_hosts_ino = 0,
|
||||
.etc_hosts_dev = 0,
|
||||
.read_etc_hosts = true,
|
||||
};
|
||||
|
||||
|
@ -127,6 +127,8 @@ struct Manager {
|
||||
/* Data from /etc/hosts */
|
||||
EtcHosts etc_hosts;
|
||||
usec_t etc_hosts_last, etc_hosts_mtime;
|
||||
ino_t etc_hosts_ino;
|
||||
dev_t etc_hosts_dev;
|
||||
bool read_etc_hosts;
|
||||
|
||||
/* Local DNS stub on 127.0.0.53:53 */
|
||||
|
@ -283,9 +283,9 @@ static int write_uplink_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSe
|
||||
"# This is a dynamic resolv.conf file for connecting local clients directly to\n"
|
||||
"# all known uplink DNS servers. This file lists all configured search domains.\n"
|
||||
"#\n"
|
||||
"# Third party programs must not access this file directly, but only through the\n"
|
||||
"# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,\n"
|
||||
"# replace this symlink by a static file or a different symlink.\n"
|
||||
"# Third party programs should typically not access this file directly, but only\n"
|
||||
"# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a\n"
|
||||
"# different way, replace this symlink by a static file or a different symlink.\n"
|
||||
"#\n"
|
||||
"# See man:systemd-resolved.service(8) for details about the supported modes of\n"
|
||||
"# operation for /etc/resolv.conf.\n"
|
||||
@ -308,24 +308,24 @@ static int write_uplink_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSe
|
||||
}
|
||||
|
||||
static int write_stub_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) {
|
||||
fputs_unlocked("# This file is managed by man:systemd-resolved(8). Do not edit.\n"
|
||||
"#\n"
|
||||
"# This is a dynamic resolv.conf file for connecting local clients to the\n"
|
||||
"# internal DNS stub resolver of systemd-resolved. This file lists all\n"
|
||||
"# configured search domains.\n"
|
||||
"#\n"
|
||||
"# Run \"resolvectl status\" to see details about the uplink DNS servers\n"
|
||||
"# currently in use.\n"
|
||||
"#\n"
|
||||
"# Third party programs must not access this file directly, but only through the\n"
|
||||
"# symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a different way,\n"
|
||||
"# replace this symlink by a static file or a different symlink.\n"
|
||||
"#\n"
|
||||
"# See man:systemd-resolved.service(8) for details about the supported modes of\n"
|
||||
"# operation for /etc/resolv.conf.\n"
|
||||
"\n"
|
||||
"nameserver 127.0.0.53\n"
|
||||
"options edns0\n", f);
|
||||
fputs("# This file is managed by man:systemd-resolved(8). Do not edit.\n"
|
||||
"#\n"
|
||||
"# This is a dynamic resolv.conf file for connecting local clients to the\n"
|
||||
"# internal DNS stub resolver of systemd-resolved. This file lists all\n"
|
||||
"# configured search domains.\n"
|
||||
"#\n"
|
||||
"# Run \"resolvectl status\" to see details about the uplink DNS servers\n"
|
||||
"# currently in use.\n"
|
||||
"#\n"
|
||||
"# Third party programs should typically not access this file directly, but only\n"
|
||||
"# through the symlink at /etc/resolv.conf. To manage man:resolv.conf(5) in a\n"
|
||||
"# different way, replace this symlink by a static file or a different symlink.\n"
|
||||
"#\n"
|
||||
"# See man:systemd-resolved.service(8) for details about the supported modes of\n"
|
||||
"# operation for /etc/resolv.conf.\n"
|
||||
"\n"
|
||||
"nameserver 127.0.0.53\n"
|
||||
"options edns0\n", f);
|
||||
|
||||
if (!ordered_set_isempty(domains))
|
||||
write_resolv_conf_search(domains, f);
|
||||
|
@ -294,7 +294,7 @@ int config_parse(const char *unit,
|
||||
_cleanup_fclose_ FILE *ours = NULL;
|
||||
unsigned line = 0, section_line = 0;
|
||||
bool section_ignored = false, bom_seen = false;
|
||||
int r;
|
||||
int r, fd;
|
||||
|
||||
assert(filename);
|
||||
assert(lookup);
|
||||
@ -311,7 +311,9 @@ int config_parse(const char *unit,
|
||||
}
|
||||
}
|
||||
|
||||
fd_warn_permissions(filename, fileno(f));
|
||||
fd = fileno(f);
|
||||
if (fd >= 0) /* stream might not have an fd, let's be careful hence */
|
||||
fd_warn_permissions(filename, fd);
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
|
@ -1188,6 +1188,8 @@ static int decrypt_partition(
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to initialize dm-crypt: %m");
|
||||
|
||||
crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
|
||||
|
||||
r = crypt_load(cd, CRYPT_LUKS, NULL);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "Failed to load LUKS metadata: %m");
|
||||
@ -1246,6 +1248,8 @@ static int verity_partition(
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
crypt_set_log_callback(cd, cryptsetup_log_glue, NULL);
|
||||
|
||||
r = crypt_load(cd, CRYPT_VERITY, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
@ -86,8 +86,8 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
|
||||
{ "matchMachineId", _JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
|
||||
{ "matchHostname", _JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(GroupRecord, gid), 0 },
|
||||
{ "members", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, members), 0 },
|
||||
{ "administrators", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, administrators), 0 },
|
||||
{ "members", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, members), JSON_RELAX},
|
||||
{ "administrators", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, administrators), JSON_RELAX},
|
||||
{},
|
||||
};
|
||||
|
||||
@ -190,14 +190,14 @@ int group_record_load(
|
||||
UserRecordLoadFlags load_flags) {
|
||||
|
||||
static const JsonDispatch group_dispatch_table[] = {
|
||||
{ "groupName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(GroupRecord, group_name), 0 },
|
||||
{ "groupName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(GroupRecord, group_name), JSON_RELAX},
|
||||
{ "realm", JSON_VARIANT_STRING, json_dispatch_realm, offsetof(GroupRecord, realm), 0 },
|
||||
{ "disposition", JSON_VARIANT_STRING, json_dispatch_user_disposition, offsetof(GroupRecord, disposition), 0 },
|
||||
{ "service", JSON_VARIANT_STRING, json_dispatch_string, offsetof(GroupRecord, service), JSON_SAFE },
|
||||
{ "lastChangeUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(GroupRecord, last_change_usec), 0 },
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(GroupRecord, gid), 0 },
|
||||
{ "members", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, members), 0 },
|
||||
{ "administrators", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, administrators), 0 },
|
||||
{ "members", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, members), JSON_RELAX},
|
||||
{ "administrators", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(GroupRecord, administrators), JSON_RELAX},
|
||||
|
||||
{ "privileged", JSON_VARIANT_OBJECT, dispatch_privileged, 0, 0 },
|
||||
|
||||
|
@ -4107,7 +4107,7 @@ int json_dispatch_user_group_name(const char *name, JsonVariant *variant, JsonDi
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
|
||||
|
||||
n = json_variant_string(variant);
|
||||
if (!valid_user_group_name_compat(n))
|
||||
if (!valid_user_group_name(n, FLAGS_SET(flags, JSON_RELAX) ? VALID_USER_RELAX : 0))
|
||||
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid user/group name.", strna(name));
|
||||
|
||||
r = free_and_strdup(s, n);
|
||||
|
@ -255,6 +255,7 @@ typedef enum JsonDispatchFlags {
|
||||
JSON_MANDATORY = 1 << 1, /* Should existence of this property be mandatory? */
|
||||
JSON_LOG = 1 << 2, /* Should the parser log about errors? */
|
||||
JSON_SAFE = 1 << 3, /* Don't accept "unsafe" strings in json_dispatch_string() + json_dispatch_string() */
|
||||
JSON_RELAX = 1 << 4, /* Use relaxed user name checking in json_dispatch_user_group_name */
|
||||
|
||||
/* The following two may be passed into log_json() in addition to the three above */
|
||||
JSON_DEBUG = 1 << 4, /* Indicates that this log message is a debug message */
|
||||
|
@ -223,7 +223,7 @@ static int calculate_swap_file_offset(const SwapEntry *swap, uint64_t *ret_offse
|
||||
|
||||
fd = open(swap->device, O_RDONLY|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd < 0)
|
||||
return log_error_errno(errno, "Failed to open %s: %m", swap->device);
|
||||
return log_error_errno(errno, "Failed to open swap file %s to determine on-disk offset: %m", swap->device);
|
||||
|
||||
if (fstat(fd, &sb) < 0)
|
||||
return log_error_errno(errno, "Failed to stat %s: %m", swap->device);
|
||||
|
@ -600,7 +600,7 @@ int json_dispatch_user_group_list(const char *name, JsonVariant *variant, JsonDi
|
||||
if (!json_variant_is_string(e))
|
||||
return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
|
||||
|
||||
if (!valid_user_group_name_compat(json_variant_string(e)))
|
||||
if (!valid_user_group_name(json_variant_string(e), FLAGS_SET(flags, JSON_RELAX) ? VALID_USER_RELAX : 0))
|
||||
return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a valid user/group name: %s", json_variant_string(e));
|
||||
|
||||
r = strv_extend(&l, json_variant_string(e));
|
||||
@ -938,7 +938,7 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
|
||||
{ "imagePath", JSON_VARIANT_STRING, json_dispatch_path, offsetof(UserRecord, image_path), 0 },
|
||||
{ "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
|
||||
{ "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), 0 },
|
||||
{ "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
|
||||
{ "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
|
||||
{ "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
|
||||
{ "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
|
||||
@ -1231,7 +1231,7 @@ int user_group_record_mangle(
|
||||
int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_flags) {
|
||||
|
||||
static const JsonDispatch user_dispatch_table[] = {
|
||||
{ "userName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(UserRecord, user_name), 0 },
|
||||
{ "userName", JSON_VARIANT_STRING, json_dispatch_user_group_name, offsetof(UserRecord, user_name), JSON_RELAX},
|
||||
{ "realm", JSON_VARIANT_STRING, json_dispatch_realm, offsetof(UserRecord, realm), 0 },
|
||||
{ "realName", JSON_VARIANT_STRING, json_dispatch_gecos, offsetof(UserRecord, real_name), 0 },
|
||||
{ "emailAddress", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, email_address), JSON_SAFE },
|
||||
@ -1270,7 +1270,7 @@ int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_fla
|
||||
{ "homeDirectory", JSON_VARIANT_STRING, json_dispatch_home_directory, offsetof(UserRecord, home_directory), 0 },
|
||||
{ "uid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, uid), 0 },
|
||||
{ "gid", JSON_VARIANT_UNSIGNED, json_dispatch_uid_gid, offsetof(UserRecord, gid), 0 },
|
||||
{ "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), 0 },
|
||||
{ "memberOf", JSON_VARIANT_ARRAY, json_dispatch_user_group_list, offsetof(UserRecord, member_of), JSON_RELAX},
|
||||
{ "fileSystemType", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, file_system_type), JSON_SAFE },
|
||||
{ "partitionUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, partition_uuid), 0 },
|
||||
{ "luksUuid", JSON_VARIANT_STRING, json_dispatch_id128, offsetof(UserRecord, luks_uuid), 0 },
|
||||
|
@ -587,7 +587,7 @@ int userdb_by_name(const char *name, UserDBFlags flags, UserRecord **ret) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *query = NULL;
|
||||
int r;
|
||||
|
||||
if (!valid_user_group_name_compat(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return -EINVAL;
|
||||
|
||||
r = json_build(&query, JSON_BUILD_OBJECT(
|
||||
@ -795,7 +795,7 @@ int groupdb_by_name(const char *name, UserDBFlags flags, GroupRecord **ret) {
|
||||
_cleanup_(json_variant_unrefp) JsonVariant *query = NULL;
|
||||
int r;
|
||||
|
||||
if (!valid_user_group_name_compat(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return -EINVAL;
|
||||
|
||||
r = json_build(&query, JSON_BUILD_OBJECT(
|
||||
@ -982,7 +982,7 @@ int membershipdb_by_user(const char *name, UserDBFlags flags, UserDBIterator **r
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (!valid_user_group_name_compat(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return -EINVAL;
|
||||
|
||||
r = json_build(&query, JSON_BUILD_OBJECT(
|
||||
@ -1025,7 +1025,7 @@ int membershipdb_by_group(const char *name, UserDBFlags flags, UserDBIterator **
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (!valid_user_group_name_compat(name))
|
||||
if (!valid_user_group_name(name, VALID_USER_RELAX))
|
||||
return -EINVAL;
|
||||
|
||||
r = json_build(&query, JSON_BUILD_OBJECT(
|
||||
|
@ -158,6 +158,9 @@ _SD_BEGIN_DECLARATIONS;
|
||||
#define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
|
||||
#define SD_MESSAGE_DNSSEC_DOWNGRADE_STR SD_ID128_MAKE_STR(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57)
|
||||
|
||||
#define SD_MESSAGE_UNSAFE_USER_NAME SD_ID128_MAKE(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
|
||||
#define SD_MESSAGE_UNSAFE_USER_NAME_STR SD_ID128_MAKE_STR(b6,1f,da,c6,12,e9,4b,91,82,28,5b,99,88,43,06,1f)
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
@ -1445,7 +1445,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
||||
if (r < 0)
|
||||
log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, name);
|
||||
|
||||
if (!valid_user_group_name(resolved_name))
|
||||
if (!valid_user_group_name(resolved_name, 0))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"[%s:%u] '%s' is not a valid user or group name.",
|
||||
fname, line, resolved_name);
|
||||
@ -1548,7 +1548,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
||||
"[%s:%u] Lines of type 'm' require a group name in the third field.",
|
||||
fname, line);
|
||||
|
||||
if (!valid_user_group_name(resolved_id))
|
||||
if (!valid_user_group_name(resolved_id, 0))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"[%s:%u] '%s' is not a valid user or group name.",
|
||||
fname, line, resolved_id);
|
||||
@ -1589,7 +1589,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
|
||||
if (split_pair(resolved_id, ":", &uid, &gid) == 0) {
|
||||
r = parse_gid(gid, &i->gid);
|
||||
if (r < 0) {
|
||||
if (valid_user_group_name(gid))
|
||||
if (valid_user_group_name(gid, 0))
|
||||
i->group_name = TAKE_PTR(gid);
|
||||
else
|
||||
return log_error_errno(r, "Failed to parse GID: '%s': %m", id);
|
||||
|
@ -1123,6 +1123,10 @@ tests += [
|
||||
[],
|
||||
[]],
|
||||
|
||||
[['src/analyze/test-verify.c', 'src/analyze/analyze-verify.c', 'src/analyze/analyze-verify.h'],
|
||||
[libcore, libshared],
|
||||
[]],
|
||||
|
||||
[['src/login/test-inhibit.c'],
|
||||
[],
|
||||
[],
|
||||
|
@ -307,6 +307,12 @@ static void test_strv_split(void) {
|
||||
l = strv_split_full(" 'one' \" two\t three \"' four five", NULL, SPLIT_QUOTES | SPLIT_RELAX);
|
||||
assert_se(l);
|
||||
assert_se(strv_equal(l, (char**) input_table_quoted));
|
||||
|
||||
strv_free_erase(l);
|
||||
|
||||
l = strv_split_full("\\", NULL, SPLIT_QUOTES | SPLIT_RELAX);
|
||||
assert_se(l);
|
||||
assert_se(strv_equal(l, STRV_MAKE("\\")));
|
||||
}
|
||||
|
||||
static void test_strv_split_empty(void) {
|
||||
|
@ -63,144 +63,163 @@ static void test_uid_ptr(void) {
|
||||
assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000);
|
||||
}
|
||||
|
||||
static void test_valid_user_group_name_compat(void) {
|
||||
static void test_valid_user_group_name_relaxed(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(!valid_user_group_name_compat(NULL));
|
||||
assert_se(!valid_user_group_name_compat(""));
|
||||
assert_se(!valid_user_group_name_compat("1"));
|
||||
assert_se(!valid_user_group_name_compat("65535"));
|
||||
assert_se(!valid_user_group_name_compat("-1"));
|
||||
assert_se(!valid_user_group_name_compat("-kkk"));
|
||||
assert_se(!valid_user_group_name_compat("rööt"));
|
||||
assert_se(!valid_user_group_name_compat("."));
|
||||
assert_se(!valid_user_group_name_compat(".eff"));
|
||||
assert_se(!valid_user_group_name_compat("foo\nbar"));
|
||||
assert_se(!valid_user_group_name_compat("0123456789012345678901234567890123456789"));
|
||||
assert_se(!valid_user_group_name_or_id_compat("aaa:bbb"));
|
||||
assert_se(!valid_user_group_name_compat("."));
|
||||
assert_se(!valid_user_group_name_compat(".1"));
|
||||
assert_se(!valid_user_group_name_compat(".65535"));
|
||||
assert_se(!valid_user_group_name_compat(".-1"));
|
||||
assert_se(!valid_user_group_name_compat(".-kkk"));
|
||||
assert_se(!valid_user_group_name_compat(".rööt"));
|
||||
assert_se(!valid_user_group_name_or_id_compat(".aaa:bbb"));
|
||||
assert_se(!valid_user_group_name(NULL, VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("", VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("1", VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("65535", VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("-1", VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("foo\nbar", VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_RELAX|VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name(".aaa:bbb", VALID_USER_RELAX|VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name(".", VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("..", VALID_USER_RELAX));
|
||||
|
||||
assert_se(valid_user_group_name_compat("root"));
|
||||
assert_se(valid_user_group_name_compat("lennart"));
|
||||
assert_se(valid_user_group_name_compat("LENNART"));
|
||||
assert_se(valid_user_group_name_compat("_kkk"));
|
||||
assert_se(valid_user_group_name_compat("kkk-"));
|
||||
assert_se(valid_user_group_name_compat("kk-k"));
|
||||
assert_se(valid_user_group_name_compat("eff.eff"));
|
||||
assert_se(valid_user_group_name_compat("eff."));
|
||||
assert_se(valid_user_group_name("root", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("lennart", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("LENNART", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("_kkk", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("kkk-", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("kk-k", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("eff.eff", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("eff.", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("-kkk", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("rööt", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name(".eff", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name(".1", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name(".65535", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name(".-1", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name(".-kkk", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name(".rööt", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("...", VALID_USER_RELAX));
|
||||
|
||||
assert_se(valid_user_group_name_compat("some5"));
|
||||
assert_se(valid_user_group_name_compat("5some"));
|
||||
assert_se(valid_user_group_name_compat("INNER5NUMBER"));
|
||||
assert_se(valid_user_group_name("some5", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("5some", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("INNER5NUMBER", VALID_USER_RELAX));
|
||||
|
||||
assert_se(valid_user_group_name("piff.paff@ad.domain.example", VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("Dāvis", VALID_USER_RELAX));
|
||||
}
|
||||
|
||||
static void test_valid_user_group_name(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(!valid_user_group_name(NULL));
|
||||
assert_se(!valid_user_group_name(""));
|
||||
assert_se(!valid_user_group_name("1"));
|
||||
assert_se(!valid_user_group_name("65535"));
|
||||
assert_se(!valid_user_group_name("-1"));
|
||||
assert_se(!valid_user_group_name("-kkk"));
|
||||
assert_se(!valid_user_group_name("rööt"));
|
||||
assert_se(!valid_user_group_name("."));
|
||||
assert_se(!valid_user_group_name(".eff"));
|
||||
assert_se(!valid_user_group_name("foo\nbar"));
|
||||
assert_se(!valid_user_group_name("0123456789012345678901234567890123456789"));
|
||||
assert_se(!valid_user_group_name_or_id("aaa:bbb"));
|
||||
assert_se(!valid_user_group_name("."));
|
||||
assert_se(!valid_user_group_name(".1"));
|
||||
assert_se(!valid_user_group_name(".65535"));
|
||||
assert_se(!valid_user_group_name(".-1"));
|
||||
assert_se(!valid_user_group_name(".-kkk"));
|
||||
assert_se(!valid_user_group_name(".rööt"));
|
||||
assert_se(!valid_user_group_name_or_id(".aaa:bbb"));
|
||||
assert_se(!valid_user_group_name(NULL, 0));
|
||||
assert_se(!valid_user_group_name("", 0));
|
||||
assert_se(!valid_user_group_name("1", 0));
|
||||
assert_se(!valid_user_group_name("65535", 0));
|
||||
assert_se(!valid_user_group_name("-1", 0));
|
||||
assert_se(!valid_user_group_name("-kkk", 0));
|
||||
assert_se(!valid_user_group_name("rööt", 0));
|
||||
assert_se(!valid_user_group_name(".", 0));
|
||||
assert_se(!valid_user_group_name(".eff", 0));
|
||||
assert_se(!valid_user_group_name("foo\nbar", 0));
|
||||
assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", 0));
|
||||
assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name(".", 0));
|
||||
assert_se(!valid_user_group_name("..", 0));
|
||||
assert_se(!valid_user_group_name("...", 0));
|
||||
assert_se(!valid_user_group_name(".1", 0));
|
||||
assert_se(!valid_user_group_name(".65535", 0));
|
||||
assert_se(!valid_user_group_name(".-1", 0));
|
||||
assert_se(!valid_user_group_name(".-kkk", 0));
|
||||
assert_se(!valid_user_group_name(".rööt", 0));
|
||||
assert_se(!valid_user_group_name(".aaa:bbb", VALID_USER_ALLOW_NUMERIC));
|
||||
|
||||
assert_se(valid_user_group_name("root"));
|
||||
assert_se(valid_user_group_name("lennart"));
|
||||
assert_se(valid_user_group_name("LENNART"));
|
||||
assert_se(valid_user_group_name("_kkk"));
|
||||
assert_se(valid_user_group_name("kkk-"));
|
||||
assert_se(valid_user_group_name("kk-k"));
|
||||
assert_se(!valid_user_group_name("eff.eff"));
|
||||
assert_se(!valid_user_group_name("eff."));
|
||||
assert_se(valid_user_group_name("root", 0));
|
||||
assert_se(valid_user_group_name("lennart", 0));
|
||||
assert_se(valid_user_group_name("LENNART", 0));
|
||||
assert_se(valid_user_group_name("_kkk", 0));
|
||||
assert_se(valid_user_group_name("kkk-", 0));
|
||||
assert_se(valid_user_group_name("kk-k", 0));
|
||||
assert_se(!valid_user_group_name("eff.eff", 0));
|
||||
assert_se(!valid_user_group_name("eff.", 0));
|
||||
|
||||
assert_se(valid_user_group_name("some5"));
|
||||
assert_se(!valid_user_group_name("5some"));
|
||||
assert_se(valid_user_group_name("INNER5NUMBER"));
|
||||
assert_se(valid_user_group_name("some5", 0));
|
||||
assert_se(!valid_user_group_name("5some", 0));
|
||||
assert_se(valid_user_group_name("INNER5NUMBER", 0));
|
||||
|
||||
assert_se(!valid_user_group_name("piff.paff@ad.domain.example", 0));
|
||||
assert_se(!valid_user_group_name("Dāvis", 0));
|
||||
}
|
||||
|
||||
static void test_valid_user_group_name_or_id_compat(void) {
|
||||
static void test_valid_user_group_name_or_numeric_relaxed(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(!valid_user_group_name_or_id_compat(NULL));
|
||||
assert_se(!valid_user_group_name_or_id_compat(""));
|
||||
assert_se(valid_user_group_name_or_id_compat("0"));
|
||||
assert_se(valid_user_group_name_or_id_compat("1"));
|
||||
assert_se(valid_user_group_name_or_id_compat("65534"));
|
||||
assert_se(!valid_user_group_name_or_id_compat("65535"));
|
||||
assert_se(valid_user_group_name_or_id_compat("65536"));
|
||||
assert_se(!valid_user_group_name_or_id_compat("-1"));
|
||||
assert_se(!valid_user_group_name_or_id_compat("-kkk"));
|
||||
assert_se(!valid_user_group_name_or_id_compat("rööt"));
|
||||
assert_se(!valid_user_group_name_or_id_compat("."));
|
||||
assert_se(!valid_user_group_name_or_id_compat(".eff"));
|
||||
assert_se(valid_user_group_name_or_id_compat("eff.eff"));
|
||||
assert_se(valid_user_group_name_or_id_compat("eff."));
|
||||
assert_se(!valid_user_group_name_or_id_compat("foo\nbar"));
|
||||
assert_se(!valid_user_group_name_or_id_compat("0123456789012345678901234567890123456789"));
|
||||
assert_se(!valid_user_group_name_or_id_compat("aaa:bbb"));
|
||||
assert_se(!valid_user_group_name(NULL, VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("0", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("1", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("65534", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("65535", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("65536", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("-1", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("foo\nbar", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name(".", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(!valid_user_group_name("..", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
|
||||
assert_se(valid_user_group_name_or_id_compat("root"));
|
||||
assert_se(valid_user_group_name_or_id_compat("lennart"));
|
||||
assert_se(valid_user_group_name_or_id_compat("LENNART"));
|
||||
assert_se(valid_user_group_name_or_id_compat("_kkk"));
|
||||
assert_se(valid_user_group_name_or_id_compat("kkk-"));
|
||||
assert_se(valid_user_group_name_or_id_compat("kk-k"));
|
||||
assert_se(valid_user_group_name("root", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("lennart", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("LENNART", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("_kkk", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("kkk-", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("kk-k", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("-kkk", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("rööt", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name(".eff", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("eff.eff", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("eff.", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("...", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
|
||||
assert_se(valid_user_group_name_or_id_compat("some5"));
|
||||
assert_se(valid_user_group_name_or_id_compat("5some"));
|
||||
assert_se(valid_user_group_name_or_id_compat("INNER5NUMBER"));
|
||||
assert_se(valid_user_group_name("some5", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("5some", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("INNER5NUMBER", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
|
||||
assert_se(valid_user_group_name("piff.paff@ad.domain.example", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
assert_se(valid_user_group_name("Dāvis", VALID_USER_ALLOW_NUMERIC|VALID_USER_RELAX));
|
||||
}
|
||||
|
||||
static void test_valid_user_group_name_or_id(void) {
|
||||
static void test_valid_user_group_name_or_numeric(void) {
|
||||
log_info("/* %s */", __func__);
|
||||
|
||||
assert_se(!valid_user_group_name_or_id(NULL));
|
||||
assert_se(!valid_user_group_name_or_id(""));
|
||||
assert_se(valid_user_group_name_or_id("0"));
|
||||
assert_se(valid_user_group_name_or_id("1"));
|
||||
assert_se(valid_user_group_name_or_id("65534"));
|
||||
assert_se(!valid_user_group_name_or_id("65535"));
|
||||
assert_se(valid_user_group_name_or_id("65536"));
|
||||
assert_se(!valid_user_group_name_or_id("-1"));
|
||||
assert_se(!valid_user_group_name_or_id("-kkk"));
|
||||
assert_se(!valid_user_group_name_or_id("rööt"));
|
||||
assert_se(!valid_user_group_name_or_id("."));
|
||||
assert_se(!valid_user_group_name_or_id(".eff"));
|
||||
assert_se(!valid_user_group_name_or_id("eff.eff"));
|
||||
assert_se(!valid_user_group_name_or_id("eff."));
|
||||
assert_se(!valid_user_group_name_or_id("foo\nbar"));
|
||||
assert_se(!valid_user_group_name_or_id("0123456789012345678901234567890123456789"));
|
||||
assert_se(!valid_user_group_name_or_id("aaa:bbb"));
|
||||
assert_se(!valid_user_group_name(NULL, VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(valid_user_group_name("0", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(valid_user_group_name("1", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(valid_user_group_name("65534", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("65535", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(valid_user_group_name("65536", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("-1", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("-kkk", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("rööt", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name(".", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("..", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("...", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name(".eff", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("eff.eff", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("eff.", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("foo\nbar", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("0123456789012345678901234567890123456789", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("aaa:bbb", VALID_USER_ALLOW_NUMERIC));
|
||||
|
||||
assert_se(valid_user_group_name_or_id("root"));
|
||||
assert_se(valid_user_group_name_or_id("lennart"));
|
||||
assert_se(valid_user_group_name_or_id("LENNART"));
|
||||
assert_se(valid_user_group_name_or_id("_kkk"));
|
||||
assert_se(valid_user_group_name_or_id("kkk-"));
|
||||
assert_se(valid_user_group_name_or_id("kk-k"));
|
||||
assert_se(valid_user_group_name("root", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(valid_user_group_name("lennart", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(valid_user_group_name("LENNART", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(valid_user_group_name("_kkk", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(valid_user_group_name("kkk-", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(valid_user_group_name("kk-k", VALID_USER_ALLOW_NUMERIC));
|
||||
|
||||
assert_se(valid_user_group_name_or_id("some5"));
|
||||
assert_se(!valid_user_group_name_or_id("5some"));
|
||||
assert_se(valid_user_group_name_or_id("INNER5NUMBER"));
|
||||
assert_se(valid_user_group_name("some5", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("5some", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(valid_user_group_name("INNER5NUMBER", VALID_USER_ALLOW_NUMERIC));
|
||||
|
||||
assert_se(!valid_user_group_name("piff.paff@ad.domain.example", VALID_USER_ALLOW_NUMERIC));
|
||||
assert_se(!valid_user_group_name("Dāvis", VALID_USER_ALLOW_NUMERIC));
|
||||
}
|
||||
|
||||
static void test_valid_gecos(void) {
|
||||
@ -355,10 +374,10 @@ int main(int argc, char *argv[]) {
|
||||
test_parse_uid();
|
||||
test_uid_ptr();
|
||||
|
||||
test_valid_user_group_name_compat();
|
||||
test_valid_user_group_name_relaxed();
|
||||
test_valid_user_group_name();
|
||||
test_valid_user_group_name_or_id_compat();
|
||||
test_valid_user_group_name_or_id();
|
||||
test_valid_user_group_name_or_numeric_relaxed();
|
||||
test_valid_user_group_name_or_numeric();
|
||||
test_valid_gecos();
|
||||
test_valid_home();
|
||||
|
||||
|
@ -490,7 +490,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
|
||||
|
||||
if (config->alternative_names_policy)
|
||||
for (NamePolicy *p = config->alternative_names_policy; *p != _NAMEPOLICY_INVALID; p++) {
|
||||
const char *n;
|
||||
const char *n = NULL;
|
||||
|
||||
switch (*p) {
|
||||
case NAMEPOLICY_DATABASE:
|
||||
|
@ -541,16 +541,15 @@ static int ssh_authorized_keys(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
|
||||
int r;
|
||||
|
||||
if (!valid_user_group_name(argv[1]))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid user name '%s'.", argv[1]);
|
||||
|
||||
r = userdb_by_name(argv[1], arg_userdb_flags, &ur);
|
||||
if (r == -ESRCH)
|
||||
log_error_errno(r, "User %s does not exist.", argv[1]);
|
||||
return log_error_errno(r, "User %s does not exist.", argv[1]);
|
||||
else if (r == -EHOSTDOWN)
|
||||
log_error_errno(r, "Selected user database service is not available for this request.");
|
||||
return log_error_errno(r, "Selected user database service is not available for this request.");
|
||||
else if (r == -EINVAL)
|
||||
return log_error_errno(r, "Failed to find user %s: %m (Invalid user name?)", argv[1]);
|
||||
else if (r < 0)
|
||||
log_error_errno(r, "Failed to find user %s: %m", argv[1]);
|
||||
return log_error_errno(r, "Failed to find user %s: %m", argv[1]);
|
||||
|
||||
if (strv_isempty(ur->ssh_authorized_keys))
|
||||
log_debug("User record for %s has no public SSH keys.", argv[1]);
|
||||
|
@ -12,6 +12,7 @@ systemctl status issue_14566_test
|
||||
leaked_pid=$(cat /leakedtestpid)
|
||||
|
||||
systemctl stop issue_14566_test
|
||||
sleep 1
|
||||
|
||||
# Leaked PID will still be around if we're buggy.
|
||||
# I personally prefer to see 42.
|
||||
|
Loading…
Reference in New Issue
Block a user