]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/user-util.c
user-util: rework how we validate user names
[thirdparty/systemd.git] / src / basic / user-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
b1d4f8e1 2
11c3a366
TA
3#include <errno.h>
4#include <fcntl.h>
11c3a366
TA
5#include <stddef.h>
6#include <stdint.h>
7#include <stdio.h>
8#include <stdlib.h>
11c3a366
TA
9#include <sys/stat.h>
10#include <unistd.h>
e4631b48 11#include <utmp.h>
b1d4f8e1 12
7a8867ab
LP
13#include "sd-messages.h"
14
b5efdb8a 15#include "alloc-util.h"
66855de7 16#include "errno-util.h"
e929bee0 17#include "fd-util.h"
36d85478 18#include "fileio.h"
f97b34a6 19#include "format-util.h"
b1d4f8e1 20#include "macro.h"
6bedfcbb 21#include "parse-util.h"
b1d4f8e1 22#include "path-util.h"
7a8867ab 23#include "path-util.h"
f2c5edbe 24#include "random-util.h"
6bedfcbb 25#include "string-util.h"
be39ccf3 26#include "strv.h"
6bedfcbb 27#include "user-util.h"
e4631b48 28#include "utf8.h"
b1d4f8e1
LP
29
30bool uid_is_valid(uid_t uid) {
31
1429dfe5
LP
32 /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.436. */
33
b1d4f8e1 34 /* Some libc APIs use UID_INVALID as special placeholder */
b1d52773 35 if (uid == (uid_t) UINT32_C(0xFFFFFFFF))
b1d4f8e1
LP
36 return false;
37
38 /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
b1d52773 39 if (uid == (uid_t) UINT32_C(0xFFFF))
b1d4f8e1
LP
40 return false;
41
42 return true;
43}
44
b1d52773
LP
45int parse_uid(const char *s, uid_t *ret) {
46 uint32_t uid = 0;
b1d4f8e1
LP
47 int r;
48
49 assert(s);
50
b1d52773
LP
51 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
52 r = safe_atou32(s, &uid);
b1d4f8e1
LP
53 if (r < 0)
54 return r;
55
b1d4f8e1
LP
56 if (!uid_is_valid(uid))
57 return -ENXIO; /* we return ENXIO instead of EINVAL
5238e957 58 * here, to make it easy to distinguish
ba60af86 59 * invalid numeric uids from invalid
b1d4f8e1
LP
60 * strings. */
61
b1d52773
LP
62 if (ret)
63 *ret = uid;
b1d4f8e1
LP
64
65 return 0;
66}
67
03de302a
YW
68int parse_uid_range(const char *s, uid_t *ret_lower, uid_t *ret_upper) {
69 uint32_t u, l;
70 int r;
71
72 assert(s);
73 assert(ret_lower);
74 assert(ret_upper);
75
76 r = parse_range(s, &l, &u);
77 if (r < 0)
78 return r;
79
80 if (l > u)
81 return -EINVAL;
82
83 if (!uid_is_valid(l) || !uid_is_valid(u))
84 return -ENXIO;
85
86 *ret_lower = l;
87 *ret_upper = u;
88 return 0;
89}
90
b1d4f8e1
LP
91char* getlogname_malloc(void) {
92 uid_t uid;
93 struct stat st;
94
95 if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
96 uid = st.st_uid;
97 else
98 uid = getuid();
99
d0260817 100 return uid_to_name(uid);
b1d4f8e1
LP
101}
102
103char *getusername_malloc(void) {
104 const char *e;
105
b2a3953f 106 e = secure_getenv("USER");
b1d4f8e1
LP
107 if (e)
108 return strdup(e);
109
d0260817 110 return uid_to_name(getuid());
b1d4f8e1
LP
111}
112
6093b2bb 113bool is_nologin_shell(const char *shell) {
fafff8f1
LP
114
115 return PATH_IN_SET(shell,
116 /* 'nologin' is the friendliest way to disable logins for a user account. It prints a nice
117 * message and exits. Different distributions place the binary at different places though,
118 * hence let's list them all. */
119 "/bin/nologin",
120 "/sbin/nologin",
121 "/usr/bin/nologin",
122 "/usr/sbin/nologin",
123 /* 'true' and 'false' work too for the same purpose, but are less friendly as they don't do
124 * any message printing. Different distributions place the binary at various places but at
125 * least not in the 'sbin' directory. */
126 "/bin/false",
127 "/usr/bin/false",
128 "/bin/true",
129 "/usr/bin/true");
130}
131
132static int synthesize_user_creds(
b1d4f8e1
LP
133 const char **username,
134 uid_t *uid, gid_t *gid,
135 const char **home,
fafff8f1
LP
136 const char **shell,
137 UserCredsFlags flags) {
b1d4f8e1 138
7e61fd02
LP
139 /* We enforce some special rules for uid=0 and uid=65534: in order to avoid NSS lookups for root we hardcode
140 * their user record data. */
b1d4f8e1 141
7e61fd02 142 if (STR_IN_SET(*username, "root", "0")) {
b1d4f8e1
LP
143 *username = "root";
144
145 if (uid)
146 *uid = 0;
b1d4f8e1
LP
147 if (gid)
148 *gid = 0;
149
150 if (home)
151 *home = "/root";
152
153 if (shell)
154 *shell = "/bin/sh";
155
156 return 0;
157 }
158
24eccc34
LP
159 if (synthesize_nobody() &&
160 STR_IN_SET(*username, NOBODY_USER_NAME, "65534")) {
7e61fd02
LP
161 *username = NOBODY_USER_NAME;
162
163 if (uid)
164 *uid = UID_NOBODY;
165 if (gid)
166 *gid = GID_NOBODY;
167
168 if (home)
fafff8f1 169 *home = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : "/";
7e61fd02
LP
170
171 if (shell)
6db90462 172 *shell = FLAGS_SET(flags, USER_CREDS_CLEAN) ? NULL : NOLOGIN;
7e61fd02
LP
173
174 return 0;
175 }
176
fafff8f1
LP
177 return -ENOMEDIUM;
178}
179
180int get_user_creds(
181 const char **username,
182 uid_t *uid, gid_t *gid,
183 const char **home,
184 const char **shell,
185 UserCredsFlags flags) {
186
187 uid_t u = UID_INVALID;
188 struct passwd *p;
189 int r;
190
191 assert(username);
192 assert(*username);
193
43ad3ad7 194 if (!FLAGS_SET(flags, USER_CREDS_PREFER_NSS) ||
fafff8f1
LP
195 (!home && !shell)) {
196
197 /* So here's the deal: normally, we'll try to synthesize all records we can synthesize, and override
43ad3ad7 198 * the user database with that. However, if the user specifies USER_CREDS_PREFER_NSS then the
fafff8f1
LP
199 * user database will override the synthetic records instead — except if the user is only interested in
200 * the UID and/or GID (but not the home directory, or the shell), in which case we'll always override
43ad3ad7 201 * the user database (i.e. the USER_CREDS_PREFER_NSS flag has no effect in this case). Why?
fafff8f1
LP
202 * Simply because there are valid usecase where the user might change the home directory or the shell
203 * of the relevant users, but changing the UID/GID mappings for them is something we explicitly don't
204 * support. */
205
206 r = synthesize_user_creds(username, uid, gid, home, shell, flags);
207 if (r >= 0)
208 return 0;
209 if (r != -ENOMEDIUM) /* not a username we can synthesize */
210 return r;
211 }
212
b1d4f8e1
LP
213 if (parse_uid(*username, &u) >= 0) {
214 errno = 0;
215 p = getpwuid(u);
216
fafff8f1
LP
217 /* If there are multiple users with the same id, make sure to leave $USER to the configured value
218 * instead of the first occurrence in the database. However if the uid was configured by a numeric uid,
219 * then let's pick the real username from /etc/passwd. */
b1d4f8e1
LP
220 if (p)
221 *username = p->pw_name;
fafff8f1
LP
222 else if (FLAGS_SET(flags, USER_CREDS_ALLOW_MISSING) && !gid && !home && !shell) {
223
224 /* If the specified user is a numeric UID and it isn't in the user database, and the caller
225 * passed USER_CREDS_ALLOW_MISSING and was only interested in the UID, then juts return that
226 * and don't complain. */
227
228 if (uid)
229 *uid = u;
230
231 return 0;
232 }
b1d4f8e1
LP
233 } else {
234 errno = 0;
235 p = getpwnam(*username);
236 }
fafff8f1 237 if (!p) {
66855de7 238 r = errno_or_else(ESRCH);
b1d4f8e1 239
fafff8f1 240 /* If the user requested that we only synthesize as fallback, do so now */
43ad3ad7 241 if (FLAGS_SET(flags, USER_CREDS_PREFER_NSS)) {
fafff8f1
LP
242 if (synthesize_user_creds(username, uid, gid, home, shell, flags) >= 0)
243 return 0;
244 }
245
246 return r;
247 }
b1d4f8e1 248
67c7c892
LP
249 if (uid) {
250 if (!uid_is_valid(p->pw_uid))
251 return -EBADMSG;
252
b1d4f8e1 253 *uid = p->pw_uid;
67c7c892
LP
254 }
255
256 if (gid) {
257 if (!gid_is_valid(p->pw_gid))
258 return -EBADMSG;
b1d4f8e1 259
b1d4f8e1 260 *gid = p->pw_gid;
67c7c892 261 }
b1d4f8e1 262
fafff8f1 263 if (home) {
71ae7b57
LP
264 if (FLAGS_SET(flags, USER_CREDS_CLEAN) &&
265 (empty_or_root(p->pw_dir) ||
266 !path_is_valid(p->pw_dir) ||
267 !path_is_absolute(p->pw_dir)))
268 *home = NULL; /* Note: we don't insist on normalized paths, since there are setups that have /./ in the path */
fafff8f1
LP
269 else
270 *home = p->pw_dir;
271 }
be39ccf3 272
fafff8f1 273 if (shell) {
71ae7b57
LP
274 if (FLAGS_SET(flags, USER_CREDS_CLEAN) &&
275 (isempty(p->pw_shell) ||
276 !path_is_valid(p->pw_dir) ||
277 !path_is_absolute(p->pw_shell) ||
278 is_nologin_shell(p->pw_shell)))
fafff8f1
LP
279 *shell = NULL;
280 else
281 *shell = p->pw_shell;
282 }
be39ccf3
LP
283
284 return 0;
285}
286
fafff8f1 287int get_group_creds(const char **groupname, gid_t *gid, UserCredsFlags flags) {
b1d4f8e1
LP
288 struct group *g;
289 gid_t id;
290
291 assert(groupname);
292
fafff8f1 293 /* We enforce some special rules for gid=0: in order to avoid NSS lookups for root we hardcode its data. */
b1d4f8e1 294
7e61fd02 295 if (STR_IN_SET(*groupname, "root", "0")) {
b1d4f8e1
LP
296 *groupname = "root";
297
298 if (gid)
299 *gid = 0;
300
301 return 0;
302 }
303
24eccc34
LP
304 if (synthesize_nobody() &&
305 STR_IN_SET(*groupname, NOBODY_GROUP_NAME, "65534")) {
7e61fd02
LP
306 *groupname = NOBODY_GROUP_NAME;
307
308 if (gid)
309 *gid = GID_NOBODY;
310
311 return 0;
312 }
313
b1d4f8e1
LP
314 if (parse_gid(*groupname, &id) >= 0) {
315 errno = 0;
316 g = getgrgid(id);
317
318 if (g)
319 *groupname = g->gr_name;
fafff8f1
LP
320 else if (FLAGS_SET(flags, USER_CREDS_ALLOW_MISSING)) {
321 if (gid)
322 *gid = id;
323
324 return 0;
325 }
b1d4f8e1
LP
326 } else {
327 errno = 0;
328 g = getgrnam(*groupname);
329 }
330
331 if (!g)
66855de7 332 return errno_or_else(ESRCH);
b1d4f8e1 333
67c7c892
LP
334 if (gid) {
335 if (!gid_is_valid(g->gr_gid))
336 return -EBADMSG;
337
b1d4f8e1 338 *gid = g->gr_gid;
67c7c892 339 }
b1d4f8e1
LP
340
341 return 0;
342}
343
344char* uid_to_name(uid_t uid) {
d0260817
LP
345 char *ret;
346 int r;
b1d4f8e1 347
d0260817 348 /* Shortcut things to avoid NSS lookups */
b1d4f8e1
LP
349 if (uid == 0)
350 return strdup("root");
24eccc34
LP
351 if (synthesize_nobody() &&
352 uid == UID_NOBODY)
7e61fd02 353 return strdup(NOBODY_USER_NAME);
b1d4f8e1 354
d0260817
LP
355 if (uid_is_valid(uid)) {
356 long bufsize;
357
358 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
359 if (bufsize <= 0)
360 bufsize = 4096;
361
362 for (;;) {
363 struct passwd pwbuf, *pw = NULL;
364 _cleanup_free_ char *buf = NULL;
365
366 buf = malloc(bufsize);
367 if (!buf)
368 return NULL;
369
370 r = getpwuid_r(uid, &pwbuf, buf, (size_t) bufsize, &pw);
371 if (r == 0 && pw)
372 return strdup(pw->pw_name);
373 if (r != ERANGE)
374 break;
375
47436d30
LP
376 if (bufsize > LONG_MAX/2) /* overflow check */
377 return NULL;
378
d0260817
LP
379 bufsize *= 2;
380 }
381 }
b1d4f8e1 382
d0260817 383 if (asprintf(&ret, UID_FMT, uid) < 0)
b1d4f8e1
LP
384 return NULL;
385
d0260817 386 return ret;
b1d4f8e1
LP
387}
388
389char* gid_to_name(gid_t gid) {
d0260817
LP
390 char *ret;
391 int r;
b1d4f8e1
LP
392
393 if (gid == 0)
394 return strdup("root");
24eccc34
LP
395 if (synthesize_nobody() &&
396 gid == GID_NOBODY)
7e61fd02 397 return strdup(NOBODY_GROUP_NAME);
b1d4f8e1 398
d0260817
LP
399 if (gid_is_valid(gid)) {
400 long bufsize;
401
402 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
403 if (bufsize <= 0)
404 bufsize = 4096;
405
406 for (;;) {
407 struct group grbuf, *gr = NULL;
408 _cleanup_free_ char *buf = NULL;
409
410 buf = malloc(bufsize);
411 if (!buf)
412 return NULL;
413
414 r = getgrgid_r(gid, &grbuf, buf, (size_t) bufsize, &gr);
415 if (r == 0 && gr)
416 return strdup(gr->gr_name);
417 if (r != ERANGE)
418 break;
419
47436d30
LP
420 if (bufsize > LONG_MAX/2) /* overflow check */
421 return NULL;
422
d0260817
LP
423 bufsize *= 2;
424 }
425 }
b1d4f8e1 426
d0260817 427 if (asprintf(&ret, GID_FMT, gid) < 0)
b1d4f8e1
LP
428 return NULL;
429
d0260817 430 return ret;
b1d4f8e1
LP
431}
432
0c5d6679
DG
433static bool gid_list_has(const gid_t *list, size_t size, gid_t val) {
434 for (size_t i = 0; i < size; i++)
435 if (list[i] == val)
436 return true;
437 return false;
438}
439
b1d4f8e1 440int in_gid(gid_t gid) {
0c5d6679
DG
441 _cleanup_free_ gid_t *gids = NULL;
442 int ngroups;
b1d4f8e1
LP
443
444 if (getgid() == gid)
445 return 1;
446
447 if (getegid() == gid)
448 return 1;
449
67c7c892
LP
450 if (!gid_is_valid(gid))
451 return -EINVAL;
452
0c5d6679
DG
453 ngroups = getgroups_alloc(&gids);
454 if (ngroups < 0)
455 return ngroups;
456
457 return gid_list_has(gids, ngroups, gid);
458}
459
460int in_group(const char *name) {
461 int r;
462 gid_t gid;
463
464 r = get_group_creds(&name, &gid, 0);
465 if (r < 0)
466 return r;
467
468 return in_gid(gid);
469}
470
471int merge_gid_lists(const gid_t *list1, size_t size1, const gid_t *list2, size_t size2, gid_t **ret) {
472 size_t nresult = 0;
473 assert(ret);
474
475 if (size2 > INT_MAX - size1)
476 return -ENOBUFS;
477
478 gid_t *buf = new(gid_t, size1 + size2);
479 if (!buf)
480 return -ENOMEM;
481
482 /* Duplicates need to be skipped on merging, otherwise they'll be passed on and stored in the kernel. */
483 for (size_t i = 0; i < size1; i++)
484 if (!gid_list_has(buf, nresult, list1[i]))
485 buf[nresult++] = list1[i];
486 for (size_t i = 0; i < size2; i++)
487 if (!gid_list_has(buf, nresult, list2[i]))
488 buf[nresult++] = list2[i];
489 *ret = buf;
490 return (int)nresult;
491}
492
493int getgroups_alloc(gid_t** gids) {
494 gid_t *allocated;
495 _cleanup_free_ gid_t *p = NULL;
496 int ngroups = 8;
497 unsigned attempt = 0;
498
499 allocated = new(gid_t, ngroups);
500 if (!allocated)
501 return -ENOMEM;
502 p = allocated;
503
6e0a3888
LP
504 for (;;) {
505 ngroups = getgroups(ngroups, p);
506 if (ngroups >= 0)
507 break;
508 if (errno != EINVAL)
509 return -errno;
510
511 /* Give up eventually */
512 if (attempt++ > 10)
513 return -EINVAL;
514
515 /* Get actual size needed, and size the array explicitly. Note that this is potentially racy
516 * to use (in multi-threaded programs), hence let's call this in a loop. */
517 ngroups = getgroups(0, NULL);
518 if (ngroups < 0)
519 return -errno;
520 if (ngroups == 0)
521 return false;
522
523 free(allocated);
524
4af8ab2c 525 p = allocated = new(gid_t, ngroups);
6e0a3888
LP
526 if (!allocated)
527 return -ENOMEM;
6e0a3888 528 }
b1d4f8e1 529
0c5d6679
DG
530 *gids = TAKE_PTR(p);
531 return ngroups;
b1d4f8e1
LP
532}
533
534int get_home_dir(char **_h) {
535 struct passwd *p;
536 const char *e;
537 char *h;
538 uid_t u;
539
540 assert(_h);
541
542 /* Take the user specified one */
543 e = secure_getenv("HOME");
d575f88b 544 if (e && path_is_valid(e) && path_is_absolute(e)) {
b1d4f8e1
LP
545 h = strdup(e);
546 if (!h)
547 return -ENOMEM;
548
db246781 549 *_h = path_simplify(h, true);
b1d4f8e1
LP
550 return 0;
551 }
552
7e61fd02 553 /* Hardcode home directory for root and nobody to avoid NSS */
b1d4f8e1
LP
554 u = getuid();
555 if (u == 0) {
556 h = strdup("/root");
557 if (!h)
558 return -ENOMEM;
559
560 *_h = h;
561 return 0;
562 }
24eccc34
LP
563 if (synthesize_nobody() &&
564 u == UID_NOBODY) {
7e61fd02
LP
565 h = strdup("/");
566 if (!h)
567 return -ENOMEM;
568
569 *_h = h;
570 return 0;
571 }
b1d4f8e1
LP
572
573 /* Check the database... */
574 errno = 0;
575 p = getpwuid(u);
576 if (!p)
66855de7 577 return errno_or_else(ESRCH);
b1d4f8e1 578
d575f88b
LP
579 if (!path_is_valid(p->pw_dir) ||
580 !path_is_absolute(p->pw_dir))
b1d4f8e1
LP
581 return -EINVAL;
582
583 h = strdup(p->pw_dir);
584 if (!h)
585 return -ENOMEM;
586
db246781 587 *_h = path_simplify(h, true);
b1d4f8e1
LP
588 return 0;
589}
590
591int get_shell(char **_s) {
592 struct passwd *p;
593 const char *e;
594 char *s;
595 uid_t u;
596
597 assert(_s);
598
599 /* Take the user specified one */
b2a3953f 600 e = secure_getenv("SHELL");
d575f88b 601 if (e && path_is_valid(e) && path_is_absolute(e)) {
b1d4f8e1
LP
602 s = strdup(e);
603 if (!s)
604 return -ENOMEM;
605
db246781 606 *_s = path_simplify(s, true);
b1d4f8e1
LP
607 return 0;
608 }
609
7e61fd02 610 /* Hardcode shell for root and nobody to avoid NSS */
b1d4f8e1
LP
611 u = getuid();
612 if (u == 0) {
613 s = strdup("/bin/sh");
614 if (!s)
615 return -ENOMEM;
616
617 *_s = s;
618 return 0;
619 }
24eccc34
LP
620 if (synthesize_nobody() &&
621 u == UID_NOBODY) {
6db90462 622 s = strdup(NOLOGIN);
7e61fd02
LP
623 if (!s)
624 return -ENOMEM;
625
626 *_s = s;
627 return 0;
628 }
b1d4f8e1
LP
629
630 /* Check the database... */
631 errno = 0;
632 p = getpwuid(u);
633 if (!p)
66855de7 634 return errno_or_else(ESRCH);
b1d4f8e1 635
d575f88b
LP
636 if (!path_is_valid(p->pw_shell) ||
637 !path_is_absolute(p->pw_shell))
b1d4f8e1
LP
638 return -EINVAL;
639
640 s = strdup(p->pw_shell);
641 if (!s)
642 return -ENOMEM;
643
db246781 644 *_s = path_simplify(s, true);
b1d4f8e1
LP
645 return 0;
646}
647
648int reset_uid_gid(void) {
97f0e76f 649 int r;
b1d4f8e1 650
97f0e76f
LP
651 r = maybe_setgroups(0, NULL);
652 if (r < 0)
653 return r;
b1d4f8e1
LP
654
655 if (setresgid(0, 0, 0) < 0)
656 return -errno;
657
658 if (setresuid(0, 0, 0) < 0)
659 return -errno;
660
661 return 0;
662}
e929bee0
LP
663
664int take_etc_passwd_lock(const char *root) {
665
666 struct flock flock = {
667 .l_type = F_WRLCK,
668 .l_whence = SEEK_SET,
669 .l_start = 0,
670 .l_len = 0,
671 };
672
673 const char *path;
674 int fd, r;
675
676 /* This is roughly the same as lckpwdf(), but not as awful. We
677 * don't want to use alarm() and signals, hence we implement
678 * our own trivial version of this.
679 *
680 * Note that shadow-utils also takes per-database locks in
681 * addition to lckpwdf(). However, we don't given that they
61233823 682 * are redundant as they invoke lckpwdf() first and keep
e929bee0
LP
683 * it during everything they do. The per-database locks are
684 * awfully racy, and thus we just won't do them. */
685
686 if (root)
d1e4b8fd 687 path = prefix_roota(root, ETC_PASSWD_LOCK_PATH);
e929bee0 688 else
d1e4b8fd 689 path = ETC_PASSWD_LOCK_PATH;
e929bee0
LP
690
691 fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
692 if (fd < 0)
d1e4b8fd 693 return log_debug_errno(errno, "Cannot open %s: %m", path);
e929bee0
LP
694
695 r = fcntl(fd, F_SETLKW, &flock);
696 if (r < 0) {
697 safe_close(fd);
d1e4b8fd 698 return log_debug_errno(errno, "Locking %s failed: %m", path);
e929bee0
LP
699 }
700
701 return fd;
702}
e4631b48 703
7a8867ab 704bool valid_user_group_name(const char *u, ValidUserFlags flags) {
e4631b48 705 const char *i;
e4631b48 706
7a8867ab
LP
707 /* Checks if the specified name is a valid user/group name. There are two flavours of this call:
708 * strict mode is the default which is POSIX plus some extra rules; and relaxed mode where we accept
709 * pretty much everything except the really worst offending names.
1429dfe5 710 *
7a8867ab
LP
711 * Whenever we synthesize users ourselves we should use the strict mode. But when we process users
712 * created by other stuff, let's be more liberal. */
e4631b48 713
7a8867ab 714 if (isempty(u)) /* An empty user name is never valid */
e4631b48
LP
715 return false;
716
7a8867ab
LP
717 if (parse_uid(u, NULL) >= 0) /* Something that parses as numeric UID string is valid exactly when the
718 * flag for it is set */
719 return FLAGS_SET(flags, VALID_USER_ALLOW_NUMERIC);
720
721 if (FLAGS_SET(flags, VALID_USER_RELAX)) {
722
723 /* In relaxed mode we just check very superficially. Apparently SSSD and other stuff is
724 * extremely liberal (way too liberal if you ask me, even inserting "@" in user names, which
725 * is bound to cause problems for example when used with an MTA), hence only filter the most
726 * obvious cases, or where things would result in an invalid entry if such a user name would
727 * show up in /etc/passwd (or equivalent getent output).
728 *
729 * Note that we stepped far out of POSIX territory here. It's not our fault though, but
730 * SSSD's, Samba's and everybody else who ignored POSIX on this. (I mean, I am happy to step
731 * outside of POSIX' bounds any day, but I must say in this case I probably wouldn't
732 * have...) */
733
734 if (startswith(u, " ") || endswith(u, " ")) /* At least expect whitespace padding is removed
735 * at front and back (accept in the middle, since
736 * that's apparently a thing on Windows). Note
737 * that this also blocks usernames consisting of
738 * whitespace only. */
739 return false;
93c23c92 740
7a8867ab
LP
741 if (!utf8_is_valid(u)) /* We want to synthesize JSON from this, hence insist on UTF-8 */
742 return false;
88e2ed0b 743
7a8867ab
LP
744 if (string_has_cc(u, NULL)) /* CC characters are just dangerous (and \n in particular is the
745 * record separator in /etc/passwd), so we can't allow that. */
746 return false;
88e2ed0b 747
7a8867ab
LP
748 if (strpbrk(u, ":/")) /* Colons are the field separator in /etc/passwd, we can't allow
749 * that. Slashes are special to file systems paths and user names
750 * typically show up in the file system as home directories, hence
751 * don't allow slashes. */
752 return false;
e4631b48 753
7a8867ab
LP
754 if (in_charset(u, "0123456789")) /* Don't allow fully numeric strings, they might be confused
755 * with with UIDs (note that this test is more broad than
756 * the parse_uid() test above, as it will cover more than
757 * the 32bit range, and it will detect 65535 (which is in
758 * invalid UID, even though in the unsigned 32 bit range) */
759 return false;
93c23c92 760
7a8867ab
LP
761 if (u[0] == '-' && in_charset(u + 1, "0123456789")) /* Don't allow negative fully numeric
762 * strings either. After all some people
763 * write 65535 as -1 (even though that's
764 * not even true on 32bit uid_t
765 * anyway) */
766 return false;
e4631b48 767
7a8867ab
LP
768 if (dot_or_dot_dot(u)) /* User names typically become home directory names, and these two are
769 * special in that context, don't allow that. */
770 return false;
e4631b48 771
7a8867ab
LP
772 /* Compare with strict result and warn if result doesn't match */
773 if (FLAGS_SET(flags, VALID_USER_WARN) && !valid_user_group_name(u, 0))
774 log_struct(LOG_NOTICE,
775 "MESSAGE=Accepting user/group name '%s', which does not match strict user/group name rules.", u,
776 "USER_GROUP_NAME=%s", u,
777 "MESSAGE_ID=" SD_MESSAGE_UNSAFE_USER_NAME_STR);
e4631b48 778
7a8867ab
LP
779 /* Note that we make no restrictions on the length in relaxed mode! */
780 } else {
781 long sz;
782 size_t l;
783
784 /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.437. We are a bit stricter here
785 * however. Specifically we deviate from POSIX rules:
786 *
787 * - We don't allow empty user names (see above)
788 * - We require that names fit into the appropriate utmp field
789 * - We don't allow any dots (this conflicts with chown syntax which permits dots as user/group name separator)
790 * - We don't allow dashes or digit as the first character
791 *
792 * Note that other systems are even more restrictive, and don't permit underscores or uppercase characters.
793 */
794
795 if (!(u[0] >= 'a' && u[0] <= 'z') &&
796 !(u[0] >= 'A' && u[0] <= 'Z') &&
797 u[0] != '_')
798 return false;
e4631b48 799
7a8867ab
LP
800 for (i = u+1; *i; i++)
801 if (!(*i >= 'a' && *i <= 'z') &&
802 !(*i >= 'A' && *i <= 'Z') &&
803 !(*i >= '0' && *i <= '9') &&
804 !IN_SET(*i, '_', '-'))
805 return false;
e4631b48 806
7a8867ab 807 l = i - u;
e4631b48 808
7a8867ab
LP
809 sz = sysconf(_SC_LOGIN_NAME_MAX);
810 assert_se(sz > 0);
e4631b48 811
7a8867ab
LP
812 if (l > (size_t) sz)
813 return false;
814 if (l > FILENAME_MAX)
815 return false;
816 if (l > UT_NAMESIZE - 1)
817 return false;
818 }
e4631b48 819
7a8867ab 820 return true;
e4631b48
LP
821}
822
823bool valid_gecos(const char *d) {
824
825 if (!d)
826 return false;
827
828 if (!utf8_is_valid(d))
829 return false;
830
831 if (string_has_cc(d, NULL))
832 return false;
833
834 /* Colons are used as field separators, and hence not OK */
835 if (strchr(d, ':'))
836 return false;
837
838 return true;
839}
840
841bool valid_home(const char *p) {
7b1aaf66
ZJS
842 /* Note that this function is also called by valid_shell(), any
843 * changes must account for that. */
e4631b48
LP
844
845 if (isempty(p))
846 return false;
847
848 if (!utf8_is_valid(p))
849 return false;
850
851 if (string_has_cc(p, NULL))
852 return false;
853
854 if (!path_is_absolute(p))
855 return false;
856
99be45a4 857 if (!path_is_normalized(p))
e4631b48
LP
858 return false;
859
860 /* Colons are used as field separators, and hence not OK */
861 if (strchr(p, ':'))
862 return false;
863
864 return true;
865}
36d85478
GS
866
867int maybe_setgroups(size_t size, const gid_t *list) {
97f0e76f
LP
868 int r;
869
870 /* Check if setgroups is allowed before we try to drop all the auxiliary groups */
871 if (size == 0) { /* Dropping all aux groups? */
872 _cleanup_free_ char *setgroups_content = NULL;
873 bool can_setgroups;
874
875 r = read_one_line_file("/proc/self/setgroups", &setgroups_content);
876 if (r == -ENOENT)
877 /* Old kernels don't have /proc/self/setgroups, so assume we can use setgroups */
878 can_setgroups = true;
879 else if (r < 0)
880 return r;
881 else
882 can_setgroups = streq(setgroups_content, "allow");
883
884 if (!can_setgroups) {
885 log_debug("Skipping setgroups(), /proc/self/setgroups is set to 'deny'");
36d85478 886 return 0;
97f0e76f 887 }
36d85478 888 }
97f0e76f
LP
889
890 if (setgroups(size, list) < 0)
891 return -errno;
892
893 return 0;
36d85478 894}
24eccc34
LP
895
896bool synthesize_nobody(void) {
24eccc34
LP
897 /* Returns true when we shall synthesize the "nobody" user (which we do by default). This can be turned off by
898 * touching /etc/systemd/dont-synthesize-nobody in order to provide upgrade compatibility with legacy systems
899 * that used the "nobody" user name and group name for other UIDs/GIDs than 65534.
900 *
901 * Note that we do not employ any kind of synchronization on the following caching variable. If the variable is
902 * accessed in multi-threaded programs in the worst case it might happen that we initialize twice, but that
903 * shouldn't matter as each initialization should come to the same result. */
904 static int cache = -1;
905
906 if (cache < 0)
907 cache = access("/etc/systemd/dont-synthesize-nobody", F_OK) < 0;
908
909 return cache;
24eccc34 910}
100d5f6e
FB
911
912int putpwent_sane(const struct passwd *pw, FILE *stream) {
913 assert(pw);
914 assert(stream);
915
916 errno = 0;
917 if (putpwent(pw, stream) != 0)
66855de7 918 return errno_or_else(EIO);
100d5f6e
FB
919
920 return 0;
921}
922
923int putspent_sane(const struct spwd *sp, FILE *stream) {
924 assert(sp);
925 assert(stream);
926
927 errno = 0;
928 if (putspent(sp, stream) != 0)
66855de7 929 return errno_or_else(EIO);
100d5f6e
FB
930
931 return 0;
932}
933
934int putgrent_sane(const struct group *gr, FILE *stream) {
935 assert(gr);
936 assert(stream);
937
938 errno = 0;
939 if (putgrent(gr, stream) != 0)
66855de7 940 return errno_or_else(EIO);
100d5f6e
FB
941
942 return 0;
943}
944
945#if ENABLE_GSHADOW
946int putsgent_sane(const struct sgrp *sg, FILE *stream) {
947 assert(sg);
948 assert(stream);
949
950 errno = 0;
951 if (putsgent(sg, stream) != 0)
66855de7 952 return errno_or_else(EIO);
100d5f6e
FB
953
954 return 0;
955}
956#endif
957
958int fgetpwent_sane(FILE *stream, struct passwd **pw) {
959 struct passwd *p;
960
961 assert(pw);
962 assert(stream);
963
964 errno = 0;
965 p = fgetpwent(stream);
ad80c6a6 966 if (!p && errno != ENOENT)
66855de7 967 return errno_or_else(EIO);
100d5f6e
FB
968
969 *pw = p;
ad80c6a6 970 return !!p;
100d5f6e
FB
971}
972
973int fgetspent_sane(FILE *stream, struct spwd **sp) {
974 struct spwd *s;
975
976 assert(sp);
977 assert(stream);
978
979 errno = 0;
980 s = fgetspent(stream);
ad80c6a6 981 if (!s && errno != ENOENT)
66855de7 982 return errno_or_else(EIO);
100d5f6e
FB
983
984 *sp = s;
ad80c6a6 985 return !!s;
100d5f6e
FB
986}
987
988int fgetgrent_sane(FILE *stream, struct group **gr) {
989 struct group *g;
990
991 assert(gr);
992 assert(stream);
993
994 errno = 0;
995 g = fgetgrent(stream);
ad80c6a6 996 if (!g && errno != ENOENT)
66855de7 997 return errno_or_else(EIO);
100d5f6e
FB
998
999 *gr = g;
ad80c6a6 1000 return !!g;
100d5f6e
FB
1001}
1002
1003#if ENABLE_GSHADOW
1004int fgetsgent_sane(FILE *stream, struct sgrp **sg) {
1005 struct sgrp *s;
1006
1007 assert(sg);
1008 assert(stream);
1009
1010 errno = 0;
1011 s = fgetsgent(stream);
ad80c6a6 1012 if (!s && errno != ENOENT)
66855de7 1013 return errno_or_else(EIO);
100d5f6e
FB
1014
1015 *sg = s;
ad80c6a6 1016 return !!s;
100d5f6e
FB
1017}
1018#endif