123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- /* Copyright (c) 2003-2004, Roger Dingledine
- * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
- * Copyright (c) 2007-2019, The Tor Project, Inc. */
- /* See LICENSE for licensing information */
- /**
- * \file userdb.c
- *
- * \brief Access the POSIX user database.
- **/
- #include "lib/fs/userdb.h"
- #ifndef _WIN32
- #include "lib/malloc/malloc.h"
- #include "lib/log/log.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) */
|