/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <alloca.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "alloc-util.h"
#include "fd-util.h"
#include "formats-util.h"
#include "macro.h"
#include "parse-util.h"
#include "path-util.h"
#include "string-util.h"
#include "user-util.h"
/* Some libc APIs use UID_INVALID as special placeholder */
return false;
/* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
return false;
return true;
}
int r;
assert(s);
r = safe_atou32(s, &uid);
if (r < 0)
return r;
if (!uid_is_valid(uid))
return -ENXIO; /* we return ENXIO instead of EINVAL
* here, to make it easy to distuingish
* invalid numeric uids from invalid
* strings. */
if (ret)
return 0;
}
char* getlogname_malloc(void) {
else
return uid_to_name(uid);
}
char *getusername_malloc(void) {
const char *e;
e = getenv("USER");
if (e)
return strdup(e);
return uid_to_name(getuid());
}
int get_user_creds(
const char **username,
const char **home,
const char **shell) {
struct passwd *p;
uid_t u;
/* We enforce some special rules for uid=0: in order to avoid
* NSS lookups for root we hardcode its data. */
*username = "root";
if (uid)
*uid = 0;
if (gid)
*gid = 0;
if (home)
*home = "/root";
if (shell)
return 0;
}
errno = 0;
p = getpwuid(u);
/* If there are multiple users with the same id, make
* sure to leave $USER to the configured value instead
* of the first occurrence in the database. However if
* the uid was configured by a numeric uid, then let's
if (p)
} else {
errno = 0;
}
if (!p)
if (uid) {
if (!uid_is_valid(p->pw_uid))
return -EBADMSG;
}
if (gid) {
if (!gid_is_valid(p->pw_gid))
return -EBADMSG;
}
if (home)
if (shell)
return 0;
}
struct group *g;
/* We enforce some special rules for gid=0: in order to avoid
* NSS lookups for root we hardcode its data. */
*groupname = "root";
if (gid)
*gid = 0;
return 0;
}
errno = 0;
if (g)
} else {
errno = 0;
}
if (!g)
if (gid) {
if (!gid_is_valid(g->gr_gid))
return -EBADMSG;
}
return 0;
}
char *ret;
int r;
/* Shortcut things to avoid NSS lookups */
if (uid == 0)
return strdup("root");
if (uid_is_valid(uid)) {
long bufsize;
if (bufsize <= 0)
bufsize = 4096;
for (;;) {
if (!buf)
return NULL;
if (r == 0 && pw)
if (r != ERANGE)
break;
bufsize *= 2;
}
}
return NULL;
return ret;
}
char *ret;
int r;
if (gid == 0)
return strdup("root");
if (gid_is_valid(gid)) {
long bufsize;
if (bufsize <= 0)
bufsize = 4096;
for (;;) {
if (!buf)
return NULL;
if (r == 0 && gr)
if (r != ERANGE)
break;
bufsize *= 2;
}
}
return NULL;
return ret;
}
int ngroups_max, r, i;
return 1;
return 1;
if (!gid_is_valid(gid))
return -EINVAL;
assert(ngroups_max > 0);
if (r < 0)
return -errno;
for (i = 0; i < r; i++)
return 1;
return 0;
}
int r;
if (r < 0)
return r;
}
struct passwd *p;
const char *e;
char *h;
uid_t u;
/* Take the user specified one */
e = secure_getenv("HOME");
if (e && path_is_absolute(e)) {
h = strdup(e);
if (!h)
return -ENOMEM;
*_h = h;
return 0;
}
/* Hardcode home directory for root to avoid NSS */
u = getuid();
if (u == 0) {
h = strdup("/root");
if (!h)
return -ENOMEM;
*_h = h;
return 0;
}
/* Check the database... */
errno = 0;
p = getpwuid(u);
if (!p)
if (!path_is_absolute(p->pw_dir))
return -EINVAL;
if (!h)
return -ENOMEM;
*_h = h;
return 0;
}
struct passwd *p;
const char *e;
char *s;
uid_t u;
/* Take the user specified one */
e = getenv("SHELL");
if (e) {
s = strdup(e);
if (!s)
return -ENOMEM;
*_s = s;
return 0;
}
/* Hardcode home directory for root to avoid NSS */
u = getuid();
if (u == 0) {
if (!s)
return -ENOMEM;
*_s = s;
return 0;
}
/* Check the database... */
errno = 0;
p = getpwuid(u);
if (!p)
if (!path_is_absolute(p->pw_shell))
return -EINVAL;
if (!s)
return -ENOMEM;
*_s = s;
return 0;
}
int reset_uid_gid(void) {
return -errno;
if (setresgid(0, 0, 0) < 0)
return -errno;
if (setresuid(0, 0, 0) < 0)
return -errno;
return 0;
}
.l_start = 0,
.l_len = 0,
};
const char *path;
int fd, r;
/* This is roughly the same as lckpwdf(), but not as awful. We
* don't want to use alarm() and signals, hence we implement
* our own trivial version of this.
*
* Note that shadow-utils also takes per-database locks in
* addition to lckpwdf(). However, we don't given that they
* are redundant as they they invoke lckpwdf() first and keep
* it during everything they do. The per-database locks are
* awfully racy, and thus we just won't do them. */
if (root)
else
path = "/etc/.pwd.lock";
if (fd < 0)
return -errno;
if (r < 0) {
safe_close(fd);
return -errno;
}
return fd;
}