chiark / gitweb /
sysusers: allow the shell to be specified
[elogind.git] / src / basic / user-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2010 Lennart Poettering
6
7   systemd is free software; you can redistribute it and/or modify it
8   under the terms of the GNU Lesser General Public License as published by
9   the Free Software Foundation; either version 2.1 of the License, or
10   (at your option) any later version.
11
12   systemd is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <alloca.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <grp.h>
25 #include <pwd.h>
26 #include <stddef.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <utmp.h>
34
35 #include "alloc-util.h"
36 #include "fd-util.h"
37 #include "fileio.h"
38 #include "format-util.h"
39 #include "macro.h"
40 #include "missing.h"
41 #include "parse-util.h"
42 #include "path-util.h"
43 #include "string-util.h"
44 #include "strv.h"
45 #include "user-util.h"
46 #include "utf8.h"
47
48 bool uid_is_valid(uid_t uid) {
49
50         /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.436. */
51
52         /* Some libc APIs use UID_INVALID as special placeholder */
53         if (uid == (uid_t) UINT32_C(0xFFFFFFFF))
54                 return false;
55
56         /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
57         if (uid == (uid_t) UINT32_C(0xFFFF))
58                 return false;
59
60         return true;
61 }
62
63 int parse_uid(const char *s, uid_t *ret) {
64         uint32_t uid = 0;
65         int r;
66
67         assert(s);
68
69         assert_cc(sizeof(uid_t) == sizeof(uint32_t));
70         r = safe_atou32(s, &uid);
71         if (r < 0)
72                 return r;
73
74         if (!uid_is_valid(uid))
75                 return -ENXIO; /* we return ENXIO instead of EINVAL
76                                 * here, to make it easy to distuingish
77                                 * invalid numeric uids from invalid
78                                 * strings. */
79
80         if (ret)
81                 *ret = uid;
82
83         return 0;
84 }
85
86 char* getlogname_malloc(void) {
87         uid_t uid;
88         struct stat st;
89
90         if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
91                 uid = st.st_uid;
92         else
93                 uid = getuid();
94
95         return uid_to_name(uid);
96 }
97
98 #if 0 /// UNNEEDED by elogind
99 char *getusername_malloc(void) {
100         const char *e;
101
102         e = getenv("USER");
103         if (e)
104                 return strdup(e);
105
106         return uid_to_name(getuid());
107 }
108 #endif // 0
109
110 int get_user_creds(
111                 const char **username,
112                 uid_t *uid, gid_t *gid,
113                 const char **home,
114                 const char **shell) {
115
116         struct passwd *p;
117         uid_t u;
118
119         assert(username);
120         assert(*username);
121
122         /* We enforce some special rules for uid=0 and uid=65534: in order to avoid NSS lookups for root we hardcode
123          * their user record data. */
124
125         if (STR_IN_SET(*username, "root", "0")) {
126                 *username = "root";
127
128                 if (uid)
129                         *uid = 0;
130                 if (gid)
131                         *gid = 0;
132
133                 if (home)
134                         *home = "/root";
135
136                 if (shell)
137                         *shell = "/bin/sh";
138
139                 return 0;
140         }
141
142         if (synthesize_nobody() &&
143             STR_IN_SET(*username, NOBODY_USER_NAME, "65534")) {
144                 *username = NOBODY_USER_NAME;
145
146                 if (uid)
147                         *uid = UID_NOBODY;
148                 if (gid)
149                         *gid = GID_NOBODY;
150
151                 if (home)
152                         *home = "/";
153
154                 if (shell)
155                         *shell = "/sbin/nologin";
156
157                 return 0;
158         }
159
160         if (parse_uid(*username, &u) >= 0) {
161                 errno = 0;
162                 p = getpwuid(u);
163
164                 /* If there are multiple users with the same id, make
165                  * sure to leave $USER to the configured value instead
166                  * of the first occurrence in the database. However if
167                  * the uid was configured by a numeric uid, then let's
168                  * pick the real username from /etc/passwd. */
169                 if (p)
170                         *username = p->pw_name;
171         } else {
172                 errno = 0;
173                 p = getpwnam(*username);
174         }
175
176         if (!p)
177                 return errno > 0 ? -errno : -ESRCH;
178
179         if (uid) {
180                 if (!uid_is_valid(p->pw_uid))
181                         return -EBADMSG;
182
183                 *uid = p->pw_uid;
184         }
185
186         if (gid) {
187                 if (!gid_is_valid(p->pw_gid))
188                         return -EBADMSG;
189
190                 *gid = p->pw_gid;
191         }
192
193         if (home)
194                 *home = p->pw_dir;
195
196         if (shell)
197                 *shell = p->pw_shell;
198
199         return 0;
200 }
201
202 #if 0 /// UNNEEDED by elogind
203 int get_user_creds_clean(
204                 const char **username,
205                 uid_t *uid, gid_t *gid,
206                 const char **home,
207                 const char **shell) {
208
209         int r;
210
211         /* Like get_user_creds(), but resets home/shell to NULL if they don't contain anything relevant. */
212
213         r = get_user_creds(username, uid, gid, home, shell);
214         if (r < 0)
215                 return r;
216
217         if (shell &&
218             (isempty(*shell) || PATH_IN_SET(*shell,
219                                             "/bin/nologin",
220                                             "/sbin/nologin",
221                                             "/usr/bin/nologin",
222                                             "/usr/sbin/nologin")))
223                 *shell = NULL;
224
225         if (home &&
226             (isempty(*home) || path_equal(*home, "/")))
227                 *home = NULL;
228
229         return 0;
230 }
231
232 int get_group_creds(const char **groupname, gid_t *gid) {
233         struct group *g;
234         gid_t id;
235
236         assert(groupname);
237
238         /* We enforce some special rules for gid=0: in order to avoid
239          * NSS lookups for root we hardcode its data. */
240
241         if (STR_IN_SET(*groupname, "root", "0")) {
242                 *groupname = "root";
243
244                 if (gid)
245                         *gid = 0;
246
247                 return 0;
248         }
249
250         if (synthesize_nobody() &&
251             STR_IN_SET(*groupname, NOBODY_GROUP_NAME, "65534")) {
252                 *groupname = NOBODY_GROUP_NAME;
253
254                 if (gid)
255                         *gid = GID_NOBODY;
256
257                 return 0;
258         }
259
260         if (parse_gid(*groupname, &id) >= 0) {
261                 errno = 0;
262                 g = getgrgid(id);
263
264                 if (g)
265                         *groupname = g->gr_name;
266         } else {
267                 errno = 0;
268                 g = getgrnam(*groupname);
269         }
270
271         if (!g)
272                 return errno > 0 ? -errno : -ESRCH;
273
274         if (gid) {
275                 if (!gid_is_valid(g->gr_gid))
276                         return -EBADMSG;
277
278                 *gid = g->gr_gid;
279         }
280
281         return 0;
282 }
283 #endif // 0
284
285 char* uid_to_name(uid_t uid) {
286         char *ret;
287         int r;
288
289         /* Shortcut things to avoid NSS lookups */
290         if (uid == 0)
291                 return strdup("root");
292         if (synthesize_nobody() &&
293             uid == UID_NOBODY)
294                 return strdup(NOBODY_USER_NAME);
295
296         if (uid_is_valid(uid)) {
297                 long bufsize;
298
299                 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
300                 if (bufsize <= 0)
301                         bufsize = 4096;
302
303                 for (;;) {
304                         struct passwd pwbuf, *pw = NULL;
305                         _cleanup_free_ char *buf = NULL;
306
307                         buf = malloc(bufsize);
308                         if (!buf)
309                                 return NULL;
310
311                         r = getpwuid_r(uid, &pwbuf, buf, (size_t) bufsize, &pw);
312                         if (r == 0 && pw)
313                                 return strdup(pw->pw_name);
314                         if (r != ERANGE)
315                                 break;
316
317                         bufsize *= 2;
318                 }
319         }
320
321         if (asprintf(&ret, UID_FMT, uid) < 0)
322                 return NULL;
323
324         return ret;
325 }
326
327 char* gid_to_name(gid_t gid) {
328         char *ret;
329         int r;
330
331         if (gid == 0)
332                 return strdup("root");
333         if (synthesize_nobody() &&
334             gid == GID_NOBODY)
335                 return strdup(NOBODY_GROUP_NAME);
336
337         if (gid_is_valid(gid)) {
338                 long bufsize;
339
340                 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
341                 if (bufsize <= 0)
342                         bufsize = 4096;
343
344                 for (;;) {
345                         struct group grbuf, *gr = NULL;
346                         _cleanup_free_ char *buf = NULL;
347
348                         buf = malloc(bufsize);
349                         if (!buf)
350                                 return NULL;
351
352                         r = getgrgid_r(gid, &grbuf, buf, (size_t) bufsize, &gr);
353                         if (r == 0 && gr)
354                                 return strdup(gr->gr_name);
355                         if (r != ERANGE)
356                                 break;
357
358                         bufsize *= 2;
359                 }
360         }
361
362         if (asprintf(&ret, GID_FMT, gid) < 0)
363                 return NULL;
364
365         return ret;
366 }
367
368 #if 0 /// UNNEEDED by elogind
369 int in_gid(gid_t gid) {
370         long ngroups_max;
371         gid_t *gids;
372         int r, i;
373
374         if (getgid() == gid)
375                 return 1;
376
377         if (getegid() == gid)
378                 return 1;
379
380         if (!gid_is_valid(gid))
381                 return -EINVAL;
382
383         ngroups_max = sysconf(_SC_NGROUPS_MAX);
384         assert(ngroups_max > 0);
385
386         gids = newa(gid_t, ngroups_max);
387
388         r = getgroups(ngroups_max, gids);
389         if (r < 0)
390                 return -errno;
391
392         for (i = 0; i < r; i++)
393                 if (gids[i] == gid)
394                         return 1;
395
396         return 0;
397 }
398
399 int in_group(const char *name) {
400         int r;
401         gid_t gid;
402
403         r = get_group_creds(&name, &gid);
404         if (r < 0)
405                 return r;
406
407         return in_gid(gid);
408 }
409
410 int get_home_dir(char **_h) {
411         struct passwd *p;
412         const char *e;
413         char *h;
414         uid_t u;
415
416         assert(_h);
417
418         /* Take the user specified one */
419         e = secure_getenv("HOME");
420         if (e && path_is_absolute(e)) {
421                 h = strdup(e);
422                 if (!h)
423                         return -ENOMEM;
424
425                 *_h = h;
426                 return 0;
427         }
428
429         /* Hardcode home directory for root and nobody to avoid NSS */
430         u = getuid();
431         if (u == 0) {
432                 h = strdup("/root");
433                 if (!h)
434                         return -ENOMEM;
435
436                 *_h = h;
437                 return 0;
438         }
439         if (synthesize_nobody() &&
440             u == UID_NOBODY) {
441                 h = strdup("/");
442                 if (!h)
443                         return -ENOMEM;
444
445                 *_h = h;
446                 return 0;
447         }
448
449         /* Check the database... */
450         errno = 0;
451         p = getpwuid(u);
452         if (!p)
453                 return errno > 0 ? -errno : -ESRCH;
454
455         if (!path_is_absolute(p->pw_dir))
456                 return -EINVAL;
457
458         h = strdup(p->pw_dir);
459         if (!h)
460                 return -ENOMEM;
461
462         *_h = h;
463         return 0;
464 }
465
466 int get_shell(char **_s) {
467         struct passwd *p;
468         const char *e;
469         char *s;
470         uid_t u;
471
472         assert(_s);
473
474         /* Take the user specified one */
475         e = getenv("SHELL");
476         if (e) {
477                 s = strdup(e);
478                 if (!s)
479                         return -ENOMEM;
480
481                 *_s = s;
482                 return 0;
483         }
484
485         /* Hardcode shell for root and nobody to avoid NSS */
486         u = getuid();
487         if (u == 0) {
488                 s = strdup("/bin/sh");
489                 if (!s)
490                         return -ENOMEM;
491
492                 *_s = s;
493                 return 0;
494         }
495         if (synthesize_nobody() &&
496             u == UID_NOBODY) {
497                 s = strdup("/sbin/nologin");
498                 if (!s)
499                         return -ENOMEM;
500
501                 *_s = s;
502                 return 0;
503         }
504
505         /* Check the database... */
506         errno = 0;
507         p = getpwuid(u);
508         if (!p)
509                 return errno > 0 ? -errno : -ESRCH;
510
511         if (!path_is_absolute(p->pw_shell))
512                 return -EINVAL;
513
514         s = strdup(p->pw_shell);
515         if (!s)
516                 return -ENOMEM;
517
518         *_s = s;
519         return 0;
520 }
521 #endif // 0
522
523 int reset_uid_gid(void) {
524         int r;
525
526         r = maybe_setgroups(0, NULL);
527         if (r < 0)
528                 return r;
529
530         if (setresgid(0, 0, 0) < 0)
531                 return -errno;
532
533         if (setresuid(0, 0, 0) < 0)
534                 return -errno;
535
536         return 0;
537 }
538
539 #if 0 /// UNNEEDED by elogind
540 int take_etc_passwd_lock(const char *root) {
541
542         struct flock flock = {
543                 .l_type = F_WRLCK,
544                 .l_whence = SEEK_SET,
545                 .l_start = 0,
546                 .l_len = 0,
547         };
548
549         const char *path;
550         int fd, r;
551
552         /* This is roughly the same as lckpwdf(), but not as awful. We
553          * don't want to use alarm() and signals, hence we implement
554          * our own trivial version of this.
555          *
556          * Note that shadow-utils also takes per-database locks in
557          * addition to lckpwdf(). However, we don't given that they
558          * are redundant as they invoke lckpwdf() first and keep
559          * it during everything they do. The per-database locks are
560          * awfully racy, and thus we just won't do them. */
561
562         if (root)
563                 path = prefix_roota(root, ETC_PASSWD_LOCK_PATH);
564         else
565                 path = ETC_PASSWD_LOCK_PATH;
566
567         fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
568         if (fd < 0)
569                 return log_debug_errno(errno, "Cannot open %s: %m", path);
570
571         r = fcntl(fd, F_SETLKW, &flock);
572         if (r < 0) {
573                 safe_close(fd);
574                 return log_debug_errno(errno, "Locking %s failed: %m", path);
575         }
576
577         return fd;
578 }
579 #endif // 0
580
581 bool valid_user_group_name(const char *u) {
582         const char *i;
583         long sz;
584
585         /* Checks if the specified name is a valid user/group name. Also see POSIX IEEE Std 1003.1-2008, 2016 Edition,
586          * 3.437. We are a bit stricter here however. Specifically we deviate from POSIX rules:
587          *
588          * - We don't allow any dots (this would break chown syntax which permits dots as user/group name separator)
589          * - We require that names fit into the appropriate utmp field
590          * - We don't allow empty user names
591          *
592          * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
593          */
594
595         if (isempty(u))
596                 return false;
597
598         if (!(u[0] >= 'a' && u[0] <= 'z') &&
599             !(u[0] >= 'A' && u[0] <= 'Z') &&
600             u[0] != '_')
601                 return false;
602
603         for (i = u+1; *i; i++) {
604                 if (!(*i >= 'a' && *i <= 'z') &&
605                     !(*i >= 'A' && *i <= 'Z') &&
606                     !(*i >= '0' && *i <= '9') &&
607                     !IN_SET(*i, '_', '-'))
608                         return false;
609         }
610
611         sz = sysconf(_SC_LOGIN_NAME_MAX);
612         assert_se(sz > 0);
613
614         if ((size_t) (i-u) > (size_t) sz)
615                 return false;
616
617         if ((size_t) (i-u) > UT_NAMESIZE - 1)
618                 return false;
619
620         return true;
621 }
622
623 bool valid_user_group_name_or_id(const char *u) {
624
625         /* Similar as above, but is also fine with numeric UID/GID specifications, as long as they are in the right
626          * range, and not the invalid user ids. */
627
628         if (isempty(u))
629                 return false;
630
631         if (valid_user_group_name(u))
632                 return true;
633
634         return parse_uid(u, NULL) >= 0;
635 }
636
637 bool valid_gecos(const char *d) {
638
639         if (!d)
640                 return false;
641
642         if (!utf8_is_valid(d))
643                 return false;
644
645         if (string_has_cc(d, NULL))
646                 return false;
647
648         /* Colons are used as field separators, and hence not OK */
649         if (strchr(d, ':'))
650                 return false;
651
652         return true;
653 }
654
655 bool valid_home(const char *p) {
656         /* Note that this function is also called by valid_shell(), any
657          * changes must account for that. */
658
659         if (isempty(p))
660                 return false;
661
662         if (!utf8_is_valid(p))
663                 return false;
664
665         if (string_has_cc(p, NULL))
666                 return false;
667
668         if (!path_is_absolute(p))
669                 return false;
670
671         if (!path_is_normalized(p))
672                 return false;
673
674         /* Colons are used as field separators, and hence not OK */
675         if (strchr(p, ':'))
676                 return false;
677
678         return true;
679 }
680
681 int maybe_setgroups(size_t size, const gid_t *list) {
682         int r;
683
684         /* Check if setgroups is allowed before we try to drop all the auxiliary groups */
685         if (size == 0) { /* Dropping all aux groups? */
686                 _cleanup_free_ char *setgroups_content = NULL;
687                 bool can_setgroups;
688
689                 r = read_one_line_file("/proc/self/setgroups", &setgroups_content);
690                 if (r == -ENOENT)
691                         /* Old kernels don't have /proc/self/setgroups, so assume we can use setgroups */
692                         can_setgroups = true;
693                 else if (r < 0)
694                         return r;
695                 else
696                         can_setgroups = streq(setgroups_content, "allow");
697
698                 if (!can_setgroups) {
699                         log_debug("Skipping setgroups(), /proc/self/setgroups is set to 'deny'");
700                         return 0;
701                 }
702         }
703
704         if (setgroups(size, list) < 0)
705                 return -errno;
706
707         return 0;
708 }
709
710 bool synthesize_nobody(void) {
711
712 #ifdef NOLEGACY
713         return true;
714 #else
715         /* Returns true when we shall synthesize the "nobody" user (which we do by default). This can be turned off by
716          * touching /etc/systemd/dont-synthesize-nobody in order to provide upgrade compatibility with legacy systems
717          * that used the "nobody" user name and group name for other UIDs/GIDs than 65534.
718          *
719          * Note that we do not employ any kind of synchronization on the following caching variable. If the variable is
720          * accessed in multi-threaded programs in the worst case it might happen that we initialize twice, but that
721          * shouldn't matter as each initialization should come to the same result. */
722         static int cache = -1;
723
724         if (cache < 0)
725                 cache = access("/etc/elogind/dont-synthesize-nobody", F_OK) < 0;
726
727         return cache;
728 #endif
729 }