mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
Merge pull request #9783 from poettering/get-user-creds-flags
beef up get_user_creds() a bit and other improvements
This commit is contained in:
commit
7692fed98b
@ -87,17 +87,31 @@ char *getusername_malloc(void) {
|
||||
return uid_to_name(getuid());
|
||||
}
|
||||
|
||||
int get_user_creds(
|
||||
static inline bool is_nologin_shell(const char *shell) {
|
||||
|
||||
return PATH_IN_SET(shell,
|
||||
/* 'nologin' is the friendliest way to disable logins for a user account. It prints a nice
|
||||
* message and exits. Different distributions place the binary at different places though,
|
||||
* hence let's list them all. */
|
||||
"/bin/nologin",
|
||||
"/sbin/nologin",
|
||||
"/usr/bin/nologin",
|
||||
"/usr/sbin/nologin",
|
||||
/* 'true' and 'false' work too for the same purpose, but are less friendly as they don't do
|
||||
* any message printing. Different distributions place the binary at various places but at
|
||||
* least not in the 'sbin' directory. */
|
||||
"/bin/false",
|
||||
"/usr/bin/false",
|
||||
"/bin/true",
|
||||
"/usr/bin/true");
|
||||
}
|
||||
|
||||
static int synthesize_user_creds(
|
||||
const char **username,
|
||||
uid_t *uid, gid_t *gid,
|
||||
const char **home,
|
||||
const char **shell) {
|
||||
|
||||
struct passwd *p;
|
||||
uid_t u;
|
||||
|
||||
assert(username);
|
||||
assert(*username);
|
||||
const char **shell,
|
||||
UserCredsFlags flags) {
|
||||
|
||||
/* We enforce some special rules for uid=0 and uid=65534: in order to avoid NSS lookups for root we hardcode
|
||||
* their user record data. */
|
||||
@ -129,32 +143,85 @@ int get_user_creds(
|
||||
*gid = GID_NOBODY;
|
||||
|
||||
if (home)
|
||||
*home = "/";
|
||||
*home = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : "/";
|
||||
|
||||
if (shell)
|
||||
*shell = "/sbin/nologin";
|
||||
*shell = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : "/sbin/nologin";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -ENOMEDIUM;
|
||||
}
|
||||
|
||||
int get_user_creds(
|
||||
const char **username,
|
||||
uid_t *uid, gid_t *gid,
|
||||
const char **home,
|
||||
const char **shell,
|
||||
UserCredsFlags flags) {
|
||||
|
||||
uid_t u = UID_INVALID;
|
||||
struct passwd *p;
|
||||
int r;
|
||||
|
||||
assert(username);
|
||||
assert(*username);
|
||||
|
||||
if (!FLAGS_SET(flags, USER_CREDS_PREFER_NSS) ||
|
||||
(!home && !shell)) {
|
||||
|
||||
/* So here's the deal: normally, we'll try to synthesize all records we can synthesize, and override
|
||||
* the user database with that. However, if the user specifies USER_CREDS_PREFER_NSS then the
|
||||
* user database will override the synthetic records instead — except if the user is only interested in
|
||||
* the UID and/or GID (but not the home directory, or the shell), in which case we'll always override
|
||||
* the user database (i.e. the USER_CREDS_PREFER_NSS flag has no effect in this case). Why?
|
||||
* Simply because there are valid usecase where the user might change the home directory or the shell
|
||||
* of the relevant users, but changing the UID/GID mappings for them is something we explicitly don't
|
||||
* support. */
|
||||
|
||||
r = synthesize_user_creds(username, uid, gid, home, shell, flags);
|
||||
if (r >= 0)
|
||||
return 0;
|
||||
if (r != -ENOMEDIUM) /* not a username we can synthesize */
|
||||
return r;
|
||||
}
|
||||
|
||||
if (parse_uid(*username, &u) >= 0) {
|
||||
errno = 0;
|
||||
p = getpwuid(u);
|
||||
|
||||
/* If there are multiple users with the same id, make
|
||||
* sure to leave $USER to the configured value instead
|
||||
* of the first occurrence in the database. However if
|
||||
* the uid was configured by a numeric uid, then let's
|
||||
* pick the real username from /etc/passwd. */
|
||||
/* If there are multiple users with the same id, make sure to leave $USER to the configured value
|
||||
* instead of the first occurrence in the database. However if the uid was configured by a numeric uid,
|
||||
* then let's pick the real username from /etc/passwd. */
|
||||
if (p)
|
||||
*username = p->pw_name;
|
||||
else if (FLAGS_SET(flags, USER_CREDS_ALLOW_MISSING) && !gid && !home && !shell) {
|
||||
|
||||
/* If the specified user is a numeric UID and it isn't in the user database, and the caller
|
||||
* passed USER_CREDS_ALLOW_MISSING and was only interested in the UID, then juts return that
|
||||
* and don't complain. */
|
||||
|
||||
if (uid)
|
||||
*uid = u;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
errno = 0;
|
||||
p = getpwnam(*username);
|
||||
}
|
||||
if (!p) {
|
||||
r = errno > 0 ? -errno : -ESRCH;
|
||||
|
||||
if (!p)
|
||||
return errno > 0 ? -errno : -ESRCH;
|
||||
/* If the user requested that we only synthesize as fallback, do so now */
|
||||
if (FLAGS_SET(flags, USER_CREDS_PREFER_NSS)) {
|
||||
if (synthesize_user_creds(username, uid, gid, home, shell, flags) >= 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
if (uid) {
|
||||
if (!uid_is_valid(p->pw_uid))
|
||||
@ -170,66 +237,30 @@ int get_user_creds(
|
||||
*gid = p->pw_gid;
|
||||
}
|
||||
|
||||
if (home)
|
||||
*home = p->pw_dir;
|
||||
if (home) {
|
||||
if (FLAGS_SET(flags, USER_CREDS_CLEAN) && empty_or_root(p->pw_dir))
|
||||
*home = NULL;
|
||||
else
|
||||
*home = p->pw_dir;
|
||||
}
|
||||
|
||||
if (shell)
|
||||
*shell = p->pw_shell;
|
||||
if (shell) {
|
||||
if (FLAGS_SET(flags, USER_CREDS_CLEAN) && (isempty(p->pw_shell) || is_nologin_shell(p->pw_shell)))
|
||||
*shell = NULL;
|
||||
else
|
||||
*shell = p->pw_shell;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline bool is_nologin_shell(const char *shell) {
|
||||
|
||||
return PATH_IN_SET(shell,
|
||||
/* 'nologin' is the friendliest way to disable logins for a user account. It prints a nice
|
||||
* message and exits. Different distributions place the binary at different places though,
|
||||
* hence let's list them all. */
|
||||
"/bin/nologin",
|
||||
"/sbin/nologin",
|
||||
"/usr/bin/nologin",
|
||||
"/usr/sbin/nologin",
|
||||
/* 'true' and 'false' work too for the same purpose, but are less friendly as they don't do
|
||||
* any message printing. Different distributions place the binary at various places but at
|
||||
* least not in the 'sbin' directory. */
|
||||
"/bin/false",
|
||||
"/usr/bin/false",
|
||||
"/bin/true",
|
||||
"/usr/bin/true");
|
||||
}
|
||||
|
||||
int get_user_creds_clean(
|
||||
const char **username,
|
||||
uid_t *uid, gid_t *gid,
|
||||
const char **home,
|
||||
const char **shell) {
|
||||
|
||||
int r;
|
||||
|
||||
/* Like get_user_creds(), but resets home/shell to NULL if they don't contain anything relevant. */
|
||||
|
||||
r = get_user_creds(username, uid, gid, home, shell);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (shell &&
|
||||
(isempty(*shell) || is_nologin_shell(*shell)))
|
||||
*shell = NULL;
|
||||
|
||||
if (home && empty_or_root(*home))
|
||||
*home = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_group_creds(const char **groupname, gid_t *gid) {
|
||||
int get_group_creds(const char **groupname, gid_t *gid, UserCredsFlags flags) {
|
||||
struct group *g;
|
||||
gid_t id;
|
||||
|
||||
assert(groupname);
|
||||
|
||||
/* We enforce some special rules for gid=0: in order to avoid
|
||||
* NSS lookups for root we hardcode its data. */
|
||||
/* We enforce some special rules for gid=0: in order to avoid NSS lookups for root we hardcode its data. */
|
||||
|
||||
if (STR_IN_SET(*groupname, "root", "0")) {
|
||||
*groupname = "root";
|
||||
@ -256,6 +287,12 @@ int get_group_creds(const char **groupname, gid_t *gid) {
|
||||
|
||||
if (g)
|
||||
*groupname = g->gr_name;
|
||||
else if (FLAGS_SET(flags, USER_CREDS_ALLOW_MISSING)) {
|
||||
if (gid)
|
||||
*gid = id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
errno = 0;
|
||||
g = getgrnam(*groupname);
|
||||
@ -391,7 +428,7 @@ int in_group(const char *name) {
|
||||
int r;
|
||||
gid_t gid;
|
||||
|
||||
r = get_group_creds(&name, &gid);
|
||||
r = get_group_creds(&name, &gid, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -25,9 +25,14 @@ static inline int parse_gid(const char *s, gid_t *ret_gid) {
|
||||
char* getlogname_malloc(void);
|
||||
char* getusername_malloc(void);
|
||||
|
||||
int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
|
||||
int get_user_creds_clean(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell);
|
||||
int get_group_creds(const char **groupname, gid_t *gid);
|
||||
typedef enum UserCredsFlags {
|
||||
USER_CREDS_PREFER_NSS = 1 << 0, /* if set, only synthesize user records if database lacks them. Normally we bypass the userdb entirely for the records we can synthesize */
|
||||
USER_CREDS_ALLOW_MISSING = 1 << 1, /* if a numeric UID string is resolved, be OK if there's no record for it */
|
||||
USER_CREDS_CLEAN = 1 << 2, /* try to clean up shell and home fields with invalid data */
|
||||
} UserCredsFlags;
|
||||
|
||||
int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const char **home, const char **shell, UserCredsFlags flags);
|
||||
int get_group_creds(const char **groupname, gid_t *gid, UserCredsFlags flags);
|
||||
|
||||
char* uid_to_name(uid_t uid);
|
||||
char* gid_to_name(gid_t gid);
|
||||
|
@ -921,7 +921,7 @@ static int get_fixed_user(const ExecContext *c, const char **user,
|
||||
* (i.e. are "/" or "/bin/nologin"). */
|
||||
|
||||
name = c->user;
|
||||
r = get_user_creds_clean(&name, uid, gid, home, shell);
|
||||
r = get_user_creds(&name, uid, gid, home, shell, USER_CREDS_CLEAN);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -939,7 +939,7 @@ static int get_fixed_group(const ExecContext *c, const char **group, gid_t *gid)
|
||||
return 0;
|
||||
|
||||
name = c->group;
|
||||
r = get_group_creds(&name, gid);
|
||||
r = get_group_creds(&name, gid, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1011,7 +1011,7 @@ static int get_supplementary_groups(const ExecContext *c, const char *user,
|
||||
return -E2BIG;
|
||||
|
||||
g = *i;
|
||||
r = get_group_creds(&g, l_gids+k);
|
||||
r = get_group_creds(&g, l_gids+k, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -570,36 +570,44 @@ static void drop_outside_root(const char *root_directory, MountEntry *m, size_t
|
||||
*n = t - m;
|
||||
}
|
||||
|
||||
static int clone_device_node(const char *d, const char *temporary_mount, bool *make_devnode) {
|
||||
const char *dn;
|
||||
static int clone_device_node(
|
||||
const char *d,
|
||||
const char *temporary_mount,
|
||||
bool *make_devnode) {
|
||||
|
||||
_cleanup_free_ char *sl = NULL;
|
||||
const char *dn, *bn, *t;
|
||||
struct stat st;
|
||||
int r;
|
||||
|
||||
if (stat(d, &st) < 0) {
|
||||
if (errno == ENOENT)
|
||||
if (errno == ENOENT) {
|
||||
log_debug_errno(errno, "Device node '%s' to clone does not exist, ignoring.", d);
|
||||
return -ENXIO;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return log_debug_errno(errno, "Failed to stat() device node '%s' to clone, ignoring: %m", d);
|
||||
}
|
||||
|
||||
if (!S_ISBLK(st.st_mode) &&
|
||||
!S_ISCHR(st.st_mode))
|
||||
!S_ISCHR(st.st_mode)) {
|
||||
log_debug("Device node '%s' to clone is not a device node, ignoring.", d);
|
||||
return -EINVAL;
|
||||
|
||||
if (st.st_rdev == 0)
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
dn = strjoina(temporary_mount, d);
|
||||
|
||||
/* First, try to create device node properly */
|
||||
if (*make_devnode) {
|
||||
mac_selinux_create_file_prepare(d, st.st_mode);
|
||||
r = mknod(dn, st.st_mode, st.st_rdev);
|
||||
mac_selinux_create_file_clear();
|
||||
|
||||
if (r == 0)
|
||||
return 0;
|
||||
if (r >= 0)
|
||||
goto add_symlink;
|
||||
if (errno != EPERM)
|
||||
return log_debug_errno(errno, "mknod failed for %s: %m", d);
|
||||
|
||||
/* This didn't work, let's not try this again for the next iterations. */
|
||||
*make_devnode = false;
|
||||
}
|
||||
|
||||
@ -608,9 +616,8 @@ static int clone_device_node(const char *d, const char *temporary_mount, bool *m
|
||||
mac_selinux_create_file_prepare(d, 0);
|
||||
r = mknod(dn, S_IFREG, 0);
|
||||
mac_selinux_create_file_clear();
|
||||
|
||||
if (r < 0 && errno != EEXIST)
|
||||
return log_debug_errno(errno, "mknod fallback failed for %s: %m", d);
|
||||
return log_debug_errno(errno, "mknod() fallback failed for '%s': %m", d);
|
||||
|
||||
/* Fallback to bind-mounting:
|
||||
* The assumption here is that all used device nodes carry standard
|
||||
@ -618,7 +625,23 @@ static int clone_device_node(const char *d, const char *temporary_mount, bool *m
|
||||
* either be owned by root:root or root:tty (e.g. /dev/tty, /dev/ptmx)
|
||||
* and should not carry ACLs. */
|
||||
if (mount(d, dn, NULL, MS_BIND, NULL) < 0)
|
||||
return log_debug_errno(errno, "mount failed for %s: %m", d);
|
||||
return log_debug_errno(errno, "Bind mounting failed for '%s': %m", d);
|
||||
|
||||
add_symlink:
|
||||
bn = path_startswith(d, "/dev/");
|
||||
if (!bn)
|
||||
return 0;
|
||||
|
||||
/* Create symlinks like /dev/char/1:9 → ../urandom */
|
||||
if (asprintf(&sl, "%s/dev/%s/%u:%u", temporary_mount, S_ISCHR(st.st_mode) ? "char" : "block", major(st.st_rdev), minor(st.st_rdev)) < 0)
|
||||
return log_oom();
|
||||
|
||||
(void) mkdir_parents(sl, 0755);
|
||||
|
||||
t = strjoina("../", bn);
|
||||
|
||||
if (symlink(t, sl) < 0)
|
||||
log_debug_errno(errno, "Failed to symlink '%s' to '%s': %m", t, sl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1934,7 +1934,7 @@ static int socket_chown(Socket *s, pid_t *_pid) {
|
||||
if (!isempty(s->user)) {
|
||||
const char *user = s->user;
|
||||
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_unit_error_errno(UNIT(s), r, "Failed to resolve user %s: %m", user);
|
||||
_exit(EXIT_USER);
|
||||
@ -1944,7 +1944,7 @@ static int socket_chown(Socket *s, pid_t *_pid) {
|
||||
if (!isempty(s->group)) {
|
||||
const char *group = s->group;
|
||||
|
||||
r = get_group_creds(&group, &gid);
|
||||
r = get_group_creds(&group, &gid, 0);
|
||||
if (r < 0) {
|
||||
log_unit_error_errno(UNIT(s), r, "Failed to resolve group %s: %m", group);
|
||||
_exit(EXIT_GROUP);
|
||||
|
@ -672,7 +672,7 @@ static int change_uid_gid(const char *context[]) {
|
||||
if (uid <= SYSTEM_UID_MAX) {
|
||||
const char *user = "systemd-coredump";
|
||||
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_warning_errno(r, "Cannot resolve %s user. Proceeding to dump core as root: %m", user);
|
||||
uid = gid = 0;
|
||||
|
@ -909,7 +909,7 @@ static int show_user(int argc, char *argv[], void *userdata) {
|
||||
const char *path = NULL;
|
||||
uid_t uid;
|
||||
|
||||
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
|
||||
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
|
||||
|
||||
@ -1097,7 +1097,7 @@ static int enable_linger(int argc, char *argv[], void *userdata) {
|
||||
if (isempty(argv[i]))
|
||||
uid = UID_INVALID;
|
||||
else {
|
||||
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
|
||||
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
|
||||
}
|
||||
@ -1130,7 +1130,7 @@ static int terminate_user(int argc, char *argv[], void *userdata) {
|
||||
for (i = 1; i < argc; i++) {
|
||||
uid_t uid;
|
||||
|
||||
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
|
||||
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
|
||||
|
||||
@ -1165,7 +1165,7 @@ static int kill_user(int argc, char *argv[], void *userdata) {
|
||||
for (i = 1; i < argc; i++) {
|
||||
uid_t uid;
|
||||
|
||||
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
|
||||
r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
|
||||
|
||||
|
@ -152,7 +152,7 @@ int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
|
||||
assert(m);
|
||||
assert(name);
|
||||
|
||||
r = get_user_creds(&name, &uid, &gid, NULL, NULL);
|
||||
r = get_user_creds(&name, &uid, &gid, NULL, NULL, 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
@ -117,7 +117,7 @@ static int do_mount(const char *user) {
|
||||
gid_t gid;
|
||||
int r;
|
||||
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r,
|
||||
r == -ESRCH ? "No such user \"%s\"" :
|
||||
@ -141,7 +141,7 @@ static int do_umount(const char *user) {
|
||||
/* The user may be already removed. So, first try to parse the string by parse_uid(),
|
||||
* and if it fails, fallback to get_user_creds().*/
|
||||
if (parse_uid(user, &uid) < 0) {
|
||||
r = get_user_creds(&user, &uid, NULL, NULL, NULL);
|
||||
r = get_user_creds(&user, &uid, NULL, NULL, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r,
|
||||
r == -ESRCH ? "No such user \"%s\"" :
|
||||
|
@ -223,7 +223,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_OWNER: {
|
||||
const char *user = optarg;
|
||||
|
||||
r = get_user_creds(&user, &arg_uid, &arg_gid, NULL, NULL);
|
||||
r = get_user_creds(&user, &arg_uid, &arg_gid, NULL, NULL, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r,
|
||||
r == -EBADMSG ? "UID or GID of user %s are invalid."
|
||||
|
@ -60,7 +60,7 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
|
||||
assert(netdev);
|
||||
assert(ifr);
|
||||
|
||||
fd = open(TUN_DEV, O_RDWR);
|
||||
fd = open(TUN_DEV, O_RDWR|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return log_netdev_error_errno(netdev, -errno, "Failed to open tun dev: %m");
|
||||
|
||||
@ -75,10 +75,9 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
|
||||
assert(t);
|
||||
|
||||
if (t->user_name) {
|
||||
|
||||
user = t->user_name;
|
||||
|
||||
r = get_user_creds(&user, &uid, NULL, NULL, NULL);
|
||||
r = get_user_creds(&user, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name);
|
||||
|
||||
@ -87,10 +86,9 @@ static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) {
|
||||
}
|
||||
|
||||
if (t->group_name) {
|
||||
|
||||
group = t->group_name;
|
||||
|
||||
r = get_group_creds(&group, &gid);
|
||||
r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
|
||||
if (r < 0)
|
||||
return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name);
|
||||
|
||||
|
@ -28,7 +28,7 @@ int main(int argc, char *argv[]) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Cannot resolve user name %s: %m", user);
|
||||
goto out;
|
||||
|
@ -115,7 +115,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
case ARG_UID: {
|
||||
const char *u = optarg;
|
||||
|
||||
r = get_user_creds(&u, &arg_uid, &arg_gid, NULL, NULL);
|
||||
r = get_user_creds(&u, &arg_uid, &arg_gid, NULL, NULL, 0);
|
||||
if (r == -ESRCH) /* If the user doesn't exist, then accept it anyway as numeric */
|
||||
r = parse_uid(u, &arg_uid);
|
||||
if (r < 0)
|
||||
|
@ -1790,7 +1790,12 @@ static int copy_devnodes(const char *dest) {
|
||||
struct stat st;
|
||||
|
||||
from = strappend("/dev/", d);
|
||||
if (!from)
|
||||
return log_oom();
|
||||
|
||||
to = prefix_root(dest, from);
|
||||
if (!to)
|
||||
return log_oom();
|
||||
|
||||
if (stat(from, &st) < 0) {
|
||||
|
||||
@ -1803,6 +1808,8 @@ static int copy_devnodes(const char *dest) {
|
||||
return -EIO;
|
||||
|
||||
} else {
|
||||
_cleanup_free_ char *sl = NULL, *prefixed = NULL, *dn = NULL, *t = NULL;
|
||||
|
||||
if (mknod(to, st.st_mode, st.st_rdev) < 0) {
|
||||
/* Explicitly warn the user when /dev is already populated. */
|
||||
if (errno == EEXIST)
|
||||
@ -1810,8 +1817,7 @@ static int copy_devnodes(const char *dest) {
|
||||
if (errno != EPERM)
|
||||
return log_error_errno(errno, "mknod(%s) failed: %m", to);
|
||||
|
||||
/* Some systems abusively restrict mknod but
|
||||
* allow bind mounts. */
|
||||
/* Some systems abusively restrict mknod but allow bind mounts. */
|
||||
r = touch(to);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "touch (%s) failed: %m", to);
|
||||
@ -1823,6 +1829,28 @@ static int copy_devnodes(const char *dest) {
|
||||
r = userns_lchown(to, 0, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "chown() of device node %s failed: %m", to);
|
||||
|
||||
dn = strjoin("/dev/", S_ISCHR(st.st_mode) ? "char" : "block");
|
||||
if (!dn)
|
||||
return log_oom();
|
||||
|
||||
r = userns_mkdir(dest, dn, 0755, 0, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to create '%s': %m", dn);
|
||||
|
||||
if (asprintf(&sl, "%s/%u:%u", dn, major(st.st_rdev), minor(st.st_rdev)) < 0)
|
||||
return log_oom();
|
||||
|
||||
prefixed = prefix_root(dest, sl);
|
||||
if (!prefixed)
|
||||
return log_oom();
|
||||
|
||||
t = strjoin("../", d);
|
||||
if (!t)
|
||||
return log_oom();
|
||||
|
||||
if (symlink(t, prefixed) < 0)
|
||||
log_debug_errno(errno, "Failed to symlink '%s' to '%s': %m", t, prefixed);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ int main(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Cannot resolve user name %s: %m", user);
|
||||
goto finish;
|
||||
|
@ -34,6 +34,7 @@ static void test_parse_etc_hosts(const char *fname) {
|
||||
assert_se(fd >= 0);
|
||||
|
||||
f = fdopen(fd, "r+");
|
||||
assert_se(f);
|
||||
fputs("1.2.3.4 some.where\n", f);
|
||||
fputs("1.2.3.5 some.where\n", f);
|
||||
fputs("::0 some.where some.other\n", f);
|
||||
@ -49,7 +50,7 @@ static void test_parse_etc_hosts(const char *fname) {
|
||||
|
||||
if (fname)
|
||||
return;
|
||||
|
||||
|
||||
EtcHostsItemByName *bn;
|
||||
assert_se(bn = hashmap_get(hosts.by_name, "some.where"));
|
||||
assert_se(bn->n_addresses == 3);
|
||||
|
@ -1239,7 +1239,7 @@ static int start_transient_scope(
|
||||
if (arg_exec_group) {
|
||||
gid_t gid;
|
||||
|
||||
r = get_group_creds(&arg_exec_group, &gid);
|
||||
r = get_group_creds(&arg_exec_group, &gid, 0);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to resolve group %s: %m", arg_exec_group);
|
||||
|
||||
@ -1252,7 +1252,7 @@ static int start_transient_scope(
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
|
||||
r = get_user_creds_clean(&arg_exec_user, &uid, &gid, &home, &shell);
|
||||
r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell, USER_CREDS_CLEAN|USER_CREDS_PREFER_NSS);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user);
|
||||
|
||||
|
@ -219,7 +219,7 @@ static int condition_test_user(Condition *c) {
|
||||
return streq(c->parameter, "root");
|
||||
|
||||
u = c->parameter;
|
||||
r = get_user_creds(&u, &id, NULL, NULL, NULL);
|
||||
r = get_user_creds(&u, &id, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
|
@ -32,7 +32,7 @@ static void test_add_acls_for_user(void) {
|
||||
|
||||
if (getuid() == 0) {
|
||||
const char *nobody = NOBODY_USER_NAME;
|
||||
r = get_user_creds(&nobody, &uid, NULL, NULL, NULL);
|
||||
r = get_user_creds(&nobody, &uid, NULL, NULL, NULL, 0);
|
||||
if (r < 0)
|
||||
uid = 0;
|
||||
} else
|
||||
|
@ -9,7 +9,7 @@ int main(int argc, char *argv[]) {
|
||||
int r;
|
||||
const char* name = argv[1] ?: NOBODY_USER_NAME;
|
||||
|
||||
r = get_user_creds(&name, &uid, NULL, NULL, NULL);
|
||||
r = get_user_creds(&name, &uid, NULL, NULL, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_full_errno(r == -ESRCH ? LOG_NOTICE : LOG_ERR,
|
||||
r, "Failed to resolve \"%s\": %m", name);
|
||||
|
@ -159,7 +159,7 @@ static void test_get_user_creds_one(const char *id, const char *name, uid_t uid,
|
||||
log_info("/* %s(\"%s\", \"%s\", "UID_FMT", "GID_FMT", \"%s\", \"%s\") */",
|
||||
__func__, id, name, uid, gid, home, shell);
|
||||
|
||||
r = get_user_creds(&id, &ruid, &rgid, &rhome, &rshell);
|
||||
r = get_user_creds(&id, &ruid, &rgid, &rhome, &rshell, 0);
|
||||
log_info_errno(r, "got \"%s\", "UID_FMT", "GID_FMT", \"%s\", \"%s\": %m",
|
||||
id, ruid, rgid, strnull(rhome), strnull(rshell));
|
||||
if (!synthesize_nobody() && streq(name, NOBODY_USER_NAME)) {
|
||||
@ -180,7 +180,7 @@ static void test_get_group_creds_one(const char *id, const char *name, gid_t gid
|
||||
|
||||
log_info("/* %s(\"%s\", \"%s\", "GID_FMT") */", __func__, id, name, gid);
|
||||
|
||||
r = get_group_creds(&id, &rgid);
|
||||
r = get_group_creds(&id, &rgid, 0);
|
||||
log_info_errno(r, "got \"%s\", "GID_FMT": %m", id, rgid);
|
||||
if (!synthesize_nobody() && streq(name, NOBODY_GROUP_NAME)) {
|
||||
log_info("(skipping detailed tests because nobody is not synthesized)");
|
||||
|
@ -107,7 +107,7 @@ int main(int argc, char *argv[]) {
|
||||
gid = getegid();
|
||||
|
||||
if (uid_current == 0) {
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL);
|
||||
r = get_user_creds(&user, &uid, &gid, NULL, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Cannot resolve user name %s: %m", user);
|
||||
goto finish;
|
||||
|
@ -2728,7 +2728,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
|
||||
if (!isempty(user) && !streq(user, "-")) {
|
||||
const char *u = user;
|
||||
|
||||
r = get_user_creds(&u, &i.uid, NULL, NULL, NULL);
|
||||
r = get_user_creds(&u, &i.uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
|
||||
if (r < 0) {
|
||||
*invalid_config = true;
|
||||
return log_error_errno(r, "[%s:%u] Unknown user '%s'.", fname, line, user);
|
||||
@ -2740,7 +2740,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
|
||||
if (!isempty(group) && !streq(group, "-")) {
|
||||
const char *g = group;
|
||||
|
||||
r = get_group_creds(&g, &i.gid);
|
||||
r = get_group_creds(&g, &i.gid, USER_CREDS_ALLOW_MISSING);
|
||||
if (r < 0) {
|
||||
*invalid_config = true;
|
||||
log_error("[%s:%u] Unknown group '%s'.", fname, line, group);
|
||||
|
@ -481,7 +481,7 @@ static uid_t add_uid(struct udev_rules *rules, const char *owner) {
|
||||
return uid;
|
||||
}
|
||||
}
|
||||
r = get_user_creds(&owner, &uid, NULL, NULL, NULL);
|
||||
r = get_user_creds(&owner, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
|
||||
if (r < 0)
|
||||
log_unknown_owner(r, "user", owner);
|
||||
|
||||
@ -524,7 +524,7 @@ static gid_t add_gid(struct udev_rules *rules, const char *group) {
|
||||
return gid;
|
||||
}
|
||||
}
|
||||
r = get_group_creds(&group, &gid);
|
||||
r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
|
||||
if (r < 0)
|
||||
log_unknown_owner(r, "group", group);
|
||||
|
||||
@ -2110,7 +2110,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
|
||||
event->owner_final = true;
|
||||
udev_event_apply_format(event, rules_str(rules, cur->key.value_off), owner, sizeof(owner), false);
|
||||
event->owner_set = true;
|
||||
r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL);
|
||||
r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
|
||||
if (r < 0) {
|
||||
log_unknown_owner(r, "user", owner);
|
||||
event->uid = 0;
|
||||
@ -2131,7 +2131,7 @@ void udev_rules_apply_to_event(struct udev_rules *rules,
|
||||
event->group_final = true;
|
||||
udev_event_apply_format(event, rules_str(rules, cur->key.value_off), group, sizeof(group), false);
|
||||
event->group_set = true;
|
||||
r = get_group_creds(&gr, &event->gid);
|
||||
r = get_group_creds(&gr, &event->gid, USER_CREDS_ALLOW_MISSING);
|
||||
if (r < 0) {
|
||||
log_unknown_owner(r, "group", group);
|
||||
event->gid = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user