<refsect1>
<title>Scope Unit Objects</title>
- <para>All slice unit objects implement the <interfacename>org.freedesktop.systemd1.Scope</interfacename>
+ <para>All scope unit objects implement the <interfacename>org.freedesktop.systemd1.Scope</interfacename>
interface (described here) in addition to the generic
<interfacename>org.freedesktop.systemd1.Unit</interfacename> interface (see above).</para>
this notification message has been sent. If this option is used, <varname>NotifyAccess=</varname> (see
below) should be set to open access to the notification socket provided by systemd. If
<varname>NotifyAccess=</varname> is missing or set to <option>none</option>, it will be forcibly set to
- <option>main</option></para></listitem>.
+ <option>main</option>.</para></listitem>
<listitem><para>Behavior of <option>idle</option> is very similar to <option>simple</option>; however,
actual execution of the service program is delayed until all active jobs are dispatched. This may be used
return true;
}
+char *mangle_gecos(const char *d) {
+ char *mangled;
+
+ /* Makes sure the provided string becomes valid as a GEGOS field, by dropping bad chars. glibc's
+ * putwent() only changes \n and : to spaces. We do more: replace all CC too, and remove invalid
+ * UTF-8 */
+
+ mangled = strdup(d);
+ if (!mangled)
+ return NULL;
+
+ for (char *i = mangled; *i; i++) {
+ int len;
+
+ if ((uint8_t) *i < (uint8_t) ' ' || *i == ':') {
+ *i = ' ';
+ continue;
+ }
+
+ len = utf8_encoded_valid_unichar(i, (size_t) -1);
+ if (len < 0) {
+ *i = ' ';
+ continue;
+ }
+
+ i += len - 1;
+ }
+
+ return mangled;
+}
+
bool valid_home(const char *p) {
/* Note that this function is also called by valid_shell(), any
* changes must account for that. */
bool valid_user_group_name(const char *u, ValidUserFlags flags);
bool valid_gecos(const char *d);
+char *mangle_gecos(const char *d);
bool valid_home(const char *p);
static inline bool valid_shell(const char *p) {
printf("%s [OPTIONS...] COMMAND\n"
"\n%sMark the boot process as good or bad.%s\n"
"\nCommands:\n"
+ " status Show status of current boot loader entry\n"
" good Mark this boot as good\n"
" bad Mark this boot as bad\n"
" indeterminate Undo any marking as good or bad\n"
static int make_tmp_subdir(const char *parent, char **ret) {
_cleanup_free_ char *y = NULL;
- RUN_WITH_UMASK(0000) {
- y = strjoin(parent, "/tmp");
- if (!y)
- return -ENOMEM;
+ y = path_join(parent, "/tmp");
+ if (!y)
+ return -ENOMEM;
+ RUN_WITH_UMASK(0000) {
if (mkdir(y, 0777 | S_ISVTX) < 0)
return -errno;
}
if (r < 0)
return r;
- x = strdup(RUN_SYSTEMD_EMPTY);
- if (!x)
- return -ENOMEM;
+ r = free_and_strdup(&x, RUN_SYSTEMD_EMPTY);
+ if (r < 0)
+ return r;
}
*path = TAKE_PTR(x);
"close\0"
"creat\0"
"faccessat\0"
+ "faccessat2\0"
"fallocate\0"
"fchdir\0"
"fchmod\0"
#include "libcrypt-util.h"
#include "strv.h"
#include "user-record-nss.h"
+#include "user-util.h"
#define SET_IF(field, condition, value, fallback) \
field = (condition) ? (value) : (fallback)
if (r < 0)
return r;
- r = free_and_strdup(&hr->real_name,
- streq_ptr(pwd->pw_gecos, hr->user_name) ? NULL : empty_to_null(pwd->pw_gecos));
- if (r < 0)
- return r;
+ /* Some bad NSS modules synthesize GECOS fields with embedded ":" or "\n" characters, which are not
+ * something we can output in /etc/passwd compatible format, since these are record separators
+ * there. We normally refuse that, but we need to maintain compatibility with arbitrary NSS modules,
+ * hence let's do what glibc does: mangle the data to fit the format. */
+ if (isempty(pwd->pw_gecos) || streq_ptr(pwd->pw_gecos, hr->user_name))
+ hr->real_name = mfree(hr->real_name);
+ else if (valid_gecos(pwd->pw_gecos)) {
+ r = free_and_strdup(&hr->real_name, pwd->pw_gecos);
+ if (r < 0)
+ return r;
+ } else {
+ _cleanup_free_ char *mangled = NULL;
+
+ mangled = mangle_gecos(pwd->pw_gecos);
+ if (!mangled)
+ return -ENOMEM;
+
+ free_and_replace(hr->real_name, mangled);
+ }
r = free_and_strdup(&hr->home_directory, empty_to_null(pwd->pw_dir));
if (r < 0)
static int json_dispatch_gecos(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
char **s = userdata;
const char *n;
- int r;
if (json_variant_is_null(variant)) {
*s = mfree(*s);
return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
n = json_variant_string(variant);
- if (!valid_gecos(n))
- return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid GECOS compatible real name.", strna(name));
+ if (valid_gecos(n)) {
+ if (free_and_strdup(s, n) < 0)
+ return json_log_oom(variant, flags);
+ } else {
+ _cleanup_free_ char *m = NULL;
- r = free_and_strdup(s, n);
- if (r < 0)
- return json_log(variant, flags, r, "Failed to allocate string: %m");
+ json_log(variant, flags|JSON_DEBUG, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid GECOS compatible string, mangling.", strna(name));
+
+ m = mangle_gecos(n);
+ if (!m)
+ return json_log_oom(variant, flags);
+
+ free_and_replace(*s, m);
+ }
return 0;
}
int r;
r = path_is_encrypted(p);
- if (r == -ENOENT) /* This might fail, if btrfs is used and we run in a container. In that case we
- * cannot resolve the device node paths that BTRFS_IOC_DEV_INFO returns, because
- * the device nodes are unlikely to exist in the container. But if we can't stat()
- * them we cannot determine the dev_t of them, and thus cannot figure out if they
- * are enrypted. Hence let's just ignore ENOENT here. */
+ if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r)) /* This might fail, if btrfs is used and we run in a
+ * container. In that case we cannot resolve the device node paths that
+ * BTRFS_IOC_DEV_INFO returns, because the device nodes are unlikely to exist in
+ * the container. But if we can't stat() them we cannot determine the dev_t of
+ * them, and thus cannot figure out if they are enrypted. Hence let's just ignore
+ * ENOENT here. Also skip the test if we lack privileges. */
return;
assert_se(r >= 0);
assert_se(parse_uid_range(" 01", &a, &b) == -EINVAL && a == 4 && b == 5);
}
+static void test_mangle_gecos_one(const char *input, const char *expected) {
+ _cleanup_free_ char *p = NULL;
+
+ assert_se(p = mangle_gecos(input));
+ assert_se(streq(p, expected));
+ assert_se(valid_gecos(p));
+}
+
+static void test_mangle_gecos(void) {
+ test_mangle_gecos_one("", "");
+ test_mangle_gecos_one("root", "root");
+ test_mangle_gecos_one("wuff\nwuff", "wuff wuff");
+ test_mangle_gecos_one("wuff:wuff", "wuff wuff");
+ test_mangle_gecos_one("wuff\r\n:wuff", "wuff wuff");
+ test_mangle_gecos_one("\n--wüff-wäff-wöff::", " --wüff-wäff-wöff ");
+ test_mangle_gecos_one("\xc3\x28", " (");
+ test_mangle_gecos_one("\xe2\x28\xa1", " ( ");
+}
+
int main(int argc, char *argv[]) {
test_uid_to_name_one(0, "root");
test_uid_to_name_one(UID_NOBODY, NOBODY_USER_NAME);
test_valid_user_group_name_or_numeric_relaxed();
test_valid_user_group_name_or_numeric();
test_valid_gecos();
+ test_mangle_gecos();
test_valid_home();
test_make_salt();
check_id(p, t)
section = t.find('./refmeta/manvolnum').text
refname = t.find('./refnamediv/refname').text
- purpose = ' '.join(t.find('./refnamediv/refpurpose').text.split())
+ purpose_text = ' '.join(t.find('./refnamediv/refpurpose').itertext())
+ purpose = ' '.join(purpose_text.split())
for f in t.findall('./refnamediv/refname'):
infos = (f.text, section, purpose, refname)
index[f.text[0].upper()].append(infos)