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