Line data Source code
1 : /*
2 : Authors:
3 : Jakub Hrozek <jhrozek@redhat.com>
4 :
5 : Copyright (C) 2013 Red Hat
6 :
7 : SSSD tests: AD access control filter tests
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include <talloc.h>
24 : #include <tevent.h>
25 : #include <errno.h>
26 : #include <popt.h>
27 : #include <unistd.h>
28 : #include <sys/types.h>
29 : #include <ifaddrs.h>
30 : #include <arpa/inet.h>
31 :
32 : /* In order to access opaque types */
33 : #include "providers/ad/ad_access.c"
34 :
35 : #include "tests/cmocka/common_mock.h"
36 :
37 : #define DOM_NAME "parent_dom"
38 :
39 : struct ad_access_test_ctx {
40 : struct sss_domain_info *dom;
41 : };
42 :
43 : static struct ad_access_test_ctx *test_ctx;
44 :
45 4 : int ad_access_filter_test_setup(void **state)
46 : {
47 4 : assert_true(leak_check_setup());
48 4 : test_ctx = talloc_zero(global_talloc_context,
49 : struct ad_access_test_ctx);
50 4 : assert_non_null(test_ctx);
51 :
52 4 : test_ctx->dom = talloc_zero(test_ctx, struct sss_domain_info);
53 4 : assert_non_null(test_ctx->dom);
54 :
55 4 : test_ctx->dom->name = talloc_strdup(test_ctx->dom, DOM_NAME);
56 4 : assert_non_null(test_ctx->dom->name);
57 4 : return 0;
58 : }
59 :
60 4 : int ad_access_filter_test_teardown(void **state)
61 : {
62 4 : talloc_free(test_ctx);
63 4 : assert_true(leak_check_teardown());
64 4 : return 0;
65 : }
66 :
67 : struct filter_parse_result {
68 : const int result;
69 : const char *best_match;
70 : };
71 :
72 11 : static void test_parse_filter_generic(const char *filter_in,
73 : struct filter_parse_result *expected)
74 : {
75 : errno_t ret;
76 : TALLOC_CTX *tmp_ctx;
77 : char *best_match;
78 :
79 11 : assert_non_null(expected);
80 :
81 11 : tmp_ctx = talloc_new(global_talloc_context);
82 11 : assert_non_null(tmp_ctx);
83 11 : check_leaks_push(tmp_ctx);
84 :
85 11 : ret = ad_parse_access_filter(tmp_ctx, test_ctx->dom, filter_in,
86 : &best_match);
87 11 : assert_int_equal(ret, expected->result);
88 11 : if (expected->result != EOK) {
89 0 : goto done;
90 : }
91 :
92 11 : if (expected->best_match != NULL) {
93 9 : assert_string_equal(best_match, expected->best_match);
94 : } else {
95 2 : assert_true(best_match == NULL);
96 : }
97 11 : talloc_free(best_match);
98 :
99 : done:
100 11 : assert_true(check_leaks_pop(tmp_ctx) == true);
101 11 : talloc_free(tmp_ctx);
102 11 : }
103 :
104 : /* Test that setting no filter lets all access through
105 : */
106 1 : void test_no_filter(void **state)
107 : {
108 1 : struct filter_parse_result expected = {
109 : .result = EOK,
110 : .best_match = NULL
111 : };
112 :
113 1 : test_parse_filter_generic(NULL, &expected);
114 1 : }
115 :
116 : /* Test that if one filter is provided, it is returned as-is
117 : */
118 1 : void test_single_filter(void **state)
119 : {
120 1 : struct filter_parse_result expected = {
121 : .result = EOK,
122 : .best_match = "(name=foo)"
123 : };
124 :
125 1 : test_parse_filter_generic("name=foo", &expected);
126 1 : test_parse_filter_generic("(name=foo)", &expected);
127 1 : test_parse_filter_generic(DOM_NAME":(name=foo)", &expected);
128 1 : test_parse_filter_generic("DOM:"DOM_NAME":(name=foo)", &expected);
129 1 : }
130 :
131 : /* Test that if more filters are provided, the best match is returned */
132 1 : void test_filter_order(void **state)
133 : {
134 1 : struct filter_parse_result expected = {
135 : .result = EOK,
136 : .best_match = "(name=foo)"
137 : };
138 :
139 1 : test_parse_filter_generic("name=foo?name=bar", &expected);
140 1 : test_parse_filter_generic(DOM_NAME":(name=foo)?name=bar", &expected);
141 1 : test_parse_filter_generic("name=bla?"DOM_NAME":(name=foo)?name=bar", &expected);
142 : /* Test that another foreign domain wouldn't match */
143 1 : test_parse_filter_generic("anotherdom:(name=bla)?"DOM_NAME":(name=foo)", &expected);
144 1 : test_parse_filter_generic("anotherdom:(name=bla)?(name=foo)", &expected);
145 1 : }
146 :
147 1 : void test_filter_no_match(void **state)
148 : {
149 1 : struct filter_parse_result expected = {
150 : .result = EOK,
151 : .best_match = NULL
152 : };
153 :
154 1 : test_parse_filter_generic("anotherdom:(name=bla)?yetanother:(name=foo)", &expected);
155 1 : }
156 :
157 :
158 5 : int parse_test_setup(void **state)
159 : {
160 5 : assert_true(leak_check_setup());
161 5 : return 0;
162 : }
163 :
164 5 : int parse_test_teardown(void **state)
165 : {
166 5 : assert_true(leak_check_teardown());
167 5 : return 0;
168 : }
169 :
170 : struct parse_result {
171 : const int result;
172 : const char *filter;
173 : const char *spec;
174 : const int flags;
175 : };
176 :
177 11 : static void test_parse_generic(const char *filter_in, struct parse_result *expected)
178 : {
179 : errno_t ret;
180 : TALLOC_CTX *tmp_ctx;
181 : char *filter;
182 : char *spec;
183 : int flags;
184 :
185 11 : assert_non_null(expected);
186 :
187 11 : tmp_ctx = talloc_new(global_talloc_context);
188 11 : assert_non_null(tmp_ctx);
189 11 : check_leaks_push(tmp_ctx);
190 :
191 11 : ret = parse_filter(tmp_ctx, filter_in, &filter, &spec, &flags);
192 :
193 11 : assert_int_equal(ret, expected->result);
194 11 : if (expected->result != EOK) {
195 6 : goto done;
196 : }
197 :
198 5 : if (expected->filter != NULL) {
199 5 : assert_string_equal(filter, expected->filter);
200 : } else {
201 0 : assert_true(filter == NULL);
202 : }
203 5 : talloc_free(filter);
204 :
205 5 : if (expected->spec != NULL) {
206 4 : assert_string_equal(spec, expected->spec);
207 : } else {
208 1 : assert_true(spec == NULL);
209 : }
210 5 : talloc_free(spec);
211 :
212 5 : assert_int_equal(flags, expected->flags);
213 :
214 : done:
215 11 : assert_true(check_leaks_pop(tmp_ctx) == true);
216 11 : talloc_free(tmp_ctx);
217 11 : }
218 :
219 1 : void test_parse_plain(void **state)
220 : {
221 1 : struct parse_result expected = {
222 : .result = EOK,
223 : .filter = "name=foo",
224 : .spec = NULL,
225 : .flags = AD_FILTER_GENERIC
226 : };
227 :
228 1 : test_parse_generic("name=foo", &expected);
229 1 : }
230 :
231 1 : void test_parse_dom_without_kw(void **state)
232 : {
233 1 : struct parse_result expected = {
234 : .result = EOK,
235 : .filter = "(name=foo)",
236 : .spec = "mydom",
237 : .flags = AD_FILTER_DOMAIN
238 : };
239 :
240 1 : test_parse_generic("mydom:(name=foo)", &expected);
241 :
242 : /* Check we can handle domain called DOM */
243 1 : struct parse_result expected2 = {
244 : .result = EOK,
245 : .filter = "(name=foo)",
246 : .spec = "DOM",
247 : .flags = AD_FILTER_DOMAIN
248 : };
249 :
250 1 : test_parse_generic("DOM:(name=foo)", &expected2);
251 1 : }
252 :
253 1 : void test_parse_dom_kw(void **state)
254 : {
255 1 : struct parse_result expected = {
256 : .result = EOK,
257 : .filter = "(name=foo)",
258 : .spec = "mydom",
259 : .flags = AD_FILTER_DOMAIN
260 : };
261 :
262 1 : test_parse_generic("DOM:mydom:(name=foo)", &expected);
263 1 : }
264 :
265 1 : void test_parse_forest_kw(void **state)
266 : {
267 1 : struct parse_result expected = {
268 : .result = EOK,
269 : .filter = "(name=foo)",
270 : .spec = "myforest",
271 : .flags = AD_FILTER_FOREST
272 : };
273 :
274 1 : test_parse_generic("FOREST:myforest:(name=foo)", &expected);
275 1 : }
276 :
277 :
278 1 : void test_parse_malformed(void **state)
279 : {
280 1 : struct parse_result expected = {
281 : .result = EINVAL,
282 : };
283 :
284 1 : test_parse_generic("DOM:", &expected);
285 1 : test_parse_generic("DOM::", &expected);
286 1 : test_parse_generic("DOM:mydom:", &expected);
287 1 : test_parse_generic("DOM:mydom:name=foo", &expected);
288 1 : test_parse_generic("DOM::(name=foo)", &expected);
289 1 : test_parse_generic("BLABLABLA:mydom:name=foo", &expected);
290 1 : }
291 :
292 1 : int main(int argc, const char *argv[])
293 : {
294 : poptContext pc;
295 : int opt;
296 6 : struct poptOption long_options[] = {
297 : POPT_AUTOHELP
298 5 : SSSD_DEBUG_OPTS
299 : POPT_TABLEEND
300 : };
301 :
302 1 : const struct CMUnitTest tests[] = {
303 : cmocka_unit_test_setup_teardown(test_parse_plain,
304 : parse_test_setup,
305 : parse_test_teardown),
306 :
307 : cmocka_unit_test_setup_teardown(test_parse_dom_without_kw,
308 : parse_test_setup,
309 : parse_test_teardown),
310 :
311 : cmocka_unit_test_setup_teardown(test_parse_dom_kw,
312 : parse_test_setup,
313 : parse_test_teardown),
314 :
315 : cmocka_unit_test_setup_teardown(test_parse_forest_kw,
316 : parse_test_setup,
317 : parse_test_teardown),
318 :
319 : cmocka_unit_test_setup_teardown(test_parse_malformed,
320 : parse_test_setup,
321 : parse_test_teardown),
322 :
323 : cmocka_unit_test_setup_teardown(test_no_filter,
324 : ad_access_filter_test_setup,
325 : ad_access_filter_test_teardown),
326 :
327 : cmocka_unit_test_setup_teardown(test_single_filter,
328 : ad_access_filter_test_setup,
329 : ad_access_filter_test_teardown),
330 :
331 : cmocka_unit_test_setup_teardown(test_filter_order,
332 : ad_access_filter_test_setup,
333 : ad_access_filter_test_teardown),
334 :
335 : cmocka_unit_test_setup_teardown(test_filter_no_match,
336 : ad_access_filter_test_setup,
337 : ad_access_filter_test_teardown),
338 :
339 : };
340 :
341 : /* Set debug level to invalid value so we can deside if -d 0 was used. */
342 1 : debug_level = SSSDBG_INVALID;
343 :
344 1 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
345 1 : while((opt = poptGetNextOpt(pc)) != -1) {
346 : switch(opt) {
347 : default:
348 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
349 : poptBadOption(pc, 0), poptStrerror(opt));
350 0 : poptPrintUsage(pc, stderr, 0);
351 0 : return 1;
352 : }
353 : }
354 1 : poptFreeContext(pc);
355 :
356 1 : DEBUG_CLI_INIT(debug_level);
357 :
358 1 : tests_set_cwd();
359 :
360 1 : return cmocka_run_group_tests(tests, NULL, NULL);
361 : }
|