Merge branch 'bug5105-v2-squashed'

Conflicts:
	src/or/transports.c
This commit is contained in:
Nick Mathewson 2012-02-17 11:50:10 -05:00
commit eaedcba493
5 changed files with 536 additions and 191 deletions

11
changes/bug5105 Normal file
View File

@ -0,0 +1,11 @@
o Minor bugfixes:
- Ensure that variables set in Tor's environment cannot override
environment variables which Tor tries to pass to a managed
pluggable-transport proxy. Previously, Tor would pass every
variable in its environment to managed proxies along with the
new ones, in such a way that on many operating systems, the
inherited environment variables would override those which Tor
tried to explicitly set. Bugfix on 0.2.3.12-alpha for most
Unixoid systems; bugfix on 0.2.3.9-alpha for Windows.

View File

@ -172,6 +172,35 @@ _tor_malloc_zero(size_t size DMALLOC_PARAMS)
return result; return result;
} }
/** Allocate a chunk of <b>nmemb</b>*<b>size</b> bytes of memory, fill
* the memory with zero bytes, and return a pointer to the result.
* Log and terminate the process on error. (Same as
* calloc(<b>nmemb</b>,<b>size</b>), but never returns NULL.)
*
* XXXX This implementation probably asserts in cases where it could
* work, because it only tries dividing SIZE_MAX by size (according to
* the calloc(3) man page, the size of an element of the nmemb-element
* array to be allocated), not by nmemb (which could in theory be
* smaller than size). Don't do that then.
*/
void *
_tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS)
{
/* You may ask yourself, "wouldn't it be smart to use calloc instead of
* malloc+memset? Perhaps libc's calloc knows some nifty optimization trick
* we don't!" Indeed it does, but its optimizations are only a big win when
* we're allocating something very big (it knows if it just got the memory
* from the OS in a pre-zeroed state). We don't want to use tor_malloc_zero
* for big stuff, so we don't bother with calloc. */
void *result;
size_t max_nmemb = (size == 0) ? SIZE_MAX : SIZE_MAX/size;
tor_assert(nmemb < max_nmemb);
result = _tor_malloc_zero((nmemb * size) DMALLOC_FN_ARGS);
return result;
}
/** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b> /** Change the size of the memory block pointed to by <b>ptr</b> to <b>size</b>
* bytes long; return the new memory block. On error, log and * bytes long; return the new memory block. On error, log and
* terminate. (Like realloc(ptr,size), but never returns NULL.) * terminate. (Like realloc(ptr,size), but never returns NULL.)
@ -3284,11 +3313,7 @@ process_handle_new(void)
*/ */
int int
tor_spawn_background(const char *const filename, const char **argv, tor_spawn_background(const char *const filename, const char **argv,
#ifdef _WIN32 process_environment_t *env,
LPVOID envp,
#else
const char **envp,
#endif
process_handle_t **process_handle_out) process_handle_t **process_handle_out)
{ {
#ifdef _WIN32 #ifdef _WIN32
@ -3305,8 +3330,6 @@ tor_spawn_background(const char *const filename, const char **argv,
SECURITY_ATTRIBUTES saAttr; SECURITY_ATTRIBUTES saAttr;
char *joined_argv; char *joined_argv;
(void)envp; // Unused on Windows
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE; saAttr.bInheritHandle = TRUE;
/* TODO: should we set explicit security attributes? (#2046, comment 5) */ /* TODO: should we set explicit security attributes? (#2046, comment 5) */
@ -3371,7 +3394,7 @@ tor_spawn_background(const char *const filename, const char **argv,
/*(TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess() /*(TODO: set CREATE_NEW CONSOLE/PROCESS_GROUP to make GetExitCodeProcess()
* work?) */ * work?) */
0, // creation flags 0, // creation flags
envp, // use parent's environment (env==NULL) ? NULL : env->windows_environment_block,
NULL, // use parent's current directory NULL, // use parent's current directory
&siStartInfo, // STARTUPINFO pointer &siStartInfo, // STARTUPINFO pointer
&(process_handle->pid)); // receives PROCESS_INFORMATION &(process_handle->pid)); // receives PROCESS_INFORMATION
@ -3501,8 +3524,8 @@ tor_spawn_background(const char *const filename, const char **argv,
/* Call the requested program. We need the cast because /* Call the requested program. We need the cast because
execvp doesn't define argv as const, even though it execvp doesn't define argv as const, even though it
does not modify the arguments */ does not modify the arguments */
if (envp) if (env)
execve(filename, (char *const *) argv, (char*const*)envp); execve(filename, (char *const *) argv, env->unixoid_environment_block);
else else
execvp(filename, (char *const *) argv); execvp(filename, (char *const *) argv);
@ -3692,6 +3715,162 @@ tor_get_exit_code(const process_handle_t *process_handle,
return PROCESS_EXIT_EXITED; return PROCESS_EXIT_EXITED;
} }
/** Return non-zero iff getenv would consider <b>s1</b> and <b>s2</b>
* to have the same name as strings in a process's environment. */
int
environment_variable_names_equal(const char *s1, const char *s2)
{
size_t s1_name_len = strcspn(s1, "=");
size_t s2_name_len = strcspn(s2, "=");
return (s1_name_len == s2_name_len &&
tor_memeq(s1, s2, s1_name_len));
}
/** Free <b>env</b> (assuming it was produced by
* process_environment_make). */
void
process_environment_free(process_environment_t *env)
{
if (env == NULL) return;
/* As both an optimization hack to reduce consing on Unixoid systems
* and a nice way to ensure that some otherwise-Windows-specific
* code will always get tested before changes to it get merged, the
* strings which env->unixoid_environment_block points to are packed
* into env->windows_environment_block. */
tor_free(env->unixoid_environment_block);
tor_free(env->windows_environment_block);
tor_free(env);
}
/** Make a process_environment_t containing the environment variables
* specified in <b>env_vars</b> (as C strings of the form
* "NAME=VALUE"). */
process_environment_t *
process_environment_make(struct smartlist_t *env_vars)
{
process_environment_t *env = tor_malloc_zero(sizeof(process_environment_t));
size_t n_env_vars = smartlist_len(env_vars);
size_t i;
size_t total_env_length;
smartlist_t *env_vars_sorted;
tor_assert(n_env_vars + 1 != 0);
env->unixoid_environment_block = tor_calloc(n_env_vars + 1, sizeof(char *));
/* env->unixoid_environment_block is already NULL-terminated,
* because we assume that NULL == 0 (and check that during compilation). */
total_env_length = 1; /* terminating NUL of terminating empty string */
for (i = 0; i < n_env_vars; ++i) {
const char *s = smartlist_get(env_vars, i);
size_t slen = strlen(s);
tor_assert(slen + 1 != 0);
tor_assert(slen + 1 < SIZE_MAX - total_env_length);
total_env_length += slen + 1;
}
env->windows_environment_block = tor_malloc_zero(total_env_length);
/* env->windows_environment_block is already
* (NUL-terminated-empty-string)-terminated. */
/* Some versions of Windows supposedly require that environment
* blocks be sorted. Or maybe some Windows programs (or their
* runtime libraries) fail to look up strings in non-sorted
* environment blocks.
*
* Also, sorting strings makes it easy to find duplicate environment
* variables and environment-variable strings without an '=' on all
* OSes, and they can cause badness. Let's complain about those. */
env_vars_sorted = smartlist_new();
smartlist_add_all(env_vars_sorted, env_vars);
smartlist_sort_strings(env_vars_sorted);
/* Now copy the strings into the environment blocks. */
{
char *cp = env->windows_environment_block;
const char *prev_env_var = NULL;
for (i = 0; i < n_env_vars; ++i) {
const char *s = smartlist_get(env_vars_sorted, i);
size_t slen = strlen(s);
size_t s_name_len = strcspn(s, "=");
if (s_name_len == slen) {
log_warn(LD_GENERAL,
"Preparing an environment containing a variable "
"without a value: %s",
s);
}
if (prev_env_var != NULL &&
environment_variable_names_equal(s, prev_env_var)) {
log_warn(LD_GENERAL,
"Preparing an environment containing two variables "
"with the same name: %s and %s",
prev_env_var, s);
}
prev_env_var = s;
/* Actually copy the string into the environment. */
memcpy(cp, s, slen+1);
env->unixoid_environment_block[i] = cp;
cp += slen+1;
}
tor_assert(cp == env->windows_environment_block + total_env_length - 1);
}
return env;
}
/** Return a newly allocated smartlist containing every variable in
* this process's environment, as a NUL-terminated string of the form
* "NAME=VALUE". Note that on some/many/most/all OSes, the parent
* process can put strings not of that form in our environment;
* callers should try to not get crashed by that.
*
* The returned strings are heap-allocated, and must be freed by the
* caller. */
struct smartlist_t *
get_current_process_environment_variables(void)
{
smartlist_t *sl = smartlist_new();
char **environ_tmp; /* Not const char ** ? Really? */
for (environ_tmp = environ; *environ_tmp; ++environ_tmp) {
smartlist_add(sl, tor_strdup(*environ_tmp));
}
return sl;
}
/** For each string s in <b>env_vars</b> such that
* environment_variable_names_equal(s, <b>new_var</b>), remove it; if
* <b>free_p</b> is non-zero, call <b>free_old</b>(s). If
* <b>new_var</b> contains '=', insert it into <b>env_vars</b>. */
void
set_environment_variable_in_smartlist(struct smartlist_t *env_vars,
const char *new_var,
void (*free_old)(void*),
int free_p)
{
SMARTLIST_FOREACH_BEGIN(env_vars, const char *, s) {
if (environment_variable_names_equal(s, new_var)) {
SMARTLIST_DEL_CURRENT(env_vars, s);
if (free_p) {
free_old((void *)s);
}
}
} SMARTLIST_FOREACH_END(s);
if (strchr(new_var, '=') != NULL) {
smartlist_add(env_vars, (void *)new_var);
}
}
#ifdef _WIN32 #ifdef _WIN32
/** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If /** Read from a handle <b>h</b> into <b>buf</b>, up to <b>count</b> bytes. If
* <b>hProcess</b> is NULL, the function will return immediately if there is * <b>hProcess</b> is NULL, the function will return immediately if there is

View File

@ -73,6 +73,7 @@
void *_tor_malloc(size_t size DMALLOC_PARAMS) ATTR_MALLOC; void *_tor_malloc(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
void *_tor_malloc_zero(size_t size DMALLOC_PARAMS) ATTR_MALLOC; void *_tor_malloc_zero(size_t size DMALLOC_PARAMS) ATTR_MALLOC;
void *_tor_malloc_roundup(size_t *size DMALLOC_PARAMS) ATTR_MALLOC; void *_tor_malloc_roundup(size_t *size DMALLOC_PARAMS) ATTR_MALLOC;
void *_tor_calloc(size_t nmemb, size_t size DMALLOC_PARAMS) ATTR_MALLOC;
void *_tor_realloc(void *ptr, size_t size DMALLOC_PARAMS); void *_tor_realloc(void *ptr, size_t size DMALLOC_PARAMS);
char *_tor_strdup(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1)); char *_tor_strdup(const char *s DMALLOC_PARAMS) ATTR_MALLOC ATTR_NONNULL((1));
char *_tor_strndup(const char *s, size_t n DMALLOC_PARAMS) char *_tor_strndup(const char *s, size_t n DMALLOC_PARAMS)
@ -107,6 +108,7 @@ extern int dmalloc_free(const char *file, const int line, void *pnt,
#define tor_malloc(size) _tor_malloc(size DMALLOC_ARGS) #define tor_malloc(size) _tor_malloc(size DMALLOC_ARGS)
#define tor_malloc_zero(size) _tor_malloc_zero(size DMALLOC_ARGS) #define tor_malloc_zero(size) _tor_malloc_zero(size DMALLOC_ARGS)
#define tor_calloc(nmemb,size) _tor_calloc(nmemb, size DMALLOC_ARGS)
#define tor_malloc_roundup(szp) _tor_malloc_roundup(szp DMALLOC_ARGS) #define tor_malloc_roundup(szp) _tor_malloc_roundup(szp DMALLOC_ARGS)
#define tor_realloc(ptr, size) _tor_realloc(ptr, size DMALLOC_ARGS) #define tor_realloc(ptr, size) _tor_realloc(ptr, size DMALLOC_ARGS)
#define tor_strdup(s) _tor_strdup(s DMALLOC_ARGS) #define tor_strdup(s) _tor_strdup(s DMALLOC_ARGS)
@ -363,12 +365,9 @@ void tor_check_port_forwarding(const char *filename,
int dir_port, int or_port, time_t now); int dir_port, int or_port, time_t now);
typedef struct process_handle_t process_handle_t; typedef struct process_handle_t process_handle_t;
typedef struct process_environment_t process_environment_t;
int tor_spawn_background(const char *const filename, const char **argv, int tor_spawn_background(const char *const filename, const char **argv,
#ifdef _WIN32 process_environment_t *env,
LPVOID envp,
#else
const char **envp,
#endif
process_handle_t **process_handle_out); process_handle_t **process_handle_out);
#define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code " #define SPAWN_ERROR_MESSAGE "ERR: Failed to spawn background process - code "
@ -377,6 +376,27 @@ int tor_spawn_background(const char *const filename, const char **argv,
HANDLE load_windows_system_library(const TCHAR *library_name); HANDLE load_windows_system_library(const TCHAR *library_name);
#endif #endif
int environment_variable_names_equal(const char *s1, const char *s2);
struct process_environment_t {
/** A pointer to a sorted empty-string-terminated sequence of
* NUL-terminated strings of the form "NAME=VALUE". */
char *windows_environment_block;
/** A pointer to a NULL-terminated array of pointers to
* NUL-terminated strings of the form "NAME=VALUE". */
char **unixoid_environment_block;
};
process_environment_t *process_environment_make(struct smartlist_t *env_vars);
void process_environment_free(process_environment_t *env);
struct smartlist_t *get_current_process_environment_variables(void);
void set_environment_variable_in_smartlist(struct smartlist_t *env_vars,
const char *new_var,
void (*free_old)(void*),
int free_p);
/* Values of process_handle_t.status. PROCESS_STATUS_NOTRUNNING must be /* Values of process_handle_t.status. PROCESS_STATUS_NOTRUNNING must be
* 0 because tor_check_port_forwarding depends on this being the initial * 0 because tor_check_port_forwarding depends on this being the initial
* statue of the static instance of process_handle_t */ * statue of the static instance of process_handle_t */

View File

@ -91,13 +91,8 @@
#include "util.h" #include "util.h"
#include "router.h" #include "router.h"
#ifdef _WIN32 static process_environment_t *
static void set_managed_proxy_environment(LPVOID *envp, create_managed_proxy_environment(const managed_proxy_t *mp);
const managed_proxy_t *mp);
#else
static void set_managed_proxy_environment(char ***envp,
const managed_proxy_t *mp);
#endif
static INLINE int proxy_configuration_finished(const managed_proxy_t *mp); static INLINE int proxy_configuration_finished(const managed_proxy_t *mp);
@ -287,35 +282,23 @@ launch_managed_proxy(managed_proxy_t *mp)
{ {
int retval; int retval;
process_environment_t *env = create_managed_proxy_environment(mp);
#ifdef _WIN32 #ifdef _WIN32
LPVOID envp=NULL;
set_managed_proxy_environment(&envp, mp);
tor_assert(envp);
/* Passing NULL as lpApplicationName makes Windows search for the .exe */ /* Passing NULL as lpApplicationName makes Windows search for the .exe */
retval = tor_spawn_background(NULL, (const char **)mp->argv, envp, retval = tor_spawn_background(NULL,
(const char **)mp->argv,
env,
&mp->process_handle); &mp->process_handle);
tor_free(envp);
#else #else
retval = tor_spawn_background(mp->argv[0],
char **envp=NULL; (const char **)mp->argv,
env,
/* prepare the environment variables for the managed proxy */ &mp->process_handle);
set_managed_proxy_environment(&envp, mp);
tor_assert(envp);
retval = tor_spawn_background(mp->argv[0], (const char **)mp->argv,
(const char **)envp, &mp->process_handle);
/* free the memory allocated by set_managed_proxy_environment(). */
free_execve_args(envp);
#endif #endif
process_environment_free(env);
if (retval == PROCESS_STATUS_ERROR) { if (retval == PROCESS_STATUS_ERROR) {
log_warn(LD_GENERAL, "Managed proxy at '%s' failed at launch.", log_warn(LD_GENERAL, "Managed proxy at '%s' failed at launch.",
mp->argv[0]); mp->argv[0]);
@ -969,170 +952,80 @@ get_bindaddr_for_server_proxy(const managed_proxy_t *mp)
return bindaddr_result; return bindaddr_result;
} }
#ifdef _WIN32 /** Return a newly allocated process_environment_t * for <b>mp</b>'s
* process. */
/** Prepare the environment <b>envp</b> of managed proxy <b>mp</b>. static process_environment_t *
* <b>envp</b> is allocated on the heap and should be freed by the create_managed_proxy_environment(const managed_proxy_t *mp)
* caller after its use. */
static void
set_managed_proxy_environment(LPVOID *envp, const managed_proxy_t *mp)
{ {
const or_options_t *options = get_options(); const or_options_t *options = get_options();
char *tmp=NULL; /* Environment variables to be added to or set in mp's environment. */
char *state_tmp=NULL;
char *state_env=NULL;
char *transports_to_launch=NULL;
char *transports_env=NULL;
char *bindaddr_tmp=NULL;
char *bindaddr_env=NULL;
char *orport_env=NULL;
char version_env[31]; /* XXX temp */
char extended_env[43]; /* XXX temp */
int env_size = 0;
/* A smartlist carrying all the env. variables that the managed
proxy should inherit. */
smartlist_t *envs = smartlist_new(); smartlist_t *envs = smartlist_new();
/* XXXX The next time someone touches this code, shorten the name of
* set_environment_variable_in_smartlist, add a
* set_env_var_in_smartlist_asprintf function, and get rid of the
* silly extra envs smartlist. */
/* Copy the whole environment of the Tor process. /* The final environment to be passed to mp. */
It should also copy PATH and HOME of the Tor process.*/ smartlist_t *merged_env_vars = get_current_process_environment_variables();
char **environ_tmp = environ;
while (*environ_tmp)
smartlist_add(envs, *environ_tmp++);
/* Create the TOR_PT_* environment variables. */ process_environment_t *env;
state_tmp = get_datadir_fname("pt_state/"); /* XXX temp */
tor_asprintf(&state_env, "TOR_PT_STATE_LOCATION=%s", state_tmp);
strcpy(version_env, "TOR_PT_MANAGED_TRANSPORT_VER=1"); {
char *state_tmp = get_datadir_fname("pt_state/"); /* XXX temp */
transports_to_launch = smartlist_add_asprintf(envs, "TOR_PT_STATE_LOCATION=%s", state_tmp);
smartlist_join_strings(mp->transports_to_launch, ",", 0, NULL); tor_free(state_tmp);
tor_asprintf(&transports_env,
mp->is_server ?
"TOR_PT_SERVER_TRANSPORTS=%s" : "TOR_PT_CLIENT_TRANSPORTS=%s",
transports_to_launch);
smartlist_add(envs, state_env);
smartlist_add(envs, version_env);
smartlist_add(envs, transports_env);
if (mp->is_server) {
tor_asprintf(&orport_env, "TOR_PT_ORPORT=127.0.0.1:%s",
options->ORPort->value);
bindaddr_tmp = get_bindaddr_for_server_proxy(mp);
tor_asprintf(&bindaddr_env, "TOR_PT_SERVER_BINDADDR=%s", bindaddr_tmp);
strlcpy(extended_env, "TOR_PT_EXTENDED_SERVER_PORT=",
sizeof(extended_env));
smartlist_add(envs, orport_env);
smartlist_add(envs, extended_env);
smartlist_add(envs, bindaddr_env);
} }
/* It seems like some versions of Windows need a sorted lpEnvironment smartlist_add(envs, tor_strdup("TOR_PT_MANAGED_TRANSPORT_VER=1"));
block. */
smartlist_sort_strings(envs);
/* An environment block consists of a null-terminated block of {
null-terminated strings: */ char *transports_to_launch =
smartlist_join_strings(mp->transports_to_launch, ",", 0, NULL);
/* Calculate the block's size. */ smartlist_add_asprintf(envs,
SMARTLIST_FOREACH(envs, const char *, s, mp->is_server ?
env_size += strlen(s) + 1); "TOR_PT_SERVER_TRANSPORTS=%s" :
env_size += 1; /* space for last NUL */ "TOR_PT_CLIENT_TRANSPORTS=%s",
transports_to_launch);
*envp = tor_malloc(env_size); tor_free(transports_to_launch);
tmp = *envp; }
/* Create the block. */ if (mp->is_server) {
SMARTLIST_FOREACH_BEGIN(envs, const char *, s) { smartlist_add_asprintf(envs, "TOR_PT_ORPORT=127.0.0.1:%s",
memcpy(tmp, s, strlen(s)); /* copy the env. variable string */ options->ORPort->value);
tmp += strlen(s);
memset(tmp, '\0', 1); /* append NUL at the end of the string */
tmp += 1;
} SMARTLIST_FOREACH_END(s);
memset(tmp, '\0', 1); /* last NUL */
/* Finally, free the whole mess. */ {
tor_free(state_tmp); char *bindaddr_tmp = get_bindaddr_for_server_proxy(mp);
tor_free(state_env); smartlist_add_asprintf(envs, "TOR_PT_SERVER_BINDADDR=%s", bindaddr_tmp);
tor_free(transports_to_launch); tor_free(bindaddr_tmp);
tor_free(transports_env); }
tor_free(bindaddr_tmp);
tor_free(bindaddr_env); /* XXX023 Remove the '=' here once versions of obfsproxy which
tor_free(orport_env); * assert that this env var exists are sufficiently dead.
*
* (If we remove this line entirely, some joker will stick this
* variable in Tor's environment and crash PTs that try to parse
* it even when not run in server mode.) */
smartlist_add(envs, tor_strdup("TOR_PT_EXTENDED_SERVER_PORT="));
}
SMARTLIST_FOREACH_BEGIN(envs, const char *, env_var) {
set_environment_variable_in_smartlist(merged_env_vars, env_var,
_tor_free, 1);
} SMARTLIST_FOREACH_END(env_var);
env = process_environment_make(merged_env_vars);
smartlist_free(envs); smartlist_free(envs);
SMARTLIST_FOREACH(merged_env_vars, void *, x, tor_free(x));
smartlist_free(merged_env_vars);
return env;
} }
#else /* _WIN32 */
/** Prepare the environment <b>envp</b> of managed proxy <b>mp</b>.
* <b>envp</b> is allocated on the heap and should be freed by the
* caller after its use. */
static void
set_managed_proxy_environment(char ***envp, const managed_proxy_t *mp)
{
const or_options_t *options = get_options();
char **tmp=NULL;
char *state_loc=NULL;
char *transports_to_launch=NULL;
char *bindaddr=NULL;
int environ_size=0;
char **environ_tmp = get_environment();
char **environ_save = environ_tmp;
int n_envs = mp->is_server ? ENVIRON_SIZE_SERVER : ENVIRON_SIZE_CLIENT;
while (*environ_tmp) {
environ_size++;
environ_tmp++;
}
environ_tmp = environ_save;
/* allocate enough space for our env. vars and a NULL pointer */
*envp = tor_malloc(sizeof(char*)*(environ_size+n_envs+1));
tmp = *envp;
state_loc = get_datadir_fname("pt_state/"); /* XXX temp */
transports_to_launch =
smartlist_join_strings(mp->transports_to_launch, ",", 0, NULL);
while (*environ_tmp) {
*tmp = tor_strdup(*environ_tmp);
tmp++, environ_tmp++;
}
tor_asprintf(tmp++, "TOR_PT_STATE_LOCATION=%s", state_loc);
tor_asprintf(tmp++, "TOR_PT_MANAGED_TRANSPORT_VER=1"); /* temp */
if (mp->is_server) {
bindaddr = get_bindaddr_for_server_proxy(mp);
/* XXX temp */
tor_asprintf(tmp++, "TOR_PT_ORPORT=127.0.0.1:%d",
router_get_advertised_or_port(options));
tor_asprintf(tmp++, "TOR_PT_SERVER_BINDADDR=%s", bindaddr);
tor_asprintf(tmp++, "TOR_PT_SERVER_TRANSPORTS=%s", transports_to_launch);
tor_asprintf(tmp++, "TOR_PT_EXTENDED_SERVER_PORT=");
} else {
tor_asprintf(tmp++, "TOR_PT_CLIENT_TRANSPORTS=%s", transports_to_launch);
}
*tmp = NULL;
tor_free(state_loc);
tor_free(transports_to_launch);
tor_free(bindaddr);
}
#endif /* _WIN32 */
/** Create and return a new managed proxy for <b>transport</b> using /** Create and return a new managed proxy for <b>transport</b> using
* <b>proxy_argv</b>. If <b>is_server</b> is true, it's a server * <b>proxy_argv</b>. If <b>is_server</b> is true, it's a server
* managed proxy. */ * managed proxy. */

View File

@ -1856,6 +1856,245 @@ test_util_eat_whitespace(void *ptr)
; ;
} }
/** Return a newly allocated smartlist containing the lines of text in
* <b>lines</b>. The returned strings are heap-allocated, and must be
* freed by the caller.
*
* XXXX? Move to container.[hc] ? */
static smartlist_t *
smartlist_new_from_text_lines(const char *lines)
{
smartlist_t *sl = smartlist_new();
char *last_line;
smartlist_split_string(sl, lines, "\n", 0, 0);
last_line = smartlist_pop_last(sl);
if (last_line != NULL && *last_line != '\0') {
smartlist_add(sl, last_line);
}
return sl;
}
/** Test smartlist_new_from_text_lines */
static void
test_util_sl_new_from_text_lines(void *ptr)
{
(void)ptr;
{ /* Normal usage */
smartlist_t *sl = smartlist_new_from_text_lines("foo\nbar\nbaz\n");
int sl_len = smartlist_len(sl);
tt_want_int_op(sl_len, ==, 3);
if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo");
if (sl_len > 1) tt_want_str_op(smartlist_get(sl, 1), ==, "bar");
if (sl_len > 2) tt_want_str_op(smartlist_get(sl, 2), ==, "baz");
SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
smartlist_free(sl);
}
{ /* No final newline */
smartlist_t *sl = smartlist_new_from_text_lines("foo\nbar\nbaz");
int sl_len = smartlist_len(sl);
tt_want_int_op(sl_len, ==, 3);
if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo");
if (sl_len > 1) tt_want_str_op(smartlist_get(sl, 1), ==, "bar");
if (sl_len > 2) tt_want_str_op(smartlist_get(sl, 2), ==, "baz");
SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
smartlist_free(sl);
}
{ /* No newlines */
smartlist_t *sl = smartlist_new_from_text_lines("foo");
int sl_len = smartlist_len(sl);
tt_want_int_op(sl_len, ==, 1);
if (sl_len > 0) tt_want_str_op(smartlist_get(sl, 0), ==, "foo");
SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
smartlist_free(sl);
}
{ /* No text at all */
smartlist_t *sl = smartlist_new_from_text_lines("");
int sl_len = smartlist_len(sl);
tt_want_int_op(sl_len, ==, 0);
SMARTLIST_FOREACH(sl, void *, x, tor_free(x));
smartlist_free(sl);
}
}
/** Test process_environment_make */
static void
test_util_make_environment(void *ptr)
{
const char *env_vars_string =
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\n"
"HOME=/home/foozer\n";
const char expected_windows_env_block[] =
"HOME=/home/foozer\000"
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\000"
"\000";
size_t expected_windows_env_block_len = sizeof(expected_windows_env_block);
smartlist_t *env_vars = smartlist_new_from_text_lines(env_vars_string);
smartlist_t *env_vars_sorted = smartlist_new();
smartlist_t *env_vars_in_unixoid_env_block_sorted = smartlist_new();
process_environment_t *env;
(void)ptr;
env = process_environment_make(env_vars);
/* Check that the Windows environment block is correct. */
tt_want(tor_memeq(expected_windows_env_block, env->windows_environment_block,
expected_windows_env_block_len));
/* Now for the Unixoid environment block. We don't care which order
* these environment variables are in, so we sort both lists first. */
smartlist_add_all(env_vars_sorted, env_vars);
{
char **v;
for (v = env->unixoid_environment_block; *v; ++v) {
smartlist_add(env_vars_in_unixoid_env_block_sorted, *v);
}
}
smartlist_sort_strings(env_vars_sorted);
smartlist_sort_strings(env_vars_in_unixoid_env_block_sorted);
tt_want_int_op(smartlist_len(env_vars_sorted), ==,
smartlist_len(env_vars_in_unixoid_env_block_sorted));
{
int len = smartlist_len(env_vars_sorted);
int i;
if (smartlist_len(env_vars_in_unixoid_env_block_sorted) < len) {
len = smartlist_len(env_vars_in_unixoid_env_block_sorted);
}
for (i = 0; i < len; ++i) {
tt_want_str_op(smartlist_get(env_vars_sorted, i), ==,
smartlist_get(env_vars_in_unixoid_env_block_sorted, i));
}
}
/* Clean up. */
smartlist_free(env_vars_in_unixoid_env_block_sorted);
smartlist_free(env_vars_sorted);
SMARTLIST_FOREACH(env_vars, char *, x, tor_free(x));
smartlist_free(env_vars);
process_environment_free(env);
}
/** Test set_environment_variable_in_smartlist */
static void
test_util_set_env_var_in_sl(void *ptr)
{
/* The environment variables in these strings are in arbitrary
* order; we sort the resulting lists before comparing them.
*
* (They *will not* end up in the order shown in
* expected_resulting_env_vars_string.) */
const char *base_env_vars_string =
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\n"
"HOME=/home/foozer\n"
"TERM=xterm\n"
"SHELL=/bin/ksh\n"
"USER=foozer\n"
"LOGNAME=foozer\n"
"USERNAME=foozer\n"
"LANG=en_US.utf8\n"
;
const char *new_env_vars_string =
"TERM=putty\n"
"DISPLAY=:18.0\n"
;
const char *expected_resulting_env_vars_string =
"PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/bin\n"
"HOME=/home/foozer\n"
"TERM=putty\n"
"SHELL=/bin/ksh\n"
"USER=foozer\n"
"LOGNAME=foozer\n"
"USERNAME=foozer\n"
"LANG=en_US.utf8\n"
"DISPLAY=:18.0\n"
;
smartlist_t *merged_env_vars =
smartlist_new_from_text_lines(base_env_vars_string);
smartlist_t *new_env_vars =
smartlist_new_from_text_lines(new_env_vars_string);
smartlist_t *expected_resulting_env_vars =
smartlist_new_from_text_lines(expected_resulting_env_vars_string);
/* Elements of merged_env_vars are heap-allocated, and must be
* freed. Some of them are (or should) be freed by
* set_environment_variable_in_smartlist.
*
* Elements of new_env_vars are heap-allocated, but are copied into
* merged_env_vars, so they are not freed separately at the end of
* the function.
*
* Elements of expected_resulting_env_vars are heap-allocated, and
* must be freed. */
(void)ptr;
SMARTLIST_FOREACH(new_env_vars, char *, env_var,
set_environment_variable_in_smartlist(merged_env_vars,
env_var,
_tor_free,
1));
smartlist_sort_strings(merged_env_vars);
smartlist_sort_strings(expected_resulting_env_vars);
tt_want_int_op(smartlist_len(merged_env_vars), ==,
smartlist_len(expected_resulting_env_vars));
{
int len = smartlist_len(merged_env_vars);
int i;
if (smartlist_len(expected_resulting_env_vars) < len) {
len = smartlist_len(expected_resulting_env_vars);
}
for (i = 0; i < len; ++i) {
tt_want_str_op(smartlist_get(merged_env_vars, i), ==,
smartlist_get(expected_resulting_env_vars, i));
}
}
/* Clean up. */
SMARTLIST_FOREACH(merged_env_vars, char *, x, tor_free(x));
smartlist_free(merged_env_vars);
smartlist_free(new_env_vars);
SMARTLIST_FOREACH(expected_resulting_env_vars, char *, x, tor_free(x));
smartlist_free(expected_resulting_env_vars);
}
#define UTIL_LEGACY(name) \ #define UTIL_LEGACY(name) \
{ #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name } { #name, legacy_test_helper, 0, &legacy_setup, test_util_ ## name }
@ -1895,6 +2134,9 @@ struct testcase_t util_tests[] = {
UTIL_TEST(split_lines, 0), UTIL_TEST(split_lines, 0),
UTIL_TEST(n_bits_set, 0), UTIL_TEST(n_bits_set, 0),
UTIL_TEST(eat_whitespace, 0), UTIL_TEST(eat_whitespace, 0),
UTIL_TEST(sl_new_from_text_lines, 0),
UTIL_TEST(make_environment, 0),
UTIL_TEST(set_env_var_in_sl, 0),
END_OF_TESTCASES END_OF_TESTCASES
}; };