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