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