Line data Source code
1 : /*
2 : Copyright (C) 2015 Red Hat
3 :
4 : SSSD tests: Kerberos wait queue tests
5 :
6 : This program is free software; you can redistribute it and/or modify
7 : it under the terms of the GNU General Public License as published by
8 : the Free Software Foundation; either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : This program is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU General Public License for more details.
15 :
16 : You should have received a copy of the GNU General Public License
17 : along with this program. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <talloc.h>
21 : #include <tevent.h>
22 : #include <errno.h>
23 : #include <popt.h>
24 : #include <stdlib.h>
25 : #include <security/pam_modules.h>
26 :
27 : #include "util/util.h"
28 : #include "providers/krb5/krb5_common.h"
29 : #include "providers/krb5/krb5_auth.h"
30 : #include "tests/cmocka/common_mock.h"
31 : #include "tests/cmocka/common_mock_be.h"
32 :
33 : struct krb5_mocked_auth_state {
34 : const char *user;
35 : time_t us_delay;
36 : int ret;
37 : int pam_status;
38 : int dp_err;
39 : };
40 :
41 : static void krb5_mocked_auth_done(struct tevent_context *ev,
42 : struct tevent_timer *tt,
43 : struct timeval tv,
44 : void *pvt);
45 :
46 1011 : struct tevent_req *krb5_auth_send(TALLOC_CTX *mem_ctx,
47 : struct tevent_context *ev,
48 : struct be_ctx *be_ctx,
49 : struct pam_data *pd,
50 : struct krb5_ctx *krb5_ctx)
51 : {
52 : struct tevent_req *req;
53 : struct krb5_mocked_auth_state *state;
54 : struct tevent_timer *tt;
55 : struct timeval tv;
56 :
57 1011 : req = tevent_req_create(mem_ctx, &state, struct krb5_mocked_auth_state);
58 1011 : if (req == NULL) {
59 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
60 0 : return NULL;
61 : }
62 :
63 1011 : state->user = sss_mock_ptr_type(const char *);
64 1011 : state->us_delay = sss_mock_type(time_t);
65 1011 : state->ret = sss_mock_type(int);
66 1011 : state->pam_status = sss_mock_type(int);
67 1011 : state->dp_err = sss_mock_type(int);
68 :
69 1011 : tv = tevent_timeval_current_ofs(0, state->us_delay);
70 :
71 1011 : tt = tevent_add_timer(ev, req, tv, krb5_mocked_auth_done, req);
72 1011 : if (tt == NULL) {
73 0 : return NULL;
74 : }
75 :
76 1011 : return req;
77 : }
78 :
79 1011 : static void krb5_mocked_auth_done(struct tevent_context *ev,
80 : struct tevent_timer *tt,
81 : struct timeval tv,
82 : void *pvt)
83 : {
84 : struct tevent_req *req;
85 : struct krb5_mocked_auth_state *state;
86 :
87 1011 : req = talloc_get_type(pvt, struct tevent_req);
88 1011 : state = tevent_req_data(req, struct krb5_mocked_auth_state);
89 :
90 1011 : DEBUG(SSSDBG_TRACE_LIBS, "Finished auth request of %s\n", state->user);
91 :
92 1011 : if (state->ret == 0) {
93 1001 : tevent_req_done(req);
94 : } else {
95 10 : tevent_req_error(req, state->ret);
96 : }
97 1011 : }
98 :
99 1011 : int krb5_auth_recv(struct tevent_req *req,
100 : int *_pam_status,
101 : int *_dp_err)
102 : {
103 : struct krb5_mocked_auth_state *state;
104 :
105 1011 : state = tevent_req_data(req, struct krb5_mocked_auth_state);
106 :
107 1011 : if (_pam_status != NULL) {
108 1011 : *_pam_status = state->pam_status;
109 : }
110 :
111 1011 : if (_dp_err != NULL) {
112 1011 : *_dp_err = state->dp_err;
113 : }
114 :
115 1021 : TEVENT_REQ_RETURN_ON_ERROR(req);
116 1001 : return EOK;
117 : }
118 :
119 : struct test_krb5_wait_queue {
120 : struct sss_test_ctx *tctx;
121 : int num_auths;
122 : int num_finished_auths;
123 :
124 : struct be_ctx *be_ctx;
125 : struct pam_data *pd;
126 : struct krb5_ctx *krb5_ctx;
127 : };
128 :
129 3 : static int test_krb5_wait_queue_setup(void **state)
130 : {
131 : struct test_krb5_wait_queue *test_ctx;
132 :
133 3 : test_ctx = talloc_zero(global_talloc_context,
134 : struct test_krb5_wait_queue);
135 3 : assert_non_null(test_ctx);
136 :
137 3 : test_ctx->tctx = create_ev_test_ctx(test_ctx);
138 3 : assert_non_null(test_ctx);
139 :
140 3 : test_ctx->be_ctx = mock_be_ctx(test_ctx, test_ctx->tctx);
141 3 : assert_non_null(test_ctx->be_ctx);
142 :
143 3 : test_ctx->pd = talloc_zero(test_ctx, struct pam_data);
144 3 : assert_non_null(test_ctx->pd);
145 :
146 3 : test_ctx->krb5_ctx = talloc_zero(test_ctx, struct krb5_ctx);
147 3 : assert_non_null(test_ctx->krb5_ctx);
148 :
149 3 : *state = test_ctx;
150 3 : return 0;
151 : }
152 :
153 3 : static int test_krb5_wait_queue_teardown(void **state)
154 : {
155 3 : struct test_krb5_wait_queue *test_ctx =
156 3 : talloc_get_type(*state, struct test_krb5_wait_queue);
157 :
158 3 : talloc_free(test_ctx);
159 3 : return 0;
160 : }
161 :
162 1011 : static void test_krb5_wait_mock(struct test_krb5_wait_queue *test_ctx,
163 : const char *username,
164 : time_t us_delay,
165 : int ret,
166 : int pam_status,
167 : int dp_err)
168 : {
169 1011 : test_ctx->pd->user = discard_const(username);
170 :
171 1011 : will_return(krb5_auth_send, username);
172 1011 : will_return(krb5_auth_send, us_delay);
173 1011 : will_return(krb5_auth_send, ret);
174 1011 : will_return(krb5_auth_send, pam_status);
175 1011 : will_return(krb5_auth_send, dp_err);
176 1011 : }
177 :
178 1001 : static void test_krb5_wait_mock_success(struct test_krb5_wait_queue *test_ctx,
179 : const char *username)
180 : {
181 1001 : return test_krb5_wait_mock(test_ctx, username, 200, 0, 0, 0);
182 : }
183 :
184 : static void test_krb5_wait_queue_single_done(struct tevent_req *req);
185 :
186 1 : static void test_krb5_wait_queue_single(void **state)
187 : {
188 : errno_t ret;
189 : struct tevent_req *req;
190 1 : struct test_krb5_wait_queue *test_ctx =
191 1 : talloc_get_type(*state, struct test_krb5_wait_queue);
192 :
193 1 : test_krb5_wait_mock_success(test_ctx, "krb5_user");
194 :
195 2 : req = krb5_auth_queue_send(test_ctx,
196 1 : test_ctx->tctx->ev,
197 : test_ctx->be_ctx,
198 : test_ctx->pd,
199 : test_ctx->krb5_ctx);
200 1 : assert_non_null(req);
201 1 : tevent_req_set_callback(req, test_krb5_wait_queue_single_done, test_ctx);
202 :
203 1 : ret = test_ev_loop(test_ctx->tctx);
204 1 : assert_int_equal(ret, EOK);
205 1 : }
206 :
207 1 : static void test_krb5_wait_queue_single_done(struct tevent_req *req)
208 : {
209 1 : struct test_krb5_wait_queue *test_ctx = \
210 1 : tevent_req_callback_data(req, struct test_krb5_wait_queue);
211 : errno_t ret;
212 : int pam_status;
213 : int dp_err;
214 :
215 1 : ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
216 1 : talloc_free(req);
217 1 : assert_int_equal(ret, EOK);
218 :
219 1 : test_ev_done(test_ctx->tctx, EOK);
220 1 : }
221 :
222 : static void test_krb5_wait_queue_multi_done(struct tevent_req *req);
223 :
224 1 : static void test_krb5_wait_queue_multi(void **state)
225 : {
226 : int i;
227 : errno_t ret;
228 : struct tevent_req *req;
229 1 : struct test_krb5_wait_queue *test_ctx =
230 1 : talloc_get_type(*state, struct test_krb5_wait_queue);
231 :
232 1 : test_ctx->num_auths = 1000;
233 :
234 1001 : for (i=0; i < test_ctx->num_auths; i++) {
235 1000 : test_krb5_wait_mock_success(test_ctx, "krb5_user");
236 :
237 2000 : req = krb5_auth_queue_send(test_ctx,
238 1000 : test_ctx->tctx->ev,
239 : test_ctx->be_ctx,
240 : test_ctx->pd,
241 : test_ctx->krb5_ctx);
242 1000 : assert_non_null(req);
243 1000 : tevent_req_set_callback(req, test_krb5_wait_queue_multi_done, test_ctx);
244 : }
245 :
246 1 : ret = test_ev_loop(test_ctx->tctx);
247 1 : assert_int_equal(ret, EOK);
248 1 : }
249 :
250 1000 : static void test_krb5_wait_queue_multi_done(struct tevent_req *req)
251 : {
252 1000 : struct test_krb5_wait_queue *test_ctx = \
253 1000 : tevent_req_callback_data(req, struct test_krb5_wait_queue);
254 : errno_t ret;
255 : int pam_status;
256 : int dp_err;
257 :
258 1000 : ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
259 1000 : talloc_free(req);
260 1000 : assert_int_equal(ret, EOK);
261 :
262 1000 : test_ctx->num_finished_auths++;
263 :
264 1000 : if (test_ctx->num_finished_auths == test_ctx->num_auths) {
265 1 : test_ev_done(test_ctx->tctx, EOK);
266 : }
267 1000 : }
268 :
269 : static void test_krb5_wait_queue_fail_odd_done(struct tevent_req *req);
270 :
271 1 : static void test_krb5_wait_queue_fail_odd(void **state)
272 : {
273 : int i;
274 : errno_t ret;
275 : struct tevent_req *req;
276 1 : struct test_krb5_wait_queue *test_ctx =
277 1 : talloc_get_type(*state, struct test_krb5_wait_queue);
278 :
279 1 : test_ctx->num_auths = 10;
280 :
281 11 : for (i=0; i < test_ctx->num_auths; i++) {
282 10 : test_krb5_wait_mock(test_ctx, "krb5_user", 0, i+1 % 2, PAM_SUCCESS, 0);
283 :
284 20 : req = krb5_auth_queue_send(test_ctx,
285 10 : test_ctx->tctx->ev,
286 : test_ctx->be_ctx,
287 : test_ctx->pd,
288 : test_ctx->krb5_ctx);
289 10 : assert_non_null(req);
290 10 : tevent_req_set_callback(req, test_krb5_wait_queue_fail_odd_done, test_ctx);
291 : }
292 :
293 1 : ret = test_ev_loop(test_ctx->tctx);
294 1 : assert_int_equal(ret, EOK);
295 1 : }
296 :
297 10 : static void test_krb5_wait_queue_fail_odd_done(struct tevent_req *req)
298 : {
299 10 : struct test_krb5_wait_queue *test_ctx = \
300 10 : tevent_req_callback_data(req, struct test_krb5_wait_queue);
301 : errno_t ret;
302 : int pam_status;
303 : int dp_err;
304 :
305 10 : ret = krb5_auth_queue_recv(req, &pam_status, &dp_err);
306 10 : talloc_free(req);
307 10 : assert_int_equal(ret, test_ctx->num_finished_auths+1 % 2);
308 :
309 10 : test_ctx->num_finished_auths++;
310 :
311 10 : if (test_ctx->num_finished_auths == test_ctx->num_auths) {
312 1 : test_ev_done(test_ctx->tctx, EOK);
313 : }
314 10 : }
315 :
316 1 : int main(int argc, const char *argv[])
317 : {
318 : poptContext pc;
319 : int opt;
320 6 : struct poptOption long_options[] = {
321 : POPT_AUTOHELP
322 5 : SSSD_DEBUG_OPTS
323 : POPT_TABLEEND
324 : };
325 :
326 1 : const struct CMUnitTest tests[] = {
327 : /* Run a single auth request */
328 : cmocka_unit_test_setup_teardown(test_krb5_wait_queue_single,
329 : test_krb5_wait_queue_setup,
330 : test_krb5_wait_queue_teardown),
331 :
332 : /* Run multiple auth requests */
333 : cmocka_unit_test_setup_teardown(test_krb5_wait_queue_multi,
334 : test_krb5_wait_queue_setup,
335 : test_krb5_wait_queue_teardown),
336 :
337 : /* Make sure that all requests in queue run even if some fail */
338 : cmocka_unit_test_setup_teardown(test_krb5_wait_queue_fail_odd,
339 : test_krb5_wait_queue_setup,
340 : test_krb5_wait_queue_teardown),
341 : };
342 :
343 : /* Set debug level to invalid value so we can deside if -d 0 was used. */
344 1 : debug_level = SSSDBG_INVALID;
345 :
346 1 : pc = poptGetContext(argv[0], argc, argv, long_options, 0);
347 1 : while((opt = poptGetNextOpt(pc)) != -1) {
348 : switch(opt) {
349 : default:
350 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
351 : poptBadOption(pc, 0), poptStrerror(opt));
352 0 : poptPrintUsage(pc, stderr, 0);
353 0 : return 1;
354 : }
355 : }
356 1 : poptFreeContext(pc);
357 :
358 1 : DEBUG_CLI_INIT(debug_level);
359 :
360 : /* Even though normally the tests should clean up after themselves
361 : * they might not after a failed run. Remove the old db to be sure */
362 1 : tests_set_cwd();
363 :
364 1 : return cmocka_run_group_tests(tests, NULL, NULL);
365 : }
|