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 };