]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/user-util.c
Merge pull request #6974 from keszybz/clean-up-defines
[thirdparty/systemd.git] / src / basic / user-util.c
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
20 #include <alloca.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <grp.h>
24 #include <pwd.h>
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>
32 #include <utmp.h>
33
34 #include "alloc-util.h"
35 #include "fd-util.h"
36 #include "fileio.h"
37 #include "format-util.h"
38 #include "macro.h"
39 #include "missing.h"
40 #include "parse-util.h"
41 #include "path-util.h"
42 #include "string-util.h"
43 #include "strv.h"
44 #include "user-util.h"
45 #include "utf8.h"
46
47 bool uid_is_valid(uid_t uid) {
48
49 /* Also see POSIX IEEE Std 1003.1-2008, 2016 Edition, 3.436. */
50
51 /* Some libc APIs use UID_INVALID as special placeholder */
52 if (uid == (uid_t) UINT32_C(0xFFFFFFFF))
53 return false;
54
55 /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
56 if (uid == (uid_t) UINT32_C(0xFFFF))
57 return false;
58
59 return true;
60 }
61
62 int parse_uid(const char *s, uid_t *ret) {
63 uint32_t uid = 0;
64 int r;
65
66 assert(s);
67
68 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
69 r = safe_atou32(s, &uid);
70 if (r < 0)
71 return r;
72
73 if (!uid_is_valid(uid))
74 return -ENXIO; /* we return ENXIO instead of EINVAL
75 * here, to make it easy to distuingish
76 * invalid numeric uids from invalid
77 * strings. */
78
79 if (ret)
80 *ret = uid;
81
82 return 0;
83 }
84
85 char* 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
94 return uid_to_name(uid);
95 }
96
97 char *getusername_malloc(void) {
98 const char *e;
99
100 e = getenv("USER");
101 if (e)
102 return strdup(e);
103
104 return uid_to_name(getuid());
105 }
106
107 int 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
159 if (uid) {
160 if (!uid_is_valid(p->pw_uid))
161 return -EBADMSG;
162
163 *uid = p->pw_uid;
164 }
165
166 if (gid) {
167 if (!gid_is_valid(p->pw_gid))
168 return -EBADMSG;
169
170 *gid = p->pw_gid;
171 }
172
173 if (home)
174 *home = p->pw_dir;
175
176 if (shell)
177 *shell = p->pw_shell;
178
179 return 0;
180 }
181
182 int 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
211 int 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
243 if (gid) {
244 if (!gid_is_valid(g->gr_gid))
245 return -EBADMSG;
246
247 *gid = g->gr_gid;
248 }
249
250 return 0;
251 }
252
253 char* uid_to_name(uid_t uid) {
254 char *ret;
255 int r;
256
257 /* Shortcut things to avoid NSS lookups */
258 if (uid == 0)
259 return strdup("root");
260
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 }
285
286 if (asprintf(&ret, UID_FMT, uid) < 0)
287 return NULL;
288
289 return ret;
290 }
291
292 char* gid_to_name(gid_t gid) {
293 char *ret;
294 int r;
295
296 if (gid == 0)
297 return strdup("root");
298
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 }
323
324 if (asprintf(&ret, GID_FMT, gid) < 0)
325 return NULL;
326
327 return ret;
328 }
329
330 int 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
340 if (!gid_is_valid(gid))
341 return -EINVAL;
342
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
359 int 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
370 int 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
417 int 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
464 int reset_uid_gid(void) {
465 int r;
466
467 r = maybe_setgroups(0, NULL);
468 if (r < 0)
469 return r;
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 }
479
480 int 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
498 * are redundant as they invoke lckpwdf() first and keep
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 }
519
520 bool valid_user_group_name(const char *u) {
521 const char *i;
522 long sz;
523
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 */
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') &&
546 !IN_SET(*i, '_', '-'))
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
562 bool 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
576 bool 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
594 bool 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 }
617
618 int maybe_setgroups(size_t size, const gid_t *list) {
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'");
637 return 0;
638 }
639 }
640
641 if (setgroups(size, list) < 0)
642 return -errno;
643
644 return 0;
645 }