Line data Source code
1 : /*
2 : * Unit tests for ldap_message.
3 : *
4 : * Copyright (C) Catalyst.NET Ltd 2020
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 :
21 : /*
22 : * from cmocka.c:
23 : * These headers or their equivalents should be included prior to
24 : * including
25 : * this header file.
26 : *
27 : * #include <stdarg.h>
28 : * #include <stddef.h>
29 : * #include <setjmp.h>
30 : *
31 : * This allows test applications to use custom definitions of C standard
32 : * library functions and types.
33 : *
34 : */
35 : #include <stdarg.h>
36 : #include <stddef.h>
37 : #include <setjmp.h>
38 : #include <cmocka.h>
39 :
40 : #include "lib/util/attr.h"
41 : #include "includes.h"
42 : #include "lib/util/asn1.h"
43 : #include "libcli/ldap/ldap_message.h"
44 : #include "libcli/ldap/ldap_proto.h"
45 :
46 : /*
47 : * declare the internal cmocka cm_print so we can output messages in
48 : * sub unit format
49 : */
50 : void cm_print_error(const char * const format, ...);
51 : /*
52 : * helper function and macro to compare an ldap error code constant with the
53 : * corresponding nt_status code
54 : */
55 : #define NT_STATUS_LDAP_V(code) (0xF2000000 | code)
56 3 : static void _assert_ldap_status_equal(
57 : int a,
58 : NTSTATUS b,
59 : const char * const file,
60 : const int line)
61 : {
62 3 : _assert_int_equal(NT_STATUS_LDAP_V(a), NT_STATUS_V(b), file, line);
63 : }
64 :
65 : #define assert_ldap_status_equal(a, b) \
66 : _assert_ldap_status_equal((a), (b), __FILE__, __LINE__)
67 :
68 : /*
69 : * helper function and macro to assert there were no errors in the last
70 : * file operation
71 : */
72 8 : static void _assert_not_ferror(
73 : FILE *f,
74 : const char * const file,
75 : const int line)
76 : {
77 8 : if (f == NULL || ferror(f)) {
78 0 : cm_print_error("ferror (%d) %s\n", errno, strerror(errno));
79 0 : _fail(file, line);
80 : }
81 8 : }
82 :
83 : #define assert_not_ferror(f) \
84 : _assert_not_ferror((f), __FILE__, __LINE__)
85 :
86 : struct test_ctx {
87 : };
88 :
89 5 : static int setup(void **state)
90 : {
91 5 : struct test_ctx *test_ctx;
92 :
93 5 : test_ctx = talloc_zero(NULL, struct test_ctx);
94 5 : *state = test_ctx;
95 5 : return 0;
96 : }
97 :
98 5 : static int teardown(void **state)
99 : {
100 5 : struct test_ctx *test_ctx = talloc_get_type_abort(*state,
101 : struct test_ctx);
102 :
103 5 : TALLOC_FREE(test_ctx);
104 5 : return 0;
105 : }
106 :
107 : /*
108 : * Test that an empty request is handled correctly
109 : */
110 1 : static void test_empty_input(void **state)
111 : {
112 1 : struct test_ctx *test_ctx = talloc_get_type_abort(
113 : *state,
114 : struct test_ctx);
115 1 : struct asn1_data *asn1;
116 1 : struct ldap_message *ldap_msg;
117 1 : NTSTATUS status;
118 1 : uint8_t *buf = NULL;
119 1 : size_t len = 0;
120 1 : struct ldap_request_limits limits = {
121 : .max_search_size = 256000,
122 : };
123 :
124 :
125 1 : asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
126 1 : assert_non_null(asn1);
127 :
128 1 : asn1_load_nocopy(asn1, buf, len);
129 :
130 1 : ldap_msg = talloc(test_ctx, struct ldap_message);
131 1 : assert_non_null(ldap_msg);
132 :
133 1 : status = ldap_decode(
134 : asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
135 1 : assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
136 1 : }
137 :
138 : /*
139 : * Check that a request is rejected it it's recursion depth exceeds
140 : * the maximum value specified. This test uses a very deeply nested query,
141 : * 10,000 or clauses.
142 : *
143 : */
144 1 : static void test_recursion_depth_large(void **state)
145 : {
146 1 : struct test_ctx *test_ctx = talloc_get_type_abort(
147 : *state,
148 : struct test_ctx);
149 1 : struct asn1_data *asn1;
150 1 : struct ldap_message *ldap_msg;
151 1 : NTSTATUS status;
152 1 : FILE *f = NULL;
153 1 : uint8_t *buffer = NULL;
154 1 : const size_t BUFF_SIZE = 1048576;
155 1 : size_t len;
156 1 : struct ldap_request_limits limits = {
157 : .max_search_size = 256000,
158 : };
159 :
160 :
161 : /*
162 : * Load a test data file containing 10,000 or clauses in encoded as
163 : * an ASN.1 packet.
164 : */
165 1 : buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
166 1 : f = fopen("./libcli/ldap/tests/data/10000-or.dat", "r");
167 1 : assert_not_ferror(f);
168 1 : len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
169 1 : assert_not_ferror(f);
170 1 : assert_true(len > 0);
171 :
172 1 : asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
173 1 : assert_non_null(asn1);
174 1 : asn1_load_nocopy(asn1, buffer, len);
175 :
176 1 : ldap_msg = talloc(test_ctx, struct ldap_message);
177 1 : assert_non_null(ldap_msg);
178 :
179 1 : status = ldap_decode(
180 : asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
181 1 : assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
182 1 : }
183 :
184 : /*
185 : * Check that a request is not rejected it it's recursion depth equals the
186 : * maximum value
187 : */
188 1 : static void test_recursion_depth_equals_max(void **state)
189 : {
190 1 : struct test_ctx *test_ctx = talloc_get_type_abort(
191 : *state,
192 : struct test_ctx);
193 1 : struct asn1_data *asn1;
194 1 : struct ldap_message *ldap_msg;
195 1 : NTSTATUS status;
196 1 : FILE *f = NULL;
197 1 : uint8_t *buffer = NULL;
198 1 : const size_t BUFF_SIZE = 1048576;
199 1 : size_t len;
200 1 : int ret;
201 1 : struct ldap_request_limits limits = {
202 : .max_search_size = 256000,
203 : };
204 :
205 :
206 1 : buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
207 1 : f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r");
208 1 : assert_not_ferror(f);
209 1 : len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
210 1 : assert_not_ferror(f);
211 1 : assert_true(len > 0);
212 :
213 1 : asn1 = asn1_init(test_ctx, 4);
214 1 : assert_non_null(asn1);
215 1 : asn1_load_nocopy(asn1, buffer, len);
216 :
217 1 : ldap_msg = talloc(test_ctx, struct ldap_message);
218 1 : assert_non_null(ldap_msg);
219 :
220 1 : status = ldap_decode(
221 : asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
222 1 : assert_true(NT_STATUS_IS_OK(status));
223 :
224 1 : ret = fclose(f);
225 1 : f = NULL;
226 1 : assert_true(ret == 0);
227 1 : }
228 :
229 : /*
230 : * Check that a request is rejected it it's recursion depth is greater than the
231 : * maximum value
232 : */
233 1 : static void test_recursion_depth_greater_than_max(void **state)
234 : {
235 1 : struct test_ctx *test_ctx = talloc_get_type_abort(
236 : *state,
237 : struct test_ctx);
238 1 : struct asn1_data *asn1;
239 1 : struct ldap_message *ldap_msg;
240 1 : NTSTATUS status;
241 1 : FILE *f = NULL;
242 1 : uint8_t *buffer = NULL;
243 1 : const size_t BUFF_SIZE = 1048576;
244 1 : size_t len;
245 1 : int ret;
246 1 : struct ldap_request_limits limits = {
247 : .max_search_size = 256000,
248 : };
249 :
250 :
251 1 : buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
252 1 : f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r");
253 1 : assert_not_ferror(f);
254 1 : len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
255 1 : assert_not_ferror(f);
256 1 : assert_true(len > 0);
257 :
258 1 : asn1 = asn1_init(test_ctx, 3);
259 1 : assert_non_null(asn1);
260 1 : asn1_load_nocopy(asn1, buffer, len);
261 :
262 1 : ldap_msg = talloc(test_ctx, struct ldap_message);
263 1 : assert_non_null(ldap_msg);
264 :
265 1 : status = ldap_decode(
266 : asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
267 1 : assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
268 :
269 1 : ret = fclose(f);
270 1 : f = NULL;
271 1 : assert_true(ret == 0);
272 1 : }
273 :
274 : /*
275 : * Check we can decode an exop response
276 : */
277 1 : static void test_decode_exop_response(void **state)
278 : {
279 1 : struct test_ctx *test_ctx = talloc_get_type_abort(
280 : *state,
281 : struct test_ctx);
282 1 : struct asn1_data *asn1;
283 1 : struct ldap_message *ldap_msg;
284 1 : NTSTATUS status;
285 1 : FILE *f = NULL;
286 1 : uint8_t *buffer = NULL;
287 1 : const size_t BUFF_SIZE = 1048576;
288 1 : size_t len;
289 1 : int ret;
290 1 : struct ldap_request_limits limits = {
291 : .max_search_size = 256000,
292 : };
293 :
294 :
295 1 : buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
296 1 : f = fopen("./libcli/ldap/tests/data/ldap-starttls-response.dat", "r");
297 1 : assert_not_ferror(f);
298 1 : len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
299 1 : assert_not_ferror(f);
300 1 : assert_true(len > 0);
301 :
302 1 : asn1 = asn1_init(test_ctx, 3);
303 1 : assert_non_null(asn1);
304 1 : asn1_load_nocopy(asn1, buffer, len);
305 :
306 1 : ldap_msg = talloc(test_ctx, struct ldap_message);
307 1 : assert_non_null(ldap_msg);
308 :
309 1 : status = ldap_decode(
310 : asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
311 1 : assert_true(NT_STATUS_IS_OK(status));
312 :
313 1 : ret = fclose(f);
314 1 : f = NULL;
315 1 : assert_true(ret == 0);
316 1 : }
317 :
318 1 : int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
319 : {
320 1 : const struct CMUnitTest tests[] = {
321 : cmocka_unit_test_setup_teardown(
322 : test_empty_input,
323 : setup,
324 : teardown),
325 : cmocka_unit_test_setup_teardown(
326 : test_recursion_depth_large,
327 : setup,
328 : teardown),
329 : cmocka_unit_test_setup_teardown(
330 : test_recursion_depth_equals_max,
331 : setup,
332 : teardown),
333 : cmocka_unit_test_setup_teardown(
334 : test_recursion_depth_greater_than_max,
335 : setup,
336 : teardown),
337 : cmocka_unit_test_setup_teardown(
338 : test_decode_exop_response,
339 : setup,
340 : teardown),
341 : };
342 :
343 1 : cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
344 1 : return cmocka_run_group_tests(tests, NULL, NULL);
345 : }
|