chiark / gitweb /
util-lib: add a comment explaining the user name rules we enforce
[elogind.git] / src / basic / user-util.c
index 299ac32ee03e7416318a908bd15d284ce0c7ea51..332e1c6a9c7bc6a4b640208f70958a45004fa3c5 100644 (file)
@@ -33,7 +33,8 @@
 
 #include "alloc-util.h"
 #include "fd-util.h"
-#include "formats-util.h"
+#include "fileio.h"
+#include "format-util.h"
 #include "macro.h"
 #include "missing.h"
 #include "parse-util.h"
@@ -45,6 +46,8 @@
 
 bool uid_is_valid(uid_t uid) {
 
+        /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.436. */
+
         /* Some libc APIs use UID_INVALID as special placeholder */
         if (uid == (uid_t) UINT32_C(0xFFFFFFFF))
                 return false;
@@ -178,6 +181,7 @@ int get_user_creds(
         return 0;
 }
 
+#if 0 /// UNNEEDED by elogind
 int get_user_creds_clean(
                 const char **username,
                 uid_t *uid, gid_t *gid,
@@ -248,6 +252,7 @@ int get_group_creds(const char **groupname, gid_t *gid) {
 
         return 0;
 }
+#endif // 0
 
 char* uid_to_name(uid_t uid) {
         char *ret;
@@ -463,9 +468,11 @@ int get_shell(char **_s) {
 #endif // 0
 
 int reset_uid_gid(void) {
+        int r;
 
-        if (maybe_setgroups(0, NULL) < 0)
-                return -errno;
+        r = maybe_setgroups(0, NULL);
+        if (r < 0)
+                return r;
 
         if (setresgid(0, 0, 0) < 0)
                 return -errno;
@@ -522,7 +529,15 @@ bool valid_user_group_name(const char *u) {
         const char *i;
         long sz;
 
-        /* Checks if the specified name is a valid user/group name. */
+        /* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
+         * 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
+         *
+         * - We don't allow any dots (this would break chown syntax which permits dots as user/group name separator)
+         * - We require that names fit into the appropriate utmp field
+         * - We don't allow empty user names
+         *
+         * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
+         */
 
         if (isempty(u))
                 return false;
@@ -610,25 +625,30 @@ bool valid_home(const char *p) {
 }
 
 int maybe_setgroups(size_t size, const gid_t *list) {
-        static int cached_can_setgroups = -1;
-        /* check if setgroups is allowed before we try to drop all the auxiliary groups */
-        if (size == 0) {
-                if (cached_can_setgroups < 0) {
-                        _cleanup_free_ char *setgroups_content = NULL;
-                        int r = read_one_line_file("/proc/self/setgroups", &setgroups_content);
-                        if (r < 0 && errno != ENOENT)
-                                return r;
-                        if (r < 0) {
-                                /* old kernels don't have /proc/self/setgroups, so assume we can use setgroups */
-                                cached_can_setgroups = true;
-                        } else {
-                                cached_can_setgroups = streq(setgroups_content, "allow");
-                                if (!cached_can_setgroups)
-                                        log_debug("skip setgroups, /proc/self/setgroups is set to 'deny'");
-                        }
-                }
-                if (!cached_can_setgroups)
+        int r;
+
+        /* Check if setgroups is allowed before we try to drop all the auxiliary groups */
+        if (size == 0) { /* Dropping all aux groups? */
+                _cleanup_free_ char *setgroups_content = NULL;
+                bool can_setgroups;
+
+                r = read_one_line_file("/proc/self/setgroups", &setgroups_content);
+                if (r == -ENOENT)
+                        /* Old kernels don't have /proc/self/setgroups, so assume we can use setgroups */
+                        can_setgroups = true;
+                else if (r < 0)
+                        return r;
+                else
+                        can_setgroups = streq(setgroups_content, "allow");
+
+                if (!can_setgroups) {
+                        log_debug("Skipping setgroups(), /proc/self/setgroups is set to 'deny'");
                         return 0;
+                }
         }
-        return setgroups(size, list);
+
+        if (setgroups(size, list) < 0)
+                return -errno;
+
+        return 0;
 }