tor

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

test_options_act.c (9206B)


      1 /* Copyright (c) 2001-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 #define CONFIG_PRIVATE
      7 #include "core/or/or.h"
      8 #include "app/config/config.h"
      9 #include "lib/encoding/confline.h"
     10 
     11 #include "test/test.h"
     12 #include "test/log_test_helpers.h"
     13 #include "test/test_helpers.h"
     14 
     15 #ifndef _WIN32
     16 #include <sys/stat.h>
     17 
     18 /**
     19 * Check whether fname is readable. On success set
     20 * *<b>is_group_readable_out</b> to as appropriate and return 0. On failure
     21 * return -1.
     22 */
     23 static int
     24 get_file_mode(const char *fname, unsigned *permissions_out)
     25 {
     26  struct stat st;
     27  int r = stat(fname, &st);
     28  if (r < 0)
     29    return -1;
     30  *permissions_out = (unsigned) st.st_mode;
     31  return 0;
     32 }
     33 #define assert_mode(fn,mask,expected) STMT_BEGIN                 \
     34  unsigned mode_;                                                \
     35  int tmp_ = get_file_mode((fn), &mode_);                        \
     36  if (tmp_ < 0) {                                                \
     37    TT_DIE(("Couldn't stat %s: %s", (fn), strerror(errno)));     \
     38  }                                                              \
     39  if ((mode_ & (mask)) != (expected)) {                          \
     40    TT_DIE(("Bad mode %o on %s", mode_, (fn)));                  \
     41  }                                                              \
     42  STMT_END
     43 #else /* defined(_WIN32) */
     44 /* "group-readable" isn't meaningful on windows */
     45 #define assert_mode(fn,mask,expected) STMT_NIL
     46 #endif /* !defined(_WIN32) */
     47 
     48 static or_options_t *mock_opts;
     49 static const or_options_t *
     50 mock_get_options(void)
     51 {
     52  return mock_opts;
     53 }
     54 
     55 static void
     56 test_options_act_create_dirs(void *arg)
     57 {
     58  (void)arg;
     59  MOCK(get_options, mock_get_options);
     60  char *msg = NULL;
     61  or_options_t *opts = mock_opts = options_new();
     62 
     63  /* We're testing options_create_directories(), which assumes that
     64     validate_data_directories() has already been called, and all of
     65     KeyDirectory, DataDirectory, and CacheDirectory are set. */
     66 
     67  /* Success case 1: all directories are the default */
     68  char *fn;
     69  fn = tor_strdup(get_fname_rnd("ddir"));
     70  opts->DataDirectory = tor_strdup(fn);
     71  opts->CacheDirectory = tor_strdup(fn);
     72  tor_asprintf(&opts->KeyDirectory, "%s/keys", fn);
     73  opts->DataDirectoryGroupReadable = 1;
     74  opts->CacheDirectoryGroupReadable = -1; /* default. */
     75  int r = options_create_directories(&msg);
     76  tt_int_op(r, OP_EQ, 0);
     77  tt_ptr_op(msg, OP_EQ, NULL);
     78  tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
     79  tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
     80  tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
     81  assert_mode(opts->DataDirectory, 0777, 0750);
     82  assert_mode(opts->KeyDirectory, 0777, 0700);
     83  tor_free(fn);
     84  tor_free(opts->KeyDirectory);
     85  or_options_free(opts);
     86 
     87  /* Success case 2: all directories are different. */
     88  opts = mock_opts = options_new();
     89  opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
     90  opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
     91  opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
     92  opts->CacheDirectoryGroupReadable = 1; // cache directory group readable
     93  r = options_create_directories(&msg);
     94  tt_int_op(r, OP_EQ, 0);
     95  tt_ptr_op(msg, OP_EQ, NULL);
     96  tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
     97  tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
     98  tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
     99  assert_mode(opts->DataDirectory, 0777, 0700);
    100  assert_mode(opts->KeyDirectory, 0777, 0700);
    101  assert_mode(opts->CacheDirectory, 0777, 0750);
    102  tor_free(fn);
    103  or_options_free(opts);
    104 
    105  /* Success case 3: all directories are the same. */
    106  opts = mock_opts = options_new();
    107  fn = tor_strdup(get_fname_rnd("ddir"));
    108  opts->DataDirectory = tor_strdup(fn);
    109  opts->CacheDirectory = tor_strdup(fn);
    110  opts->KeyDirectory = tor_strdup(fn);
    111  opts->DataDirectoryGroupReadable = 1;
    112  opts->CacheDirectoryGroupReadable = -1; /* default. */
    113  opts->KeyDirectoryGroupReadable = -1; /* default */
    114  r = options_create_directories(&msg);
    115  tt_int_op(r, OP_EQ, 0);
    116  tt_ptr_op(msg, OP_EQ, NULL);
    117  tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
    118  tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
    119  tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
    120  assert_mode(opts->DataDirectory, 0777, 0750);
    121  assert_mode(opts->KeyDirectory, 0777, 0750);
    122  assert_mode(opts->CacheDirectory, 0777, 0750);
    123  tor_free(fn);
    124  or_options_free(opts);
    125 
    126  /* Failure case 1: Can't make datadir. */
    127  opts = mock_opts = options_new();
    128  opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
    129  opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
    130  opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
    131  write_str_to_file(opts->DataDirectory, "foo", 0);
    132  r = options_create_directories(&msg);
    133  tt_int_op(r, OP_LT, 0);
    134  tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
    135  or_options_free(opts);
    136  tor_free(msg);
    137 
    138  /* Failure case 2: Can't make keydir. */
    139  opts = mock_opts = options_new();
    140  opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
    141  opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
    142  opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
    143  write_str_to_file(opts->KeyDirectory, "foo", 0);
    144  r = options_create_directories(&msg);
    145  tt_int_op(r, OP_LT, 0);
    146  tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
    147  or_options_free(opts);
    148  tor_free(msg);
    149 
    150  /* Failure case 3: Can't make cachedir. */
    151  opts = mock_opts = options_new();
    152  opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
    153  opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
    154  opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
    155  write_str_to_file(opts->CacheDirectory, "foo", 0);
    156  r = options_create_directories(&msg);
    157  tt_int_op(r, OP_LT, 0);
    158  tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
    159  tor_free(fn);
    160  or_options_free(opts);
    161  tor_free(msg);
    162 
    163 done:
    164  UNMOCK(get_options);
    165  or_options_free(opts);
    166  mock_opts = NULL;
    167  tor_free(fn);
    168  tor_free(msg);
    169 }
    170 
    171 static void
    172 test_options_act_log_transition(void *arg)
    173 {
    174  (void)arg;
    175  or_options_t *opts = mock_opts = options_new();
    176  or_options_t *old_opts = NULL;
    177  opts->LogTimeGranularity = 1000;
    178  opts->SafeLogging_ = SAFELOG_SCRUB_ALL;
    179  struct log_transaction_t *lt = NULL;
    180  char *msg = NULL;
    181  MOCK(get_options, mock_get_options);
    182 
    183  tt_ptr_op(opts->Logs, OP_EQ, NULL);
    184  config_line_append(&opts->Logs, "Log", "notice stdout");
    185  lt = options_start_log_transaction(NULL, &msg);
    186  tt_assert(lt);
    187  tt_assert(!msg);
    188 
    189  // commit, see that there is a change.
    190  options_commit_log_transaction(lt);
    191  lt=NULL;
    192  tt_int_op(get_min_log_level(), OP_EQ, LOG_NOTICE);
    193 
    194  // Now drop to debug.
    195  old_opts = opts;
    196  opts = mock_opts = options_new();
    197  opts->LogTimeGranularity = 1000;
    198  opts->SafeLogging_ = SAFELOG_SCRUB_ALL;
    199  config_line_append(&opts->Logs, "Log", "debug stdout");
    200  lt = options_start_log_transaction(old_opts, &msg);
    201  tt_assert(lt);
    202  tt_assert(!msg);
    203 
    204  setup_full_capture_of_logs(LOG_NOTICE);
    205  options_commit_log_transaction(lt);
    206  lt=NULL;
    207  expect_single_log_msg_containing("may contain sensitive information");
    208  tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
    209 
    210  // Turn off SafeLogging
    211  or_options_free(old_opts);
    212  mock_clean_saved_logs();
    213  old_opts = opts;
    214  opts = mock_opts = options_new();
    215  opts->SafeLogging_ = SAFELOG_SCRUB_NONE;
    216  opts->LogTimeGranularity = 1000;
    217  config_line_append(&opts->Logs, "Log", "debug stdout");
    218  lt = options_start_log_transaction(old_opts, &msg);
    219  tt_assert(lt);
    220  tt_assert(!msg);
    221  options_commit_log_transaction(lt);
    222  lt=NULL;
    223  expect_single_log_msg_containing("may contain sensitive information");
    224  tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
    225 
    226  // Try rolling back.
    227  or_options_free(old_opts);
    228  mock_clean_saved_logs();
    229  old_opts = opts;
    230  opts = mock_opts = options_new();
    231  opts->SafeLogging_ = SAFELOG_SCRUB_NONE;
    232  opts->LogTimeGranularity = 1000;
    233  config_line_append(&opts->Logs, "Log", "notice stdout");
    234  lt = options_start_log_transaction(old_opts, &msg);
    235  tt_assert(lt);
    236  tt_assert(!msg);
    237  options_rollback_log_transaction(lt);
    238  expect_no_log_entry();
    239  lt = NULL;
    240  tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
    241 
    242  // Now try some bad options.
    243  or_options_free(opts);
    244  mock_clean_saved_logs();
    245  opts = mock_opts = options_new();
    246  opts->LogTimeGranularity = 1000;
    247  config_line_append(&opts->Logs, "Log", "warn blaznert");
    248  lt = options_start_log_transaction(old_opts, &msg);
    249  tt_assert(!lt);
    250  tt_str_op(msg, OP_EQ, "Failed to init Log options. See logs for details.");
    251  expect_single_log_msg_containing("Couldn't parse");
    252  tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
    253 
    254 done:
    255  UNMOCK(get_options);
    256  or_options_free(opts);
    257  or_options_free(old_opts);
    258  tor_free(msg);
    259  if (lt)
    260    options_rollback_log_transaction(lt);
    261  teardown_capture_of_logs();
    262 }
    263 
    264 #ifndef COCCI
    265 #define T(name) { #name, test_options_act_##name, TT_FORK, NULL, NULL }
    266 #endif
    267 
    268 struct testcase_t options_act_tests[] = {
    269  T(create_dirs),
    270  T(log_transition),
    271  END_OF_TESTCASES
    272 };