2 This file is part of systemd.
4 Copyright 2010 Lennart Poettering
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.
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.
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/>.
33 #include "alloc-util.h"
35 #include "formats-util.h"
37 #include "parse-util.h"
38 #include "path-util.h"
39 #include "string-util.h"
40 #include "user-util.h"
42 bool uid_is_valid(uid_t uid) {
44 /* Some libc APIs use UID_INVALID as special placeholder */
45 if (uid == (uid_t) UINT32_C(0xFFFFFFFF))
48 /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
49 if (uid == (uid_t) UINT32_C(0xFFFF))
55 int parse_uid(const char *s, uid_t *ret) {
61 assert_cc(sizeof(uid_t) == sizeof(uint32_t));
62 r = safe_atou32(s, &uid);
66 if (!uid_is_valid(uid))
67 return -ENXIO; /* we return ENXIO instead of EINVAL
68 * here, to make it easy to distuingish
69 * invalid numeric uids from invalid
78 #if 0 /// UNNEEDED by elogind
79 char* getlogname_malloc(void) {
83 if (isatty(STDIN_FILENO) && fstat(STDIN_FILENO, &st) >= 0)
88 return uid_to_name(uid);
91 char *getusername_malloc(void) {
98 return uid_to_name(getuid());
103 const char **username,
104 uid_t *uid, gid_t *gid,
106 const char **shell) {
114 /* We enforce some special rules for uid=0: in order to avoid
115 * NSS lookups for root we hardcode its data. */
117 if (streq(*username, "root") || streq(*username, "0")) {
135 if (parse_uid(*username, &u) >= 0) {
139 /* If there are multiple users with the same id, make
140 * sure to leave $USER to the configured value instead
141 * of the first occurrence in the database. However if
142 * the uid was configured by a numeric uid, then let's
143 * pick the real username from /etc/passwd. */
145 *username = p->pw_name;
148 p = getpwnam(*username);
152 return errno > 0 ? -errno : -ESRCH;
155 if (!uid_is_valid(p->pw_uid))
162 if (!gid_is_valid(p->pw_gid))
172 *shell = p->pw_shell;
177 int get_group_creds(const char **groupname, gid_t *gid) {
183 /* We enforce some special rules for gid=0: in order to avoid
184 * NSS lookups for root we hardcode its data. */
186 if (streq(*groupname, "root") || streq(*groupname, "0")) {
195 if (parse_gid(*groupname, &id) >= 0) {
200 *groupname = g->gr_name;
203 g = getgrnam(*groupname);
207 return errno > 0 ? -errno : -ESRCH;
210 if (!gid_is_valid(g->gr_gid))
219 char* uid_to_name(uid_t uid) {
223 /* Shortcut things to avoid NSS lookups */
225 return strdup("root");
227 if (uid_is_valid(uid)) {
230 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
235 struct passwd pwbuf, *pw = NULL;
236 _cleanup_free_ char *buf = NULL;
238 buf = malloc(bufsize);
242 r = getpwuid_r(uid, &pwbuf, buf, (size_t) bufsize, &pw);
244 return strdup(pw->pw_name);
252 if (asprintf(&ret, UID_FMT, uid) < 0)
258 char* gid_to_name(gid_t gid) {
263 return strdup("root");
265 if (gid_is_valid(gid)) {
268 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
273 struct group grbuf, *gr = NULL;
274 _cleanup_free_ char *buf = NULL;
276 buf = malloc(bufsize);
280 r = getgrgid_r(gid, &grbuf, buf, (size_t) bufsize, &gr);
282 return strdup(gr->gr_name);
290 if (asprintf(&ret, GID_FMT, gid) < 0)
296 #if 0 /// UNNEEDED by elogind
297 int in_gid(gid_t gid) {
299 int ngroups_max, r, i;
304 if (getegid() == gid)
307 if (!gid_is_valid(gid))
310 ngroups_max = sysconf(_SC_NGROUPS_MAX);
311 assert(ngroups_max > 0);
313 gids = alloca(sizeof(gid_t) * ngroups_max);
315 r = getgroups(ngroups_max, gids);
319 for (i = 0; i < r; i++)
326 int in_group(const char *name) {
330 r = get_group_creds(&name, &gid);
337 int get_home_dir(char **_h) {
345 /* Take the user specified one */
346 e = secure_getenv("HOME");
347 if (e && path_is_absolute(e)) {
356 /* Hardcode home directory for root to avoid NSS */
367 /* Check the database... */
371 return errno > 0 ? -errno : -ESRCH;
373 if (!path_is_absolute(p->pw_dir))
376 h = strdup(p->pw_dir);
384 int get_shell(char **_s) {
392 /* Take the user specified one */
403 /* Hardcode home directory for root to avoid NSS */
406 s = strdup("/bin/sh");
414 /* Check the database... */
418 return errno > 0 ? -errno : -ESRCH;
420 if (!path_is_absolute(p->pw_shell))
423 s = strdup(p->pw_shell);
432 int reset_uid_gid(void) {
434 if (setgroups(0, NULL) < 0)
437 if (setresgid(0, 0, 0) < 0)
440 if (setresuid(0, 0, 0) < 0)
446 #if 0 /// UNNEEDED by elogind
447 int take_etc_passwd_lock(const char *root) {
449 struct flock flock = {
451 .l_whence = SEEK_SET,
459 /* This is roughly the same as lckpwdf(), but not as awful. We
460 * don't want to use alarm() and signals, hence we implement
461 * our own trivial version of this.
463 * Note that shadow-utils also takes per-database locks in
464 * addition to lckpwdf(). However, we don't given that they
465 * are redundant as they they invoke lckpwdf() first and keep
466 * it during everything they do. The per-database locks are
467 * awfully racy, and thus we just won't do them. */
470 path = prefix_roota(root, "/etc/.pwd.lock");
472 path = "/etc/.pwd.lock";
474 fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0600);
478 r = fcntl(fd, F_SETLKW, &flock);