Line data Source code
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 8 : get_file_mode(const char *fname, unsigned *permissions_out)
25 : {
26 8 : struct stat st;
27 8 : int r = stat(fname, &st);
28 8 : if (r < 0)
29 : return -1;
30 8 : *permissions_out = (unsigned) st.st_mode;
31 8 : 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 14 : mock_get_options(void)
51 : {
52 14 : return mock_opts;
53 : }
54 :
55 : static void
56 1 : test_options_act_create_dirs(void *arg)
57 : {
58 1 : (void)arg;
59 1 : MOCK(get_options, mock_get_options);
60 1 : char *msg = NULL;
61 1 : 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 1 : char *fn;
69 1 : fn = tor_strdup(get_fname_rnd("ddir"));
70 1 : opts->DataDirectory = tor_strdup(fn);
71 1 : opts->CacheDirectory = tor_strdup(fn);
72 1 : tor_asprintf(&opts->KeyDirectory, "%s/keys", fn);
73 1 : opts->DataDirectoryGroupReadable = 1;
74 1 : opts->CacheDirectoryGroupReadable = -1; /* default. */
75 1 : int r = options_create_directories(&msg);
76 1 : tt_int_op(r, OP_EQ, 0);
77 1 : tt_ptr_op(msg, OP_EQ, NULL);
78 1 : tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
79 1 : tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
80 1 : tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
81 1 : assert_mode(opts->DataDirectory, 0777, 0750);
82 1 : assert_mode(opts->KeyDirectory, 0777, 0700);
83 1 : tor_free(fn);
84 1 : tor_free(opts->KeyDirectory);
85 1 : or_options_free(opts);
86 :
87 : /* Success case 2: all directories are different. */
88 1 : opts = mock_opts = options_new();
89 1 : opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
90 1 : opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
91 1 : opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
92 1 : opts->CacheDirectoryGroupReadable = 1; // cache directory group readable
93 1 : r = options_create_directories(&msg);
94 1 : tt_int_op(r, OP_EQ, 0);
95 1 : tt_ptr_op(msg, OP_EQ, NULL);
96 1 : tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
97 1 : tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
98 1 : tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
99 1 : assert_mode(opts->DataDirectory, 0777, 0700);
100 1 : assert_mode(opts->KeyDirectory, 0777, 0700);
101 1 : assert_mode(opts->CacheDirectory, 0777, 0750);
102 1 : tor_free(fn);
103 1 : or_options_free(opts);
104 :
105 : /* Success case 3: all directories are the same. */
106 1 : opts = mock_opts = options_new();
107 1 : fn = tor_strdup(get_fname_rnd("ddir"));
108 1 : opts->DataDirectory = tor_strdup(fn);
109 1 : opts->CacheDirectory = tor_strdup(fn);
110 1 : opts->KeyDirectory = tor_strdup(fn);
111 1 : opts->DataDirectoryGroupReadable = 1;
112 1 : opts->CacheDirectoryGroupReadable = -1; /* default. */
113 1 : opts->KeyDirectoryGroupReadable = -1; /* default */
114 1 : r = options_create_directories(&msg);
115 1 : tt_int_op(r, OP_EQ, 0);
116 1 : tt_ptr_op(msg, OP_EQ, NULL);
117 1 : tt_int_op(FN_DIR, OP_EQ, file_status(opts->DataDirectory));
118 1 : tt_int_op(FN_DIR, OP_EQ, file_status(opts->CacheDirectory));
119 1 : tt_int_op(FN_DIR, OP_EQ, file_status(opts->KeyDirectory));
120 1 : assert_mode(opts->DataDirectory, 0777, 0750);
121 1 : assert_mode(opts->KeyDirectory, 0777, 0750);
122 1 : assert_mode(opts->CacheDirectory, 0777, 0750);
123 1 : tor_free(fn);
124 1 : or_options_free(opts);
125 :
126 : /* Failure case 1: Can't make datadir. */
127 1 : opts = mock_opts = options_new();
128 1 : opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
129 1 : opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
130 1 : opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
131 1 : write_str_to_file(opts->DataDirectory, "foo", 0);
132 1 : r = options_create_directories(&msg);
133 1 : tt_int_op(r, OP_LT, 0);
134 1 : tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
135 1 : or_options_free(opts);
136 1 : tor_free(msg);
137 :
138 : /* Failure case 2: Can't make keydir. */
139 1 : opts = mock_opts = options_new();
140 1 : opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
141 1 : opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
142 1 : opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
143 1 : write_str_to_file(opts->KeyDirectory, "foo", 0);
144 1 : r = options_create_directories(&msg);
145 1 : tt_int_op(r, OP_LT, 0);
146 1 : tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
147 1 : or_options_free(opts);
148 1 : tor_free(msg);
149 :
150 : /* Failure case 3: Can't make cachedir. */
151 1 : opts = mock_opts = options_new();
152 1 : opts->DataDirectory = tor_strdup(get_fname_rnd("ddir"));
153 1 : opts->CacheDirectory = tor_strdup(get_fname_rnd("cdir"));
154 1 : opts->KeyDirectory = tor_strdup(get_fname_rnd("kdir"));
155 1 : write_str_to_file(opts->CacheDirectory, "foo", 0);
156 1 : r = options_create_directories(&msg);
157 1 : tt_int_op(r, OP_LT, 0);
158 1 : tt_assert(!strcmpstart(msg, "Couldn't create private data directory"));
159 1 : tor_free(fn);
160 1 : or_options_free(opts);
161 1 : tor_free(msg);
162 :
163 1 : done:
164 1 : UNMOCK(get_options);
165 1 : or_options_free(opts);
166 1 : mock_opts = NULL;
167 1 : tor_free(fn);
168 1 : tor_free(msg);
169 1 : }
170 :
171 : static void
172 1 : test_options_act_log_transition(void *arg)
173 : {
174 1 : (void)arg;
175 1 : or_options_t *opts = mock_opts = options_new();
176 1 : or_options_t *old_opts = NULL;
177 1 : opts->LogTimeGranularity = 1000;
178 1 : opts->SafeLogging_ = SAFELOG_SCRUB_ALL;
179 1 : struct log_transaction_t *lt = NULL;
180 1 : char *msg = NULL;
181 1 : MOCK(get_options, mock_get_options);
182 :
183 1 : tt_ptr_op(opts->Logs, OP_EQ, NULL);
184 1 : config_line_append(&opts->Logs, "Log", "notice stdout");
185 1 : lt = options_start_log_transaction(NULL, &msg);
186 1 : tt_assert(lt);
187 1 : tt_assert(!msg);
188 :
189 : // commit, see that there is a change.
190 1 : options_commit_log_transaction(lt);
191 1 : lt=NULL;
192 1 : tt_int_op(get_min_log_level(), OP_EQ, LOG_NOTICE);
193 :
194 : // Now drop to debug.
195 1 : old_opts = opts;
196 1 : opts = mock_opts = options_new();
197 1 : opts->LogTimeGranularity = 1000;
198 1 : opts->SafeLogging_ = SAFELOG_SCRUB_ALL;
199 1 : config_line_append(&opts->Logs, "Log", "debug stdout");
200 1 : lt = options_start_log_transaction(old_opts, &msg);
201 1 : tt_assert(lt);
202 1 : tt_assert(!msg);
203 :
204 1 : setup_full_capture_of_logs(LOG_NOTICE);
205 1 : options_commit_log_transaction(lt);
206 1 : lt=NULL;
207 1 : expect_single_log_msg_containing("may contain sensitive information");
208 1 : tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
209 :
210 : // Turn off SafeLogging
211 1 : or_options_free(old_opts);
212 1 : mock_clean_saved_logs();
213 1 : old_opts = opts;
214 1 : opts = mock_opts = options_new();
215 1 : opts->SafeLogging_ = SAFELOG_SCRUB_NONE;
216 1 : opts->LogTimeGranularity = 1000;
217 1 : config_line_append(&opts->Logs, "Log", "debug stdout");
218 1 : lt = options_start_log_transaction(old_opts, &msg);
219 1 : tt_assert(lt);
220 1 : tt_assert(!msg);
221 1 : options_commit_log_transaction(lt);
222 1 : lt=NULL;
223 1 : expect_single_log_msg_containing("may contain sensitive information");
224 1 : tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
225 :
226 : // Try rolling back.
227 1 : or_options_free(old_opts);
228 1 : mock_clean_saved_logs();
229 1 : old_opts = opts;
230 1 : opts = mock_opts = options_new();
231 1 : opts->SafeLogging_ = SAFELOG_SCRUB_NONE;
232 1 : opts->LogTimeGranularity = 1000;
233 1 : config_line_append(&opts->Logs, "Log", "notice stdout");
234 1 : lt = options_start_log_transaction(old_opts, &msg);
235 1 : tt_assert(lt);
236 1 : tt_assert(!msg);
237 1 : options_rollback_log_transaction(lt);
238 1 : expect_no_log_entry();
239 1 : lt = NULL;
240 1 : tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
241 :
242 : // Now try some bad options.
243 1 : or_options_free(opts);
244 1 : mock_clean_saved_logs();
245 1 : opts = mock_opts = options_new();
246 1 : opts->LogTimeGranularity = 1000;
247 1 : config_line_append(&opts->Logs, "Log", "warn blaznert");
248 1 : lt = options_start_log_transaction(old_opts, &msg);
249 1 : tt_assert(!lt);
250 1 : tt_str_op(msg, OP_EQ, "Failed to init Log options. See logs for details.");
251 1 : expect_single_log_msg_containing("Couldn't parse");
252 1 : tt_int_op(get_min_log_level(), OP_EQ, LOG_DEBUG);
253 :
254 1 : done:
255 1 : UNMOCK(get_options);
256 1 : or_options_free(opts);
257 1 : or_options_free(old_opts);
258 1 : tor_free(msg);
259 1 : if (lt)
260 0 : options_rollback_log_transaction(lt);
261 1 : teardown_capture_of_logs();
262 1 : }
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 : };
|