assert(username);
assert(*username);
- /* We enforce some special rules for uid=0: in order to avoid
- * NSS lookups for root we hardcode its data. */
+ /* 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. */
- if (streq(*username, "root") || streq(*username, "0")) {
+ if (STR_IN_SET(*username, "root", "0")) {
*username = "root";
if (uid)
*uid = 0;
-
if (gid)
*gid = 0;
return 0;
}
+ if (synthesize_nobody() &&
+ STR_IN_SET(*username, NOBODY_USER_NAME, "65534")) {
+ *username = NOBODY_USER_NAME;
+
+ if (uid)
+ *uid = UID_NOBODY;
+ if (gid)
+ *gid = GID_NOBODY;
+
+ if (home)
+ *home = "/";
+
+ if (shell)
+ *shell = "/sbin/nologin";
+
+ return 0;
+ }
+
if (parse_uid(*username, &u) >= 0) {
errno = 0;
p = getpwuid(u);
/* We enforce some special rules for gid=0: in order to avoid
* NSS lookups for root we hardcode its data. */
- if (streq(*groupname, "root") || streq(*groupname, "0")) {
+ if (STR_IN_SET(*groupname, "root", "0")) {
*groupname = "root";
if (gid)
return 0;
}
+ if (synthesize_nobody() &&
+ STR_IN_SET(*groupname, NOBODY_GROUP_NAME, "65534")) {
+ *groupname = NOBODY_GROUP_NAME;
+
+ if (gid)
+ *gid = GID_NOBODY;
+
+ return 0;
+ }
+
if (parse_gid(*groupname, &id) >= 0) {
errno = 0;
g = getgrgid(id);
/* Shortcut things to avoid NSS lookups */
if (uid == 0)
return strdup("root");
+ if (synthesize_nobody() &&
+ uid == UID_NOBODY)
+ return strdup(NOBODY_USER_NAME);
if (uid_is_valid(uid)) {
long bufsize;
if (gid == 0)
return strdup("root");
+ if (synthesize_nobody() &&
+ gid == GID_NOBODY)
+ return strdup(NOBODY_GROUP_NAME);
if (gid_is_valid(gid)) {
long bufsize;
}
int in_gid(gid_t gid) {
+ long ngroups_max;
gid_t *gids;
- int ngroups_max, r, i;
+ int r, i;
if (getgid() == gid)
return 1;
ngroups_max = sysconf(_SC_NGROUPS_MAX);
assert(ngroups_max > 0);
- gids = alloca(sizeof(gid_t) * ngroups_max);
+ gids = newa(gid_t, ngroups_max);
r = getgroups(ngroups_max, gids);
if (r < 0)
return 0;
}
- /* Hardcode home directory for root to avoid NSS */
+ /* Hardcode home directory for root and nobody to avoid NSS */
u = getuid();
if (u == 0) {
h = strdup("/root");
*_h = h;
return 0;
}
+ if (synthesize_nobody() &&
+ u == UID_NOBODY) {
+ h = strdup("/");
+ if (!h)
+ return -ENOMEM;
+
+ *_h = h;
+ return 0;
+ }
/* Check the database... */
errno = 0;
return 0;
}
- /* Hardcode home directory for root to avoid NSS */
+ /* Hardcode shell for root and nobody to avoid NSS */
u = getuid();
if (u == 0) {
s = strdup("/bin/sh");
*_s = s;
return 0;
}
+ if (synthesize_nobody() &&
+ u == UID_NOBODY) {
+ s = strdup("/sbin/nologin");
+ if (!s)
+ return -ENOMEM;
+
+ *_s = s;
+ return 0;
+ }
/* Check the database... */
errno = 0;
* awfully racy, and thus we just won't do them. */
if (root)
- path = prefix_roota(root, "/etc/.pwd.lock");
+ path = prefix_roota(root, ETC_PASSWD_LOCK_PATH);
else
- path = "/etc/.pwd.lock";
+ path = ETC_PASSWD_LOCK_PATH;
fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
if (fd < 0)
- return -errno;
+ return log_debug_errno(errno, "Cannot open %s: %m", path);
r = fcntl(fd, F_SETLKW, &flock);
if (r < 0) {
safe_close(fd);
- return -errno;
+ return log_debug_errno(errno, "Locking %s failed: %m", path);
}
return fd;
}
bool valid_home(const char *p) {
+ /* Note that this function is also called by valid_shell(), any
+ * changes must account for that. */
if (isempty(p))
return false;
return 0;
}
+
+bool synthesize_nobody(void) {
+
+#ifdef NOLEGACY
+ return true;
+#else
+ /* Returns true when we shall synthesize the "nobody" user (which we do by default). This can be turned off by
+ * touching /etc/systemd/dont-synthesize-nobody in order to provide upgrade compatibility with legacy systems
+ * that used the "nobody" user name and group name for other UIDs/GIDs than 65534.
+ *
+ * Note that we do not employ any kind of synchronization on the following caching variable. If the variable is
+ * accessed in multi-threaded programs in the worst case it might happen that we initialize twice, but that
+ * shouldn't matter as each initialization should come to the same result. */
+ static int cache = -1;
+
+ if (cache < 0)
+ cache = access("/etc/systemd/dont-synthesize-nobody", F_OK) < 0;
+
+ return cache;
+#endif
+}