Line data Source code
1 : /*
2 : Authors:
3 : Jakub Hrozek <jhrozek@redhat.com>
4 :
5 : Copyright (C) 2013 Red Hat
6 :
7 : SSSD tests: InfoPipe responder
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 <popt.h>
24 :
25 : #include "db/sysdb.h"
26 : #include "tests/cmocka/common_mock.h"
27 : #include "tests/cmocka/common_mock_resp.h"
28 : #include "responder/ifp/ifp_private.h"
29 : #include "sbus/sssd_dbus_private.h"
30 :
31 : /* dbus library checks for valid object paths when unit testing, we don't
32 : * want that */
33 : #undef DBUS_TYPE_OBJECT_PATH
34 : #define DBUS_TYPE_OBJECT_PATH ((int) 's')
35 :
36 : static struct ifp_ctx *
37 3 : mock_ifp_ctx(TALLOC_CTX *mem_ctx)
38 : {
39 : struct ifp_ctx *ifp_ctx;
40 :
41 3 : ifp_ctx = talloc_zero(mem_ctx, struct ifp_ctx);
42 3 : assert_non_null(ifp_ctx);
43 :
44 3 : ifp_ctx->rctx = mock_rctx(ifp_ctx, NULL, NULL, NULL);
45 3 : assert_non_null(ifp_ctx->rctx);
46 :
47 3 : ifp_ctx->rctx->allowed_uids = talloc_array(ifp_ctx->rctx, uint32_t, 1);
48 3 : assert_non_null(ifp_ctx->rctx->allowed_uids);
49 3 : ifp_ctx->rctx->allowed_uids[0] = geteuid();
50 3 : ifp_ctx->rctx->allowed_uids_count = 1;
51 :
52 3 : ifp_ctx->sysbus = talloc_zero(ifp_ctx, struct sysbus_ctx);
53 3 : assert_non_null(ifp_ctx->sysbus);
54 :
55 3 : ifp_ctx->sysbus->conn = talloc_zero(ifp_ctx, struct sbus_connection);
56 3 : assert_non_null(ifp_ctx->sysbus->conn);
57 :
58 3 : return ifp_ctx;
59 : }
60 :
61 : static struct sbus_request *
62 4 : mock_sbus_request(TALLOC_CTX *mem_ctx, uid_t client)
63 : {
64 : struct sbus_request *sr;
65 :
66 4 : sr = talloc_zero(mem_ctx, struct sbus_request);
67 4 : assert_non_null(sr);
68 :
69 4 : sr->conn = talloc_zero(sr, struct sbus_connection);
70 4 : assert_non_null(sr->conn);
71 :
72 4 : sr->message = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_CALL);
73 4 : assert_non_null(sr->message);
74 4 : dbus_message_set_serial(sr->message, 1);
75 :
76 4 : sr->client = client;
77 :
78 4 : return sr;
79 : }
80 :
81 1 : void ifp_test_req_create(void **state)
82 : {
83 : struct ifp_req *ireq;
84 : struct sbus_request *sr;
85 : struct ifp_ctx *ifp_ctx;
86 : errno_t ret;
87 :
88 1 : assert_true(leak_check_setup());
89 :
90 1 : ifp_ctx = mock_ifp_ctx(global_talloc_context);
91 1 : assert_non_null(ifp_ctx);
92 1 : check_leaks_push(ifp_ctx);
93 :
94 1 : sr = mock_sbus_request(ifp_ctx, geteuid());
95 1 : assert_non_null(sr);
96 1 : check_leaks_push(sr);
97 :
98 1 : ret = ifp_req_create(sr, ifp_ctx, &ireq);
99 1 : assert_int_equal(ret, EOK);
100 1 : talloc_free(ireq);
101 :
102 1 : assert_true(check_leaks_pop(sr) == true);
103 1 : talloc_free(sr);
104 :
105 1 : assert_true(check_leaks_pop(ifp_ctx) == true);
106 1 : talloc_free(ifp_ctx);
107 :
108 1 : assert_true(leak_check_teardown());
109 1 : }
110 :
111 1 : void ifp_test_req_wrong_uid(void **state)
112 : {
113 : struct ifp_req *ireq;
114 : struct sbus_request *sr;
115 : struct ifp_ctx *ifp_ctx;
116 : errno_t ret;
117 :
118 1 : assert_true(leak_check_setup());
119 :
120 1 : ifp_ctx = mock_ifp_ctx(global_talloc_context);
121 1 : assert_non_null(ifp_ctx);
122 1 : check_leaks_push(ifp_ctx);
123 :
124 1 : sr = mock_sbus_request(ifp_ctx, geteuid()+1);
125 1 : assert_non_null(sr);
126 :
127 1 : ret = ifp_req_create(sr, ifp_ctx, &ireq);
128 1 : assert_int_equal(ret, EACCES);
129 1 : talloc_free(sr);
130 :
131 1 : assert_true(check_leaks_pop(ifp_ctx) == true);
132 1 : talloc_free(ifp_ctx);
133 :
134 1 : assert_true(leak_check_teardown());
135 1 : }
136 :
137 1 : void test_el_to_dict(void **state)
138 : {
139 : static struct sbus_request *sr;
140 : dbus_bool_t dbret;
141 : DBusMessageIter iter;
142 : DBusMessageIter iter_dict;
143 : struct ldb_message_element *el;
144 : errno_t ret;
145 : char *attr_name;
146 : char *attr_val;
147 :
148 1 : sr = mock_sbus_request(global_talloc_context, geteuid());
149 1 : assert_non_null(sr);
150 :
151 1 : el = talloc(sr, struct ldb_message_element);
152 1 : assert_non_null(el);
153 1 : el->name = "numbers";
154 1 : el->values = talloc_array(el, struct ldb_val, 2);
155 1 : assert_non_null(el->values);
156 1 : el->num_values = 2;
157 1 : el->values[0].data = (uint8_t *) discard_const("one");
158 1 : el->values[0].length = strlen("one") + 1;
159 1 : el->values[1].data = (uint8_t *) discard_const("two");
160 1 : el->values[1].length = strlen("two") + 1;
161 :
162 1 : dbus_message_iter_init_append(sr->message, &iter);
163 1 : dbret = dbus_message_iter_open_container(
164 : &iter, DBUS_TYPE_ARRAY,
165 : DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
166 : DBUS_TYPE_STRING_AS_STRING
167 : DBUS_TYPE_VARIANT_AS_STRING
168 : DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
169 : &iter_dict);
170 1 : assert_true(dbret == TRUE);
171 :
172 1 : ret = ifp_add_ldb_el_to_dict(&iter_dict, el);
173 1 : assert_int_equal(ret, EOK);
174 :
175 1 : dbret = dbus_message_iter_close_container(&iter, &iter_dict);
176 1 : assert_true(dbret == TRUE);
177 :
178 : /* Test the reply contains what we expect */
179 1 : dbus_message_iter_init(sr->message, &iter);
180 1 : assert_int_equal(dbus_message_iter_get_arg_type(&iter),
181 : DBUS_TYPE_ARRAY);
182 1 : dbus_message_iter_recurse(&iter, &iter);
183 1 : assert_int_equal(dbus_message_iter_get_arg_type(&iter),
184 : DBUS_TYPE_DICT_ENTRY);
185 :
186 1 : dbus_message_iter_recurse(&iter, &iter_dict);
187 1 : dbus_message_iter_get_basic(&iter_dict, &attr_name);
188 1 : assert_string_equal(attr_name, "numbers");
189 :
190 1 : dbus_message_iter_next(&iter_dict);
191 1 : assert_int_equal(dbus_message_iter_get_arg_type(&iter_dict),
192 : DBUS_TYPE_VARIANT);
193 1 : dbus_message_iter_recurse(&iter_dict, &iter_dict);
194 1 : assert_int_equal(dbus_message_iter_get_arg_type(&iter_dict),
195 : DBUS_TYPE_ARRAY);
196 :
197 1 : dbus_message_iter_recurse(&iter_dict, &iter_dict);
198 1 : dbus_message_iter_get_basic(&iter_dict, &attr_val);
199 1 : assert_string_equal(attr_val, "one");
200 1 : assert_true(dbus_message_iter_next(&iter_dict));
201 1 : dbus_message_iter_get_basic(&iter_dict, &attr_val);
202 1 : assert_string_equal(attr_val, "two");
203 1 : assert_false(dbus_message_iter_next(&iter_dict));
204 :
205 1 : talloc_free(sr);
206 1 : }
207 :
208 11 : static void assert_string_list_equal(const char **s1,
209 : const char **s2)
210 : {
211 : int i;
212 :
213 57 : for (i=0; s1[i]; i++) {
214 46 : assert_non_null(s2[i]);
215 46 : assert_string_equal(s1[i], s2[i]);
216 : }
217 :
218 11 : assert_null(s2[i]);
219 11 : }
220 :
221 7 : static void attr_parse_test(const char *expected[], const char *input)
222 : {
223 : const char **res;
224 : TALLOC_CTX *test_ctx;
225 :
226 7 : test_ctx = talloc_new(NULL);
227 7 : assert_non_null(test_ctx);
228 :
229 7 : res = ifp_parse_user_attr_list(test_ctx, input);
230 :
231 7 : if (expected) {
232 : /* Positive test */
233 6 : assert_non_null(res);
234 6 : assert_string_list_equal(res, expected);
235 : } else {
236 : /* Negative test */
237 1 : assert_null(res);
238 : }
239 :
240 7 : talloc_free(test_ctx);
241 7 : }
242 :
243 5 : static void attr_parse_test_ex(const char *expected[], const char *input,
244 : const char **defaults)
245 : {
246 : const char **res;
247 : TALLOC_CTX *test_ctx;
248 :
249 5 : test_ctx = talloc_new(NULL);
250 5 : assert_non_null(test_ctx);
251 :
252 5 : res = parse_attr_list_ex(test_ctx, input, defaults);
253 :
254 5 : if (expected) {
255 : /* Positive test */
256 5 : assert_non_null(res);
257 5 : assert_string_list_equal(res, expected);
258 : } else {
259 : /* Negative test */
260 0 : assert_null(res);
261 : }
262 :
263 5 : talloc_free(test_ctx);
264 5 : }
265 :
266 1 : void test_attr_acl(void **state)
267 : {
268 : /* Test defaults */
269 1 : const char *exp_defaults[] = { SYSDB_NAME, SYSDB_UIDNUM,
270 : SYSDB_GIDNUM, SYSDB_GECOS,
271 : SYSDB_HOMEDIR, SYSDB_SHELL,
272 : "groups", NULL };
273 1 : attr_parse_test(exp_defaults, NULL);
274 :
275 : /* Test adding some attributes to the defaults */
276 1 : const char *exp_add[] = { "telephoneNumber", "streetAddress",
277 : SYSDB_NAME, SYSDB_UIDNUM,
278 : SYSDB_GIDNUM, SYSDB_GECOS,
279 : SYSDB_HOMEDIR, SYSDB_SHELL,
280 : "groups", NULL };
281 1 : attr_parse_test(exp_add, "+telephoneNumber, +streetAddress");
282 :
283 : /* Test removing some attributes to the defaults */
284 1 : const char *exp_rm[] = { SYSDB_NAME,
285 : SYSDB_GIDNUM, SYSDB_GECOS,
286 : SYSDB_HOMEDIR, "groups",
287 : NULL };
288 1 : attr_parse_test(exp_rm, "-"SYSDB_SHELL ",-"SYSDB_UIDNUM);
289 :
290 : /* Test both add and remove */
291 1 : const char *exp_add_rm[] = { "telephoneNumber",
292 : SYSDB_NAME, SYSDB_UIDNUM,
293 : SYSDB_GIDNUM, SYSDB_GECOS,
294 : SYSDB_HOMEDIR, "groups",
295 : NULL };
296 1 : attr_parse_test(exp_add_rm, "+telephoneNumber, -"SYSDB_SHELL);
297 :
298 : /* Test rm trumps add */
299 1 : const char *exp_add_rm_override[] = { SYSDB_NAME, SYSDB_UIDNUM,
300 : SYSDB_GIDNUM, SYSDB_GECOS,
301 : SYSDB_HOMEDIR, SYSDB_SHELL,
302 : "groups", NULL };
303 1 : attr_parse_test(exp_add_rm_override,
304 : "+telephoneNumber, -telephoneNumber, +telephoneNumber");
305 :
306 : /* Remove all */
307 1 : const char *rm_all[] = { NULL };
308 1 : attr_parse_test(rm_all, "-"SYSDB_NAME ", -"SYSDB_UIDNUM
309 : ", -"SYSDB_GIDNUM ", -"SYSDB_GECOS
310 : ", -"SYSDB_HOMEDIR ", -"SYSDB_SHELL", -groups");
311 :
312 : /* Malformed list */
313 1 : attr_parse_test(NULL, "missing_plus_or_minus");
314 1 : }
315 :
316 1 : void test_attr_acl_ex(void **state)
317 : {
318 : /* Test defaults */
319 1 : const char *exp_defaults[] = { "abc", "123", "xyz", NULL };
320 1 : attr_parse_test_ex(exp_defaults, NULL, exp_defaults);
321 :
322 : /* Test adding some attributes to the defaults */
323 1 : const char *exp_add[] = { "telephoneNumber", "streetAddress",
324 : "abc", "123", "xyz",
325 : NULL };
326 1 : attr_parse_test_ex(exp_add, "+telephoneNumber, +streetAddress",
327 : exp_defaults);
328 :
329 : /* Test removing some attributes to the defaults */
330 1 : const char *exp_rm[] = { "123", NULL };
331 1 : attr_parse_test_ex(exp_rm, "-abc, -xyz", exp_defaults);
332 :
333 : /* Test adding with empty defaults */
334 1 : const char *exp_add_empty[] = { "telephoneNumber", "streetAddress",
335 : NULL };
336 1 : attr_parse_test_ex(exp_add_empty, "+telephoneNumber, +streetAddress", NULL);
337 :
338 : /* Test removing with empty defaults */
339 1 : const char *rm_all[] = { NULL };
340 1 : attr_parse_test_ex(rm_all, "-telephoneNumber, -streetAddress", NULL);
341 1 : }
342 :
343 1 : void test_attr_allowed(void **state)
344 : {
345 1 : const char *whitelist[] = { "name", "gecos", NULL };
346 1 : const char *emptylist[] = { NULL };
347 :
348 1 : assert_true(ifp_attr_allowed(whitelist, "name"));
349 1 : assert_true(ifp_attr_allowed(whitelist, "gecos"));
350 :
351 1 : assert_false(ifp_attr_allowed(whitelist, "password"));
352 :
353 1 : assert_false(ifp_attr_allowed(emptylist, "name"));
354 1 : assert_false(ifp_attr_allowed(NULL, "name"));
355 1 : }
356 :
357 : struct ifp_test_req_ctx {
358 : struct ifp_req *ireq;
359 : struct sbus_request *sr;
360 : struct ifp_ctx *ifp_ctx;
361 : };
362 :
363 1 : static int ifp_test_req_setup(void **state)
364 : {
365 : struct ifp_test_req_ctx *test_ctx;
366 : errno_t ret;
367 :
368 1 : assert_true(leak_check_setup());
369 :
370 1 : test_ctx = talloc_zero(global_talloc_context, struct ifp_test_req_ctx);
371 1 : assert_non_null(test_ctx);
372 1 : test_ctx->ifp_ctx = mock_ifp_ctx(test_ctx);
373 1 : assert_non_null(test_ctx->ifp_ctx);
374 :
375 1 : test_ctx->sr = mock_sbus_request(test_ctx, geteuid());
376 1 : assert_non_null(test_ctx->sr);
377 :
378 1 : ret = ifp_req_create(test_ctx->sr, test_ctx->ifp_ctx, &test_ctx->ireq);
379 1 : assert_int_equal(ret, EOK);
380 1 : assert_non_null(test_ctx->ireq);
381 :
382 1 : check_leaks_push(test_ctx);
383 1 : *state = test_ctx;
384 1 : return 0;
385 : }
386 :
387 1 : static int ifp_test_req_teardown(void **state)
388 : {
389 1 : struct ifp_test_req_ctx *test_ctx = talloc_get_type_abort(*state,
390 : struct ifp_test_req_ctx);
391 :
392 1 : assert_true(check_leaks_pop(test_ctx) == true);
393 :
394 1 : dbus_message_unref(test_ctx->sr->message);
395 1 : talloc_free(test_ctx);
396 :
397 1 : assert_true(leak_check_teardown());
398 1 : return 0;
399 : }
400 :
401 1 : int main(int argc, const char *argv[])
402 : {
403 : poptContext pc;
404 : int opt;
405 6 : struct poptOption long_options[] = {
406 : POPT_AUTOHELP
407 5 : SSSD_DEBUG_OPTS
408 : POPT_TABLEEND
409 : };
410 :
411 1 : const struct CMUnitTest tests[] = {
412 : cmocka_unit_test(ifp_test_req_create),
413 : cmocka_unit_test(ifp_test_req_wrong_uid),
414 : cmocka_unit_test_setup_teardown(test_el_to_dict,
415 : ifp_test_req_setup,
416 : ifp_test_req_teardown),
417 : cmocka_unit_test(test_attr_acl),
418 : cmocka_unit_test(test_attr_acl_ex),
419 : cmocka_unit_test(test_attr_allowed),
420 : };
421 :
422 : /* Set debug level to invalid value so we can deside if -d 0 was used. */
423 1 : debug_level = SSSDBG_INVALID;
424 :
425 1 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
426 1 : while((opt = poptGetNextOpt(pc)) != -1) {
427 : switch(opt) {
428 : default:
429 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
430 : poptBadOption(pc, 0), poptStrerror(opt));
431 0 : poptPrintUsage(pc, stderr, 0);
432 0 : return 1;
433 : }
434 : }
435 1 : poptFreeContext(pc);
436 :
437 1 : DEBUG_CLI_INIT(debug_level);
438 :
439 : /* Even though normally the tests should clean up after themselves
440 : * they might not after a failed run. Remove the old db to be sure */
441 1 : tests_set_cwd();
442 :
443 1 : return cmocka_run_group_tests(tests, NULL, NULL);
444 : }
|