nss-systemd: resolve root/nobody statically

Let's extend nss-systemd to also synthesize user/group entries for the
UIDs/GIDs 0 and 65534 which have special kernel meaning. Given that nss-systemd
is listed in /etc/nsswitch.conf only very late any explicit listing in
/etc/passwd or /etc/group takes precedence.

This functionality is useful in minimal container-like setups that lack
/etc/passwd files (or only have incompletely populated ones).
This commit is contained in:
Lennart Poettering
2016-08-04 23:08:05 +02:00
parent 136dc4c435
commit 2129011e92
3 changed files with 126 additions and 1 deletions
+101
View File
@@ -26,9 +26,52 @@
#include "macro.h"
#include "nss-util.h"
#include "signal-util.h"
#include "string-util.h"
#include "user-util.h"
#include "util.h"
#ifndef NOBODY_USER_NAME
#define NOBODY_USER_NAME "nobody"
#endif
#ifndef NOBODY_GROUP_NAME
#define NOBODY_GROUP_NAME "nobody"
#endif
static const struct passwd root_passwd = {
.pw_name = (char*) "root",
.pw_passwd = (char*) "x", /* see shadow file */
.pw_uid = 0,
.pw_gid = 0,
.pw_gecos = (char*) "Super User",
.pw_dir = (char*) "/root",
.pw_shell = (char*) "/bin/sh",
};
static const struct passwd nobody_passwd = {
.pw_name = (char*) NOBODY_USER_NAME,
.pw_passwd = (char*) "*", /* locked */
.pw_uid = 65534,
.pw_gid = 65534,
.pw_gecos = (char*) "User Nobody",
.pw_dir = (char*) "/",
.pw_shell = (char*) "/sbin/nologin",
};
static const struct group root_group = {
.gr_name = (char*) "root",
.gr_gid = 0,
.gr_passwd = (char*) "x", /* see shadow file */
.gr_mem = (char*[]) { NULL },
};
static const struct group nobody_group = {
.gr_name = (char*) NOBODY_GROUP_NAME,
.gr_gid = 65534,
.gr_passwd = (char*) "*", /* locked */
.gr_mem = (char*[]) { NULL },
};
NSS_GETPW_PROTOTYPES(systemd);
NSS_GETGR_PROTOTYPES(systemd);
@@ -50,6 +93,23 @@ enum nss_status _nss_systemd_getpwnam_r(
assert(name);
assert(pwd);
if (!valid_user_group_name(name)) {
r = -EINVAL;
goto fail;
}
/* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
if (streq(name, root_passwd.pw_name)) {
*pwd = root_passwd;
*errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (streq(name, nobody_passwd.pw_name)) {
*pwd = nobody_passwd;
*errnop = 0;
return NSS_STATUS_SUCCESS;
}
/* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
goto not_found;
@@ -126,6 +186,18 @@ enum nss_status _nss_systemd_getpwuid_r(
goto fail;
}
/* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
if (uid == root_passwd.pw_uid) {
*pwd = root_passwd;
*errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (uid == nobody_passwd.pw_uid) {
*pwd = nobody_passwd;
*errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (uid <= SYSTEM_UID_MAX)
goto not_found;
@@ -202,6 +274,23 @@ enum nss_status _nss_systemd_getgrnam_r(
assert(name);
assert(gr);
if (!valid_user_group_name(name)) {
r = -EINVAL;
goto fail;
}
/* Synthesize records for root and nobody, in case they are missing form /etc/group */
if (streq(name, root_group.gr_name)) {
*gr = root_group;
*errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (streq(name, nobody_group.gr_name)) {
*gr = nobody_group;
*errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
goto not_found;
@@ -275,6 +364,18 @@ enum nss_status _nss_systemd_getgrgid_r(
goto fail;
}
/* Synthesize records for root and nobody, in case they are missing from /etc/group */
if (gid == root_group.gr_gid) {
*gr = root_group;
*errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (gid == nobody_group.gr_gid) {
*gr = nobody_group;
*errnop = 0;
return NSS_STATUS_SUCCESS;
}
if (gid <= SYSTEM_GID_MAX)
goto not_found;