|
@@ -1702,6 +1702,107 @@ log_credential_status(void)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+#ifndef _WIN32
|
|
|
+
|
|
|
+static struct passwd *passwd_cached = NULL;
|
|
|
+
|
|
|
+
|
|
|
+ *
|
|
|
+ * 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;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+static void
|
|
|
+tor_passwd_free(struct passwd *pw)
|
|
|
+{
|
|
|
+ if (!pw)
|
|
|
+ return;
|
|
|
+
|
|
|
+ tor_free(pw->pw_name);
|
|
|
+ tor_free(pw->pw_dir);
|
|
|
+ tor_free(pw);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * 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_notice(LD_GENERAL, "Caching new entry %s for %s",
|
|
|
+ passwd_cached->pw_name, username);
|
|
|
+ return pw;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (! passwd_cached || ! passwd_cached->pw_name)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (! strcmp(username, passwd_cached->pw_name))
|
|
|
+ return passwd_cached;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * 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;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (! passwd_cached)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (uid == passwd_cached->pw_uid)
|
|
|
+ return passwd_cached;
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
|
|
|
* primary group. Return 0 on success. On failure, log and return -1.
|
|
|
*/
|
|
@@ -1709,7 +1810,7 @@ int
|
|
|
switch_id(const char *user)
|
|
|
{
|
|
|
#ifndef _WIN32
|
|
|
- struct passwd *pw = NULL;
|
|
|
+ const struct passwd *pw = NULL;
|
|
|
uid_t old_uid;
|
|
|
gid_t old_gid;
|
|
|
static int have_already_switched_id = 0;
|
|
@@ -1730,7 +1831,7 @@ switch_id(const char *user)
|
|
|
old_gid = getgid();
|
|
|
|
|
|
|
|
|
- pw = getpwnam(user);
|
|
|
+ pw = tor_getpwnam(user);
|
|
|
if (pw == NULL) {
|
|
|
log_warn(LD_CONFIG, "Error setting configured user: %s not found", user);
|
|
|
return -1;
|
|
@@ -1901,10 +2002,10 @@ tor_disable_debugger_attach(void)
|
|
|
char *
|
|
|
get_user_homedir(const char *username)
|
|
|
{
|
|
|
- struct passwd *pw;
|
|
|
+ const struct passwd *pw;
|
|
|
tor_assert(username);
|
|
|
|
|
|
- if (!(pw = getpwnam(username))) {
|
|
|
+ if (!(pw = tor_getpwnam(username))) {
|
|
|
log_err(LD_CONFIG,"User \"%s\" not found.", username);
|
|
|
return NULL;
|
|
|
}
|