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) */