LCOV - code coverage report
Current view: top level - basic - user-util.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 230 448 51.3 %
Date: 2019-08-22 15:41:25 Functions: 18 31 58.1 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include <alloca.h>
       4             : #include <errno.h>
       5             : #include <fcntl.h>
       6             : #include <grp.h>
       7             : #include <pwd.h>
       8             : #include <stddef.h>
       9             : #include <stdint.h>
      10             : #include <stdio.h>
      11             : #include <stdlib.h>
      12             : #include <string.h>
      13             : #include <sys/stat.h>
      14             : #include <unistd.h>
      15             : #include <utmp.h>
      16             : 
      17             : #include "alloc-util.h"
      18             : #include "errno-util.h"
      19             : #include "fd-util.h"
      20             : #include "fileio.h"
      21             : #include "format-util.h"
      22             : #include "macro.h"
      23             : #include "missing.h"
      24             : #include "parse-util.h"
      25             : #include "path-util.h"
      26             : #include "random-util.h"
      27             : #include "string-util.h"
      28             : #include "strv.h"
      29             : #include "user-util.h"
      30             : #include "utf8.h"
      31             : 
      32        5055 : bool uid_is_valid(uid_t uid) {
      33             : 
      34             :         /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.436. */
      35             : 
      36             :         /* Some libc APIs use UID_INVALID as special placeholder */
      37        5055 :         if (uid == (uid_t) UINT32_C(0xFFFFFFFF))
      38        4350 :                 return false;
      39             : 
      40             :         /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
      41         705 :         if (uid == (uid_t) UINT32_C(0xFFFF))
      42           8 :                 return false;
      43             : 
      44         697 :         return true;
      45             : }
      46             : 
      47         248 : int parse_uid(const char *s, uid_t *ret) {
      48         248 :         uint32_t uid = 0;
      49             :         int r;
      50             : 
      51         248 :         assert(s);
      52             : 
      53             :         assert_cc(sizeof(uid_t) == sizeof(uint32_t));
      54         248 :         r = safe_atou32(s, &uid);
      55         248 :         if (r < 0)
      56          37 :                 return r;
      57             : 
      58         211 :         if (!uid_is_valid(uid))
      59           7 :                 return -ENXIO; /* we return ENXIO instead of EINVAL
      60             :                                 * here, to make it easy to distinguish
      61             :                                 * invalid numeric uids from invalid
      62             :                                 * strings. */
      63             : 
      64         204 :         if (ret)
      65         154 :                 *ret = uid;
      66             : 
      67         204 :         return 0;
      68             : }
      69             : 
      70           0 : char* getlogname_malloc(void) {
      71             :         uid_t uid;
      72             :         struct stat st;
      73             : 
      74           0 :         if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
      75           0 :                 uid = st.st_uid;
      76             :         else
      77           0 :                 uid = getuid();
      78             : 
      79           0 :         return uid_to_name(uid);
      80             : }
      81             : 
      82           5 : char *getusername_malloc(void) {
      83             :         const char *e;
      84             : 
      85           5 :         e = secure_getenv("USER");
      86           5 :         if (e)
      87           5 :                 return strdup(e);
      88             : 
      89           0 :         return uid_to_name(getuid());
      90             : }
      91             : 
      92           0 : static bool is_nologin_shell(const char *shell) {
      93             : 
      94           0 :         return PATH_IN_SET(shell,
      95             :                            /* 'nologin' is the friendliest way to disable logins for a user account. It prints a nice
      96             :                             * message and exits. Different distributions place the binary at different places though,
      97             :                             * hence let's list them all. */
      98             :                            "/bin/nologin",
      99             :                            "/sbin/nologin",
     100             :                            "/usr/bin/nologin",
     101             :                            "/usr/sbin/nologin",
     102             :                            /* 'true' and 'false' work too for the same purpose, but are less friendly as they don't do
     103             :                             * any message printing. Different distributions place the binary at various places but at
     104             :                             * least not in the 'sbin' directory. */
     105             :                            "/bin/false",
     106             :                            "/usr/bin/false",
     107             :                            "/bin/true",
     108             :                            "/usr/bin/true");
     109             : }
     110             : 
     111           7 : static int synthesize_user_creds(
     112             :                 const char **username,
     113             :                 uid_t *uid, gid_t *gid,
     114             :                 const char **home,
     115             :                 const char **shell,
     116             :                 UserCredsFlags flags) {
     117             : 
     118             :         /* We enforce some special rules for uid=0 and uid=65534: in order to avoid NSS lookups for root we hardcode
     119             :          * their user record data. */
     120             : 
     121           7 :         if (STR_IN_SET(*username, "root", "0")) {
     122           3 :                 *username = "root";
     123             : 
     124           3 :                 if (uid)
     125           3 :                         *uid = 0;
     126           3 :                 if (gid)
     127           2 :                         *gid = 0;
     128             : 
     129           3 :                 if (home)
     130           2 :                         *home = "/root";
     131             : 
     132           3 :                 if (shell)
     133           2 :                         *shell = "/bin/sh";
     134             : 
     135           3 :                 return 0;
     136             :         }
     137             : 
     138           4 :         if (synthesize_nobody() &&
     139           0 :             STR_IN_SET(*username, NOBODY_USER_NAME, "65534")) {
     140           0 :                 *username = NOBODY_USER_NAME;
     141             : 
     142           0 :                 if (uid)
     143           0 :                         *uid = UID_NOBODY;
     144           0 :                 if (gid)
     145           0 :                         *gid = GID_NOBODY;
     146             : 
     147           0 :                 if (home)
     148           0 :                         *home = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : "/";
     149             : 
     150           0 :                 if (shell)
     151           0 :                         *shell = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : NOLOGIN;
     152             : 
     153           0 :                 return 0;
     154             :         }
     155             : 
     156           4 :         return -ENOMEDIUM;
     157             : }
     158             : 
     159           7 : int get_user_creds(
     160             :                 const char **username,
     161             :                 uid_t *uid, gid_t *gid,
     162             :                 const char **home,
     163             :                 const char **shell,
     164             :                 UserCredsFlags flags) {
     165             : 
     166           7 :         uid_t u = UID_INVALID;
     167             :         struct passwd *p;
     168             :         int r;
     169             : 
     170           7 :         assert(username);
     171           7 :         assert(*username);
     172             : 
     173           7 :         if (!FLAGS_SET(flags, USER_CREDS_PREFER_NSS) ||
     174           0 :             (!home && !shell)) {
     175             : 
     176             :                 /* So here's the deal: normally, we'll try to synthesize all records we can synthesize, and override
     177             :                  * the user database with that. However, if the user specifies USER_CREDS_PREFER_NSS then the
     178             :                  * user database will override the synthetic records instead — except if the user is only interested in
     179             :                  * the UID and/or GID (but not the home directory, or the shell), in which case we'll always override
     180             :                  * the user database (i.e. the USER_CREDS_PREFER_NSS flag has no effect in this case). Why?
     181             :                  * Simply because there are valid usecase where the user might change the home directory or the shell
     182             :                  * of the relevant users, but changing the UID/GID mappings for them is something we explicitly don't
     183             :                  * support. */
     184             : 
     185           7 :                 r = synthesize_user_creds(username, uid, gid, home, shell, flags);
     186           7 :                 if (r >= 0)
     187           3 :                         return 0;
     188           4 :                 if (r != -ENOMEDIUM) /* not a username we can synthesize */
     189           0 :                         return r;
     190             :         }
     191             : 
     192           4 :         if (parse_uid(*username, &u) >= 0) {
     193           1 :                 errno = 0;
     194           1 :                 p = getpwuid(u);
     195             : 
     196             :                 /* If there are multiple users with the same id, make sure to leave $USER to the configured value
     197             :                  * instead of the first occurrence in the database. However if the uid was configured by a numeric uid,
     198             :                  * then let's pick the real username from /etc/passwd. */
     199           1 :                 if (p)
     200           1 :                         *username = p->pw_name;
     201           0 :                 else if (FLAGS_SET(flags, USER_CREDS_ALLOW_MISSING) && !gid && !home && !shell) {
     202             : 
     203             :                         /* If the specified user is a numeric UID and it isn't in the user database, and the caller
     204             :                          * passed USER_CREDS_ALLOW_MISSING and was only interested in the UID, then juts return that
     205             :                          * and don't complain. */
     206             : 
     207           0 :                         if (uid)
     208           0 :                                 *uid = u;
     209             : 
     210           0 :                         return 0;
     211             :                 }
     212             :         } else {
     213           3 :                 errno = 0;
     214           3 :                 p = getpwnam(*username);
     215             :         }
     216           4 :         if (!p) {
     217           2 :                 r = errno_or_else(ESRCH);
     218             : 
     219             :                 /* If the user requested that we only synthesize as fallback, do so now */
     220           2 :                 if (FLAGS_SET(flags, USER_CREDS_PREFER_NSS)) {
     221           0 :                         if (synthesize_user_creds(username, uid, gid, home, shell, flags) >= 0)
     222           0 :                                 return 0;
     223             :                 }
     224             : 
     225           2 :                 return r;
     226             :         }
     227             : 
     228           2 :         if (uid) {
     229           2 :                 if (!uid_is_valid(p->pw_uid))
     230           0 :                         return -EBADMSG;
     231             : 
     232           2 :                 *uid = p->pw_uid;
     233             :         }
     234             : 
     235           2 :         if (gid) {
     236           2 :                 if (!gid_is_valid(p->pw_gid))
     237           0 :                         return -EBADMSG;
     238             : 
     239           2 :                 *gid = p->pw_gid;
     240             :         }
     241             : 
     242           2 :         if (home) {
     243           2 :                 if (FLAGS_SET(flags, USER_CREDS_CLEAN) &&
     244           0 :                     (empty_or_root(p->pw_dir) ||
     245           0 :                      !path_is_valid(p->pw_dir) ||
     246           0 :                      !path_is_absolute(p->pw_dir)))
     247           0 :                     *home = NULL; /* Note: we don't insist on normalized paths, since there are setups that have /./ in the path */
     248             :                 else
     249           2 :                         *home = p->pw_dir;
     250             :         }
     251             : 
     252           2 :         if (shell) {
     253           2 :                 if (FLAGS_SET(flags, USER_CREDS_CLEAN) &&
     254           0 :                     (isempty(p->pw_shell) ||
     255           0 :                      !path_is_valid(p->pw_dir) ||
     256           0 :                      !path_is_absolute(p->pw_shell) ||
     257           0 :                      is_nologin_shell(p->pw_shell)))
     258           0 :                         *shell = NULL;
     259             :                 else
     260           2 :                         *shell = p->pw_shell;
     261             :         }
     262             : 
     263           2 :         return 0;
     264             : }
     265             : 
     266          15 : int get_group_creds(const char **groupname, gid_t *gid, UserCredsFlags flags) {
     267             :         struct group *g;
     268             :         gid_t id;
     269             : 
     270          15 :         assert(groupname);
     271             : 
     272             :         /* We enforce some special rules for gid=0: in order to avoid NSS lookups for root we hardcode its data. */
     273             : 
     274          15 :         if (STR_IN_SET(*groupname, "root", "0")) {
     275           3 :                 *groupname = "root";
     276             : 
     277           3 :                 if (gid)
     278           3 :                         *gid = 0;
     279             : 
     280           3 :                 return 0;
     281             :         }
     282             : 
     283          12 :         if (synthesize_nobody() &&
     284           0 :             STR_IN_SET(*groupname, NOBODY_GROUP_NAME, "65534")) {
     285           0 :                 *groupname = NOBODY_GROUP_NAME;
     286             : 
     287           0 :                 if (gid)
     288           0 :                         *gid = GID_NOBODY;
     289             : 
     290           0 :                 return 0;
     291             :         }
     292             : 
     293          12 :         if (parse_gid(*groupname, &id) >= 0) {
     294           1 :                 errno = 0;
     295           1 :                 g = getgrgid(id);
     296             : 
     297           1 :                 if (g)
     298           1 :                         *groupname = g->gr_name;
     299           0 :                 else if (FLAGS_SET(flags, USER_CREDS_ALLOW_MISSING)) {
     300           0 :                         if (gid)
     301           0 :                                 *gid = id;
     302             : 
     303           0 :                         return 0;
     304             :                 }
     305             :         } else {
     306          11 :                 errno = 0;
     307          11 :                 g = getgrnam(*groupname);
     308             :         }
     309             : 
     310          12 :         if (!g)
     311           1 :                 return errno_or_else(ESRCH);
     312             : 
     313          11 :         if (gid) {
     314          11 :                 if (!gid_is_valid(g->gr_gid))
     315           0 :                         return -EBADMSG;
     316             : 
     317          11 :                 *gid = g->gr_gid;
     318             :         }
     319             : 
     320          11 :         return 0;
     321             : }
     322             : 
     323          14 : char* uid_to_name(uid_t uid) {
     324             :         char *ret;
     325             :         int r;
     326             : 
     327             :         /* Shortcut things to avoid NSS lookups */
     328          14 :         if (uid == 0)
     329           1 :                 return strdup("root");
     330          13 :         if (synthesize_nobody() &&
     331             :             uid == UID_NOBODY)
     332           0 :                 return strdup(NOBODY_USER_NAME);
     333             : 
     334          13 :         if (uid_is_valid(uid)) {
     335             :                 long bufsize;
     336             : 
     337          11 :                 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
     338          11 :                 if (bufsize <= 0)
     339           0 :                         bufsize = 4096;
     340             : 
     341           0 :                 for (;;) {
     342          11 :                         struct passwd pwbuf, *pw = NULL;
     343          11 :                         _cleanup_free_ char *buf = NULL;
     344             : 
     345          11 :                         buf = malloc(bufsize);
     346          11 :                         if (!buf)
     347           0 :                                 return NULL;
     348             : 
     349          11 :                         r = getpwuid_r(uid, &pwbuf, buf, (size_t) bufsize, &pw);
     350          11 :                         if (r == 0 && pw)
     351          11 :                                 return strdup(pw->pw_name);
     352           0 :                         if (r != ERANGE)
     353           0 :                                 break;
     354             : 
     355           0 :                         if (bufsize > LONG_MAX/2) /* overflow check */
     356           0 :                                 return NULL;
     357             : 
     358           0 :                         bufsize *= 2;
     359             :                 }
     360             :         }
     361             : 
     362           2 :         if (asprintf(&ret, UID_FMT, uid) < 0)
     363           0 :                 return NULL;
     364             : 
     365           2 :         return ret;
     366             : }
     367             : 
     368          24 : char* gid_to_name(gid_t gid) {
     369             :         char *ret;
     370             :         int r;
     371             : 
     372          24 :         if (gid == 0)
     373           1 :                 return strdup("root");
     374          23 :         if (synthesize_nobody() &&
     375             :             gid == GID_NOBODY)
     376           0 :                 return strdup(NOBODY_GROUP_NAME);
     377             : 
     378          23 :         if (gid_is_valid(gid)) {
     379             :                 long bufsize;
     380             : 
     381          21 :                 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
     382          21 :                 if (bufsize <= 0)
     383           0 :                         bufsize = 4096;
     384             : 
     385           0 :                 for (;;) {
     386          21 :                         struct group grbuf, *gr = NULL;
     387          21 :                         _cleanup_free_ char *buf = NULL;
     388             : 
     389          21 :                         buf = malloc(bufsize);
     390          21 :                         if (!buf)
     391           0 :                                 return NULL;
     392             : 
     393          21 :                         r = getgrgid_r(gid, &grbuf, buf, (size_t) bufsize, &gr);
     394          21 :                         if (r == 0 && gr)
     395          21 :                                 return strdup(gr->gr_name);
     396           0 :                         if (r != ERANGE)
     397           0 :                                 break;
     398             : 
     399           0 :                         if (bufsize > LONG_MAX/2) /* overflow check */
     400           0 :                                 return NULL;
     401             : 
     402           0 :                         bufsize *= 2;
     403             :                 }
     404             :         }
     405             : 
     406           2 :         if (asprintf(&ret, GID_FMT, gid) < 0)
     407           0 :                 return NULL;
     408             : 
     409           2 :         return ret;
     410             : }
     411             : 
     412          21 : int in_gid(gid_t gid) {
     413             :         long ngroups_max;
     414             :         gid_t *gids;
     415             :         int r, i;
     416             : 
     417          21 :         if (getgid() == gid)
     418           3 :                 return 1;
     419             : 
     420          18 :         if (getegid() == gid)
     421           0 :                 return 1;
     422             : 
     423          18 :         if (!gid_is_valid(gid))
     424           0 :                 return -EINVAL;
     425             : 
     426          18 :         ngroups_max = sysconf(_SC_NGROUPS_MAX);
     427          18 :         assert(ngroups_max > 0);
     428             : 
     429          18 :         gids = newa(gid_t, ngroups_max);
     430             : 
     431          18 :         r = getgroups(ngroups_max, gids);
     432          18 :         if (r < 0)
     433           0 :                 return -errno;
     434             : 
     435          96 :         for (i = 0; i < r; i++)
     436          94 :                 if (gids[i] == gid)
     437          16 :                         return 1;
     438             : 
     439           2 :         return 0;
     440             : }
     441             : 
     442          11 : int in_group(const char *name) {
     443             :         int r;
     444             :         gid_t gid;
     445             : 
     446          11 :         r = get_group_creds(&name, &gid, 0);
     447          11 :         if (r < 0)
     448           1 :                 return r;
     449             : 
     450          10 :         return in_gid(gid);
     451             : }
     452             : 
     453         441 : int get_home_dir(char **_h) {
     454             :         struct passwd *p;
     455             :         const char *e;
     456             :         char *h;
     457             :         uid_t u;
     458             : 
     459         441 :         assert(_h);
     460             : 
     461             :         /* Take the user specified one */
     462         441 :         e = secure_getenv("HOME");
     463         441 :         if (e && path_is_valid(e) && path_is_absolute(e)) {
     464         439 :                 h = strdup(e);
     465         439 :                 if (!h)
     466           0 :                         return -ENOMEM;
     467             : 
     468         439 :                 *_h = path_simplify(h, true);
     469         439 :                 return 0;
     470             :         }
     471             : 
     472             :         /* Hardcode home directory for root and nobody to avoid NSS */
     473           2 :         u = getuid();
     474           2 :         if (u == 0) {
     475           0 :                 h = strdup("/root");
     476           0 :                 if (!h)
     477           0 :                         return -ENOMEM;
     478             : 
     479           0 :                 *_h = h;
     480           0 :                 return 0;
     481             :         }
     482           2 :         if (synthesize_nobody() &&
     483             :             u == UID_NOBODY) {
     484           0 :                 h = strdup("/");
     485           0 :                 if (!h)
     486           0 :                         return -ENOMEM;
     487             : 
     488           0 :                 *_h = h;
     489           0 :                 return 0;
     490             :         }
     491             : 
     492             :         /* Check the database... */
     493           2 :         errno = 0;
     494           2 :         p = getpwuid(u);
     495           2 :         if (!p)
     496           0 :                 return errno_or_else(ESRCH);
     497             : 
     498           2 :         if (!path_is_valid(p->pw_dir) ||
     499           2 :             !path_is_absolute(p->pw_dir))
     500           0 :                 return -EINVAL;
     501             : 
     502           2 :         h = strdup(p->pw_dir);
     503           2 :         if (!h)
     504           0 :                 return -ENOMEM;
     505             : 
     506           2 :         *_h = path_simplify(h, true);
     507           2 :         return 0;
     508             : }
     509             : 
     510           1 : int get_shell(char **_s) {
     511             :         struct passwd *p;
     512             :         const char *e;
     513             :         char *s;
     514             :         uid_t u;
     515             : 
     516           1 :         assert(_s);
     517             : 
     518             :         /* Take the user specified one */
     519           1 :         e = secure_getenv("SHELL");
     520           1 :         if (e && path_is_valid(e) && path_is_absolute(e)) {
     521           1 :                 s = strdup(e);
     522           1 :                 if (!s)
     523           0 :                         return -ENOMEM;
     524             : 
     525           1 :                 *_s = path_simplify(s, true);
     526           1 :                 return 0;
     527             :         }
     528             : 
     529             :         /* Hardcode shell for root and nobody to avoid NSS */
     530           0 :         u = getuid();
     531           0 :         if (u == 0) {
     532           0 :                 s = strdup("/bin/sh");
     533           0 :                 if (!s)
     534           0 :                         return -ENOMEM;
     535             : 
     536           0 :                 *_s = s;
     537           0 :                 return 0;
     538             :         }
     539           0 :         if (synthesize_nobody() &&
     540             :             u == UID_NOBODY) {
     541           0 :                 s = strdup(NOLOGIN);
     542           0 :                 if (!s)
     543           0 :                         return -ENOMEM;
     544             : 
     545           0 :                 *_s = s;
     546           0 :                 return 0;
     547             :         }
     548             : 
     549             :         /* Check the database... */
     550           0 :         errno = 0;
     551           0 :         p = getpwuid(u);
     552           0 :         if (!p)
     553           0 :                 return errno_or_else(ESRCH);
     554             : 
     555           0 :         if (!path_is_valid(p->pw_shell) ||
     556           0 :             !path_is_absolute(p->pw_shell))
     557           0 :                 return -EINVAL;
     558             : 
     559           0 :         s = strdup(p->pw_shell);
     560           0 :         if (!s)
     561           0 :                 return -ENOMEM;
     562             : 
     563           0 :         *_s = path_simplify(s, true);
     564           0 :         return 0;
     565             : }
     566             : 
     567           0 : int reset_uid_gid(void) {
     568             :         int r;
     569             : 
     570           0 :         r = maybe_setgroups(0, NULL);
     571           0 :         if (r < 0)
     572           0 :                 return r;
     573             : 
     574           0 :         if (setresgid(0, 0, 0) < 0)
     575           0 :                 return -errno;
     576             : 
     577           0 :         if (setresuid(0, 0, 0) < 0)
     578           0 :                 return -errno;
     579             : 
     580           0 :         return 0;
     581             : }
     582             : 
     583           0 : int take_etc_passwd_lock(const char *root) {
     584             : 
     585           0 :         struct flock flock = {
     586             :                 .l_type = F_WRLCK,
     587             :                 .l_whence = SEEK_SET,
     588             :                 .l_start = 0,
     589             :                 .l_len = 0,
     590             :         };
     591             : 
     592             :         const char *path;
     593             :         int fd, r;
     594             : 
     595             :         /* This is roughly the same as lckpwdf(), but not as awful. We
     596             :          * don't want to use alarm() and signals, hence we implement
     597             :          * our own trivial version of this.
     598             :          *
     599             :          * Note that shadow-utils also takes per-database locks in
     600             :          * addition to lckpwdf(). However, we don't given that they
     601             :          * are redundant as they invoke lckpwdf() first and keep
     602             :          * it during everything they do. The per-database locks are
     603             :          * awfully racy, and thus we just won't do them. */
     604             : 
     605           0 :         if (root)
     606           0 :                 path = prefix_roota(root, ETC_PASSWD_LOCK_PATH);
     607             :         else
     608           0 :                 path = ETC_PASSWD_LOCK_PATH;
     609             : 
     610           0 :         fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
     611           0 :         if (fd < 0)
     612           0 :                 return log_debug_errno(errno, "Cannot open %s: %m", path);
     613             : 
     614           0 :         r = fcntl(fd, F_SETLKW, &flock);
     615           0 :         if (r < 0) {
     616           0 :                 safe_close(fd);
     617           0 :                 return log_debug_errno(errno, "Locking %s failed: %m", path);
     618             :         }
     619             : 
     620           0 :         return fd;
     621             : }
     622             : 
     623          43 : bool valid_user_group_name(const char *u) {
     624             :         const char *i;
     625             :         long sz;
     626             : 
     627             :         /* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
     628             :          * 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
     629             :          *
     630             :          * - We don't allow any dots (this would break chown syntax which permits dots as user/group name separator)
     631             :          * - We require that names fit into the appropriate utmp field
     632             :          * - We don't allow empty user names
     633             :          *
     634             :          * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
     635             :          */
     636             : 
     637          43 :         if (isempty(u))
     638           2 :                 return false;
     639             : 
     640          41 :         if (!(u[0] >= 'a' && u[0] <= 'z') &&
     641          23 :             !(u[0] >= 'A' && u[0] <= 'Z') &&
     642          19 :             u[0] != '_')
     643          17 :                 return false;
     644             : 
     645         114 :         for (i = u+1; *i; i++) {
     646          98 :                 if (!(*i >= 'a' && *i <= 'z') &&
     647          48 :                     !(*i >= 'A' && *i <= 'Z') &&
     648          16 :                     !(*i >= '0' && *i <= '9') &&
     649          12 :                     !IN_SET(*i, '_', '-'))
     650           8 :                         return false;
     651             :         }
     652             : 
     653          16 :         sz = sysconf(_SC_LOGIN_NAME_MAX);
     654          16 :         assert_se(sz > 0);
     655             : 
     656          16 :         if ((size_t) (i-u) > (size_t) sz)
     657           0 :                 return false;
     658             : 
     659          16 :         if ((size_t) (i-u) > UT_NAMESIZE - 1)
     660           0 :                 return false;
     661             : 
     662          16 :         return true;
     663             : }
     664             : 
     665          25 : bool valid_user_group_name_or_id(const char *u) {
     666             : 
     667             :         /* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the right
     668             :          * range, and not the invalid user ids. */
     669             : 
     670          25 :         if (isempty(u))
     671           2 :                 return false;
     672             : 
     673          23 :         if (valid_user_group_name(u))
     674           8 :                 return true;
     675             : 
     676          15 :         return parse_uid(u, NULL) >= 0;
     677             : }
     678             : 
     679           6 : bool valid_gecos(const char *d) {
     680             : 
     681           6 :         if (!d)
     682           1 :                 return false;
     683             : 
     684           5 :         if (!utf8_is_valid(d))
     685           0 :                 return false;
     686             : 
     687           5 :         if (string_has_cc(d, NULL))
     688           1 :                 return false;
     689             : 
     690             :         /* Colons are used as field separators, and hence not OK */
     691           4 :         if (strchr(d, ':'))
     692           1 :                 return false;
     693             : 
     694           3 :         return true;
     695             : }
     696             : 
     697          12 : bool valid_home(const char *p) {
     698             :         /* Note that this function is also called by valid_shell(), any
     699             :          * changes must account for that. */
     700             : 
     701          12 :         if (isempty(p))
     702           2 :                 return false;
     703             : 
     704          10 :         if (!utf8_is_valid(p))
     705           0 :                 return false;
     706             : 
     707          10 :         if (string_has_cc(p, NULL))
     708           1 :                 return false;
     709             : 
     710           9 :         if (!path_is_absolute(p))
     711           3 :                 return false;
     712             : 
     713           6 :         if (!path_is_normalized(p))
     714           2 :                 return false;
     715             : 
     716             :         /* Colons are used as field separators, and hence not OK */
     717           4 :         if (strchr(p, ':'))
     718           1 :                 return false;
     719             : 
     720           3 :         return true;
     721             : }
     722             : 
     723           0 : int maybe_setgroups(size_t size, const gid_t *list) {
     724             :         int r;
     725             : 
     726             :         /* Check if setgroups is allowed before we try to drop all the auxiliary groups */
     727           0 :         if (size == 0) { /* Dropping all aux groups? */
     728           0 :                 _cleanup_free_ char *setgroups_content = NULL;
     729             :                 bool can_setgroups;
     730             : 
     731           0 :                 r = read_one_line_file("/proc/self/setgroups", &setgroups_content);
     732           0 :                 if (r == -ENOENT)
     733             :                         /* Old kernels don't have /proc/self/setgroups, so assume we can use setgroups */
     734           0 :                         can_setgroups = true;
     735           0 :                 else if (r < 0)
     736           0 :                         return r;
     737             :                 else
     738           0 :                         can_setgroups = streq(setgroups_content, "allow");
     739             : 
     740           0 :                 if (!can_setgroups) {
     741           0 :                         log_debug("Skipping setgroups(), /proc/self/setgroups is set to 'deny'");
     742           0 :                         return 0;
     743             :                 }
     744             :         }
     745             : 
     746           0 :         if (setgroups(size, list) < 0)
     747           0 :                 return -errno;
     748             : 
     749           0 :         return 0;
     750             : }
     751             : 
     752          71 : bool synthesize_nobody(void) {
     753             :         /* Returns true when we shall synthesize the "nobody" user (which we do by default). This can be turned off by
     754             :          * touching /etc/systemd/dont-synthesize-nobody in order to provide upgrade compatibility with legacy systems
     755             :          * that used the "nobody" user name and group name for other UIDs/GIDs than 65534.
     756             :          *
     757             :          * Note that we do not employ any kind of synchronization on the following caching variable. If the variable is
     758             :          * accessed in multi-threaded programs in the worst case it might happen that we initialize twice, but that
     759             :          * shouldn't matter as each initialization should come to the same result. */
     760             :         static int cache = -1;
     761             : 
     762          71 :         if (cache < 0)
     763           9 :                 cache = access("/etc/systemd/dont-synthesize-nobody", F_OK) < 0;
     764             : 
     765          71 :         return cache;
     766             : }
     767             : 
     768           0 : int putpwent_sane(const struct passwd *pw, FILE *stream) {
     769           0 :         assert(pw);
     770           0 :         assert(stream);
     771             : 
     772           0 :         errno = 0;
     773           0 :         if (putpwent(pw, stream) != 0)
     774           0 :                 return errno_or_else(EIO);
     775             : 
     776           0 :         return 0;
     777             : }
     778             : 
     779           0 : int putspent_sane(const struct spwd *sp, FILE *stream) {
     780           0 :         assert(sp);
     781           0 :         assert(stream);
     782             : 
     783           0 :         errno = 0;
     784           0 :         if (putspent(sp, stream) != 0)
     785           0 :                 return errno_or_else(EIO);
     786             : 
     787           0 :         return 0;
     788             : }
     789             : 
     790           0 : int putgrent_sane(const struct group *gr, FILE *stream) {
     791           0 :         assert(gr);
     792           0 :         assert(stream);
     793             : 
     794           0 :         errno = 0;
     795           0 :         if (putgrent(gr, stream) != 0)
     796           0 :                 return errno_or_else(EIO);
     797             : 
     798           0 :         return 0;
     799             : }
     800             : 
     801             : #if ENABLE_GSHADOW
     802           0 : int putsgent_sane(const struct sgrp *sg, FILE *stream) {
     803           0 :         assert(sg);
     804           0 :         assert(stream);
     805             : 
     806           0 :         errno = 0;
     807           0 :         if (putsgent(sg, stream) != 0)
     808           0 :                 return errno_or_else(EIO);
     809             : 
     810           0 :         return 0;
     811             : }
     812             : #endif
     813             : 
     814           0 : int fgetpwent_sane(FILE *stream, struct passwd **pw) {
     815             :         struct passwd *p;
     816             : 
     817           0 :         assert(pw);
     818           0 :         assert(stream);
     819             : 
     820           0 :         errno = 0;
     821           0 :         p = fgetpwent(stream);
     822           0 :         if (!p && errno != ENOENT)
     823           0 :                 return errno_or_else(EIO);
     824             : 
     825           0 :         *pw = p;
     826           0 :         return !!p;
     827             : }
     828             : 
     829           0 : int fgetspent_sane(FILE *stream, struct spwd **sp) {
     830             :         struct spwd *s;
     831             : 
     832           0 :         assert(sp);
     833           0 :         assert(stream);
     834             : 
     835           0 :         errno = 0;
     836           0 :         s = fgetspent(stream);
     837           0 :         if (!s && errno != ENOENT)
     838           0 :                 return errno_or_else(EIO);
     839             : 
     840           0 :         *sp = s;
     841           0 :         return !!s;
     842             : }
     843             : 
     844           0 : int fgetgrent_sane(FILE *stream, struct group **gr) {
     845             :         struct group *g;
     846             : 
     847           0 :         assert(gr);
     848           0 :         assert(stream);
     849             : 
     850           0 :         errno = 0;
     851           0 :         g = fgetgrent(stream);
     852           0 :         if (!g && errno != ENOENT)
     853           0 :                 return errno_or_else(EIO);
     854             : 
     855           0 :         *gr = g;
     856           0 :         return !!g;
     857             : }
     858             : 
     859             : #if ENABLE_GSHADOW
     860           0 : int fgetsgent_sane(FILE *stream, struct sgrp **sg) {
     861             :         struct sgrp *s;
     862             : 
     863           0 :         assert(sg);
     864           0 :         assert(stream);
     865             : 
     866           0 :         errno = 0;
     867           0 :         s = fgetsgent(stream);
     868           0 :         if (!s && errno != ENOENT)
     869           0 :                 return errno_or_else(EIO);
     870             : 
     871           0 :         *sg = s;
     872           0 :         return !!s;
     873             : }
     874             : #endif
     875             : 
     876           2 : int make_salt(char **ret) {
     877             :         static const char table[] =
     878             :                 "abcdefghijklmnopqrstuvwxyz"
     879             :                 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
     880             :                 "0123456789"
     881             :                 "./";
     882             : 
     883             :         uint8_t raw[16];
     884             :         char *salt, *j;
     885             :         size_t i;
     886             :         int r;
     887             : 
     888             :         /* This is a bit like crypt_gensalt_ra(), but doesn't require libcrypt, and doesn't do anything but
     889             :          * SHA512, i.e. is legacy-free and minimizes our deps. */
     890             : 
     891             :         assert_cc(sizeof(table) == 64U + 1U);
     892             : 
     893             :         /* Insist on the best randomness by setting RANDOM_BLOCK, this is about keeping passwords secret after all. */
     894           2 :         r = genuine_random_bytes(raw, sizeof(raw), RANDOM_BLOCK);
     895           2 :         if (r < 0)
     896           0 :                 return r;
     897             : 
     898           2 :         salt = new(char, 3+sizeof(raw)+1+1);
     899           2 :         if (!salt)
     900           0 :                 return -ENOMEM;
     901             : 
     902             :         /* We only bother with SHA512 hashed passwords, the rest is legacy, and we don't do legacy. */
     903           2 :         j = stpcpy(salt, "$6$");
     904          34 :         for (i = 0; i < sizeof(raw); i++)
     905          32 :                 j[i] = table[raw[i] & 63];
     906           2 :         j[i++] = '$';
     907           2 :         j[i] = 0;
     908             : 
     909           2 :         *ret = salt;
     910           2 :         return 0;
     911             : }

Generated by: LCOV version 1.14