Merge branch 'maint-0.4.8'
[tor.git] / src / test / test_options_act.c
blob00445989629fbe9922d08d0569f90f0f9cfd78d1
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 */
6 #define CONFIG_PRIVATE
7 #include "core/or/or.h"
8 #include "app/config/config.h"
9 #include "lib/encoding/confline.h"
11 #include "test/test.h"
12 #include "test/log_test_helpers.h"
13 #include "test/test_helpers.h"
15 #ifndef _WIN32
16 #include <sys/stat.h>
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.
23 static int
24 get_file_mode(const char *fname, unsigned *permissions_out)
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;
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) */
48 static or_options_t *mock_opts;
49 static const or_options_t *
50 mock_get_options(void)
52 return mock_opts;
55 static void
56 test_options_act_create_dirs(void *arg)
58 (void)arg;
59 MOCK(get_options, mock_get_options);
60 char *msg = NULL;
61 or_options_t *opts = mock_opts = options_new();
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. */
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);
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);
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);
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);
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);
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);
163 done:
164 UNMOCK(get_options);
165 or_options_free(opts);
166 mock_opts = NULL;
167 tor_free(fn);
168 tor_free(msg);
171 static void
172 test_options_act_log_transition(void *arg)
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);
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);
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);
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);
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);
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);
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);
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);
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();
264 #ifndef COCCI
265 #define T(name) { #name, test_options_act_##name, TT_FORK, NULL, NULL }
266 #endif
268 struct testcase_t options_act_tests[] = {
269 T(create_dirs),
270 T(log_transition),
271 END_OF_TESTCASES