tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

userdb.c (3523B)


      1 /* Copyright (c) 2003-2004, Roger Dingledine
      2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      4 /* See LICENSE for licensing information */
      5 
      6 /**
      7 * \file userdb.c
      8 *
      9 * \brief Access the POSIX user database.
     10 **/
     11 
     12 #include "lib/fs/userdb.h"
     13 
     14 #ifndef _WIN32
     15 #include "lib/malloc/malloc.h"
     16 #include "lib/log/log.h"
     17 #include "lib/log/util_bug.h"
     18 
     19 #include <pwd.h>
     20 #include <stddef.h>
     21 #include <string.h>
     22 
     23 /** Cached struct from the last getpwname() call we did successfully. */
     24 static struct passwd *passwd_cached = NULL;
     25 
     26 /** Helper: copy a struct passwd object.
     27 *
     28 * We only copy the fields pw_uid, pw_gid, pw_name, pw_dir.  Tor doesn't use
     29 * any others, and I don't want to run into incompatibilities.
     30 */
     31 static struct passwd *
     32 tor_passwd_dup(const struct passwd *pw)
     33 {
     34  struct passwd *new_pw = tor_malloc_zero(sizeof(struct passwd));
     35  if (pw->pw_name)
     36    new_pw->pw_name = tor_strdup(pw->pw_name);
     37  if (pw->pw_dir)
     38    new_pw->pw_dir = tor_strdup(pw->pw_dir);
     39  new_pw->pw_uid = pw->pw_uid;
     40  new_pw->pw_gid = pw->pw_gid;
     41 
     42  return new_pw;
     43 }
     44 
     45 #define tor_passwd_free(pw) \
     46  FREE_AND_NULL(struct passwd, tor_passwd_free_, (pw))
     47 
     48 /** Helper: free one of our cached 'struct passwd' values. */
     49 static void
     50 tor_passwd_free_(struct passwd *pw)
     51 {
     52  if (!pw)
     53    return;
     54 
     55  tor_free(pw->pw_name);
     56  tor_free(pw->pw_dir);
     57  tor_free(pw);
     58 }
     59 
     60 /** Wrapper around getpwnam() that caches result. Used so that we don't need
     61 * to give the sandbox access to /etc/passwd.
     62 *
     63 * The following fields alone will definitely be copied in the output: pw_uid,
     64 * pw_gid, pw_name, pw_dir.  Other fields are not present in cached values.
     65 *
     66 * When called with a NULL argument, this function clears storage associated
     67 * with static variables it uses.
     68 **/
     69 const struct passwd *
     70 tor_getpwnam(const char *username)
     71 {
     72  struct passwd *pw;
     73 
     74  if (username == NULL) {
     75    tor_passwd_free(passwd_cached);
     76    passwd_cached = NULL;
     77    return NULL;
     78  }
     79 
     80  if ((pw = getpwnam(username))) {
     81    tor_passwd_free(passwd_cached);
     82    passwd_cached = tor_passwd_dup(pw);
     83    log_info(LD_GENERAL, "Caching new entry %s for %s",
     84             passwd_cached->pw_name, username);
     85    return pw;
     86  }
     87 
     88  /* Lookup failed */
     89  if (! passwd_cached || ! passwd_cached->pw_name)
     90    return NULL;
     91 
     92  if (! strcmp(username, passwd_cached->pw_name))
     93    return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky
     94 
     95  return NULL;
     96 }
     97 
     98 /** Wrapper around getpwnam() that can use cached result from
     99 * tor_getpwnam(). Used so that we don't need to give the sandbox access to
    100 * /etc/passwd.
    101 *
    102 * The following fields alone will definitely be copied in the output: pw_uid,
    103 * pw_gid, pw_name, pw_dir.  Other fields are not present in cached values.
    104 */
    105 const struct passwd *
    106 tor_getpwuid(uid_t uid)
    107 {
    108  struct passwd *pw;
    109 
    110  if ((pw = getpwuid(uid))) {
    111    return pw;
    112  }
    113 
    114  /* Lookup failed */
    115  if (! passwd_cached)
    116    return NULL;
    117 
    118  if (uid == passwd_cached->pw_uid)
    119    return passwd_cached; // LCOV_EXCL_LINE - would need to make getpwnam flaky
    120 
    121  return NULL;
    122 }
    123 
    124 /** Allocate and return a string containing the home directory for the
    125 * user <b>username</b>. Only works on posix-like systems. */
    126 char *
    127 get_user_homedir(const char *username)
    128 {
    129  const struct passwd *pw;
    130  tor_assert(username);
    131 
    132  if (!(pw = tor_getpwnam(username))) {
    133    log_err(LD_CONFIG,"User \"%s\" not found.", username);
    134    return NULL;
    135  }
    136  return tor_strdup(pw->pw_dir);
    137 }
    138 #endif /* !defined(_WIN32) */