mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2025-02-26 23:52:30 +01:00
132 lines
3.4 KiB
C
132 lines
3.4 KiB
C
/* Copyright (c) 2003-2004, Roger Dingledine
|
|
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
|
|
* Copyright (c) 2007-2018, The Tor Project, Inc. */
|
|
/* See LICENSE for licensing information */
|
|
|
|
#include "lib/fs/userdb.h"
|
|
|
|
#ifndef _WIN32
|
|
#include "lib/malloc/util_malloc.h"
|
|
#include "lib/log/torlog.h"
|
|
#include "lib/log/util_bug.h"
|
|
|
|
#include <pwd.h>
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
|
|
/** Cached struct from the last getpwname() call we did successfully. */
|
|
static struct passwd *passwd_cached = NULL;
|
|
|
|
/** Helper: copy a struct passwd object.
|
|
*
|
|
* We only copy the fields pw_uid, pw_gid, pw_name, pw_dir. Tor doesn't use
|
|
* any others, and I don't want to run into incompatibilities.
|
|
*/
|
|
static struct passwd *
|
|
tor_passwd_dup(const struct passwd *pw)
|
|
{
|
|
struct passwd *new_pw = tor_malloc_zero(sizeof(struct passwd));
|
|
if (pw->pw_name)
|
|
new_pw->pw_name = tor_strdup(pw->pw_name);
|
|
if (pw->pw_dir)
|
|
new_pw->pw_dir = tor_strdup(pw->pw_dir);
|
|
new_pw->pw_uid = pw->pw_uid;
|
|
new_pw->pw_gid = pw->pw_gid;
|
|
|
|
return new_pw;
|
|
}
|
|
|
|
#define tor_passwd_free(pw) \
|
|
FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw))
|
|
|
|
/** Helper: free one of our cached 'struct passwd' values. */
|
|
static void
|
|
tor_passwd_free_(struct passwd *pw)
|
|
{
|
|
if (!pw)
|
|
return;
|
|
|
|
tor_free(pw->pw_name);
|
|
tor_free(pw->pw_dir);
|
|
tor_free(pw);
|
|
}
|
|
|
|
/** Wrapper around getpwnam() that caches result. Used so that we don't need
|
|
* to give the sandbox access to /etc/passwd.
|
|
*
|
|
* The following fields alone will definitely be copied in the output: pw_uid,
|
|
* pw_gid, pw_name, pw_dir. Other fields are not present in cached values.
|
|
*
|
|
* When called with a NULL argument, this function clears storage associated
|
|
* with static variables it uses.
|
|
**/
|
|
const struct passwd *
|
|
tor_getpwnam(const char *username)
|
|
{
|
|
struct passwd *pw;
|
|
|
|
if (username == NULL) {
|
|
tor_passwd_free(passwd_cached);
|
|
passwd_cached = NULL;
|
|
return NULL;
|
|
}
|
|
|
|
if ((pw = getpwnam(username))) {
|
|
tor_passwd_free(passwd_cached);
|
|
passwd_cached = tor_passwd_dup(pw);
|
|
log_info(LD_GENERAL, "Caching new entry %s for %s",
|
|
passwd_cached->pw_name, username);
|
|
return pw;
|
|
}
|
|
|
|
/* Lookup failed */
|
|
if (! passwd_cached || ! passwd_cached->pw_name)
|
|
return NULL;
|
|
|
|
if (! strcmp(username, passwd_cached->pw_name))
|
|
return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/** Wrapper around getpwnam() that can use cached result from
|
|
* tor_getpwnam(). Used so that we don't need to give the sandbox access to
|
|
* /etc/passwd.
|
|
*
|
|
* The following fields alone will definitely be copied in the output: pw_uid,
|
|
* pw_gid, pw_name, pw_dir. Other fields are not present in cached values.
|
|
*/
|
|
const struct passwd *
|
|
tor_getpwuid(uid_t uid)
|
|
{
|
|
struct passwd *pw;
|
|
|
|
if ((pw = getpwuid(uid))) {
|
|
return pw;
|
|
}
|
|
|
|
/* Lookup failed */
|
|
if (! passwd_cached)
|
|
return NULL;
|
|
|
|
if (uid == passwd_cached->pw_uid)
|
|
return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/** Allocate and return a string containing the home directory for the
|
|
* user <b>username</b>. Only works on posix-like systems. */
|
|
char *
|
|
get_user_homedir(const char *username)
|
|
{
|
|
const struct passwd *pw;
|
|
tor_assert(username);
|
|
|
|
if (!(pw = tor_getpwnam(username))) {
|
|
log_err(LD_CONFIG,"User \"%s\" not found.", username);
|
|
return NULL;
|
|
}
|
|
return tor_strdup(pw->pw_dir);
|
|
}
|
|
#endif /* !defined(_WIN32) */
|