summaryrefslogtreecommitdiffstats
path: root/src/tmpfiles/tmpfiles.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-05-05 22:45:54 +0200
committerLennart Poettering <lennart@poettering.net>2020-05-07 16:35:20 +0200
commita3451c2c4ce7d3c02451f6ace4ee9f873880f78f (patch)
treec70382fd767603558dbf90e1b0fd19e6f18b82b1 /src/tmpfiles/tmpfiles.c
parentRevert "Add Kensington SlimBlade Trackball" (diff)
downloadsystemd-a3451c2c4ce7d3c02451f6ace4ee9f873880f78f.tar.xz
systemd-a3451c2c4ce7d3c02451f6ace4ee9f873880f78f.zip
tmpfiles: optionally, read /etc/passwd + /etc/group without NSS
There are two libc APIs for accessing the user database: NSS/getpwuid(), and fgetpwent(). if we run in --root= mode (i.e. "offline" mode), let's use the latter. Otherwise the former. This means tmpfiles can use the database included in the root environment for chowning, which is a lot more appropriate. Fixes: #14806
Diffstat (limited to 'src/tmpfiles/tmpfiles.c')
-rw-r--r--src/tmpfiles/tmpfiles.c70
1 files changed, 62 insertions, 8 deletions
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index 7137e9fbd7..37dde99ef0 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -39,6 +39,7 @@
#include "main-func.h"
#include "mkdir.h"
#include "mountpoint-util.h"
+#include "offline-passwd.h"
#include "pager.h"
#include "parse-util.h"
#include "path-lookup.h"
@@ -2487,7 +2488,63 @@ static int patch_var_run(const char *fname, unsigned line, char **path) {
return 0;
}
-static int parse_line(const char *fname, unsigned line, const char *buffer, bool *invalid_config) {
+static int find_uid(const char *user, uid_t *ret_uid, Hashmap **cache) {
+ int r;
+
+ assert(user);
+ assert(ret_uid);
+
+ /* First: parse as numeric UID string */
+ r = parse_uid(user, ret_uid);
+ if (r >= 0)
+ return r;
+
+ /* Second: pass to NSS if we are running "online" */
+ if (!arg_root)
+ return get_user_creds(&user, ret_uid, NULL, NULL, NULL, 0);
+
+ /* Third, synthesize "root" unconditionally */
+ if (streq(user, "root")) {
+ *ret_uid = 0;
+ return 0;
+ }
+
+ /* Fourth: use fgetpwent() to read /etc/passwd directly, if we are "offline" */
+ return name_to_uid_offline(arg_root, user, ret_uid, cache);
+}
+
+static int find_gid(const char *group, gid_t *ret_gid, Hashmap **cache) {
+ int r;
+
+ assert(group);
+ assert(ret_gid);
+
+ /* First: parse as numeric GID string */
+ r = parse_gid(group, ret_gid);
+ if (r >= 0)
+ return r;
+
+ /* Second: pass to NSS if we are running "online" */
+ if (!arg_root)
+ return get_group_creds(&group, ret_gid, 0);
+
+ /* Third, synthesize "root" unconditionally */
+ if (streq(group, "root")) {
+ *ret_gid = 0;
+ return 0;
+ }
+
+ /* Fourth: use fgetgrent() to read /etc/group directly, if we are "offline" */
+ return name_to_gid_offline(arg_root, group, ret_gid, cache);
+}
+
+static int parse_line(
+ const char *fname,
+ unsigned line,
+ const char *buffer,
+ bool *invalid_config,
+ Hashmap **uid_cache,
+ Hashmap **gid_cache) {
_cleanup_free_ char *action = NULL, *mode = NULL, *user = NULL, *group = NULL, *age = NULL, *path = NULL;
_cleanup_(item_free_contents) Item i = {};
@@ -2718,9 +2775,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
}
if (!empty_or_dash(user)) {
- const char *u = user;
-
- r = get_user_creds(&u, &i.uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
+ r = find_uid(user, &i.uid, uid_cache);
if (r < 0) {
*invalid_config = true;
return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve user '%s': %m", user);
@@ -2730,9 +2785,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
}
if (!empty_or_dash(group)) {
- const char *g = group;
-
- r = get_group_creds(&g, &i.gid, USER_CREDS_ALLOW_MISSING);
+ r = find_gid(group, &i.gid, gid_cache);
if (r < 0) {
*invalid_config = true;
return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve group '%s'.", group);
@@ -2981,6 +3034,7 @@ static int parse_argv(int argc, char *argv[]) {
}
static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoent, bool *invalid_config) {
+ _cleanup_(hashmap_freep) Hashmap *uid_cache = NULL, *gid_cache = NULL;
_cleanup_fclose_ FILE *_f = NULL;
Iterator iterator;
unsigned v = 0;
@@ -3026,7 +3080,7 @@ static int read_config_file(char **config_dirs, const char *fn, bool ignore_enoe
if (IN_SET(*l, 0, '#'))
continue;
- k = parse_line(fn, v, l, &invalid_line);
+ k = parse_line(fn, v, l, &invalid_line, &uid_cache, &gid_cache);
if (k < 0) {
if (invalid_line)
/* Allow reporting with a special code if the caller requested this */