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