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