libcli/ldap: Fix CID 1462695 Resource leak
[Samba.git] / libcli / ldap / tests / ldap_message_test.c
blob4050b7f1cb103ed1b5d88cdfe859c97ca784338d
1 /*
2 * Unit tests for ldap_message.
4 * Copyright (C) Catalyst.NET Ltd 2020
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.
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.
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/>.
22 * from cmocka.c:
23 * These headers or their equivalents should be included prior to
24 * including
25 * this header file.
27 * #include <stdarg.h>
28 * #include <stddef.h>
29 * #include <setjmp.h>
31 * This allows test applications to use custom definitions of C standard
32 * library functions and types.
35 #include <stdarg.h>
36 #include <stddef.h>
37 #include <setjmp.h>
38 #include <cmocka.h>
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"
47 * declare the internal cmocka cm_print so we can output messages in
48 * sub unit format
50 void cm_print_error(const char * const format, ...);
52 * helper function and macro to compare an ldap error code constant with the
53 * coresponding nt_status code
55 #define NT_STATUS_LDAP_V(code) (0xF2000000 | code)
56 static void _assert_ldap_status_equal(
57 int a,
58 NTSTATUS b,
59 const char * const file,
60 const int line)
62 _assert_int_equal(NT_STATUS_LDAP_V(a), NT_STATUS_V(b), file, line);
65 #define assert_ldap_status_equal(a, b) \
66 _assert_ldap_status_equal((a), (b), __FILE__, __LINE__)
69 * helper function and macro to assert there were no errors in the last
70 * file operation
72 static void _assert_not_ferror(
73 FILE *f,
74 const char * const file,
75 const int line)
77 if (f == NULL || ferror(f)) {
78 cm_print_error("ferror (%d) %s\n", errno, strerror(errno));
79 _fail(file, line);
83 #define assert_not_ferror(f) \
84 _assert_not_ferror((f), __FILE__, __LINE__)
86 struct test_ctx {
89 static int setup(void **state)
91 struct test_ctx *test_ctx;
93 test_ctx = talloc_zero(NULL, struct test_ctx);
94 *state = test_ctx;
95 return 0;
98 static int teardown(void **state)
100 struct test_ctx *test_ctx = talloc_get_type_abort(*state,
101 struct test_ctx);
103 TALLOC_FREE(test_ctx);
104 return 0;
108 * Test that an empty request is handled correctly
110 static void test_empty_input(void **state)
112 struct test_ctx *test_ctx = talloc_get_type_abort(
113 *state,
114 struct test_ctx);
115 struct asn1_data *asn1;
116 struct ldap_message *ldap_msg;
117 NTSTATUS status;
118 uint8_t *buf = NULL;
119 size_t len = 0;
120 struct ldap_request_limits limits = {
121 .max_search_size = 256000,
125 asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
126 assert_non_null(asn1);
128 asn1_load_nocopy(asn1, buf, len);
130 ldap_msg = talloc(test_ctx, struct ldap_message);
131 assert_non_null(ldap_msg);
133 status = ldap_decode(
134 asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
135 assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
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.
144 static void test_recursion_depth_large(void **state)
146 struct test_ctx *test_ctx = talloc_get_type_abort(
147 *state,
148 struct test_ctx);
149 struct asn1_data *asn1;
150 struct ldap_message *ldap_msg;
151 NTSTATUS status;
152 FILE *f = NULL;
153 uint8_t *buffer = NULL;
154 const size_t BUFF_SIZE = 1048576;
155 size_t len;
156 struct ldap_request_limits limits = {
157 .max_search_size = 256000,
162 * Load a test data file containg 10,000 or clauses in encoded as
163 * an ASN.1 packet.
165 buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
166 f = fopen("./libcli/ldap/tests/data/10000-or.dat", "r");
167 assert_not_ferror(f);
168 len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
169 assert_not_ferror(f);
170 assert_true(len > 0);
172 asn1 = asn1_init(test_ctx, ASN1_MAX_TREE_DEPTH);
173 assert_non_null(asn1);
174 asn1_load_nocopy(asn1, buffer, len);
176 ldap_msg = talloc(test_ctx, struct ldap_message);
177 assert_non_null(ldap_msg);
179 status = ldap_decode(
180 asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
181 assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
185 * Check that a request is not rejected it it's recursion depth equals the
186 * maximum value
188 static void test_recursion_depth_equals_max(void **state)
190 struct test_ctx *test_ctx = talloc_get_type_abort(
191 *state,
192 struct test_ctx);
193 struct asn1_data *asn1;
194 struct ldap_message *ldap_msg;
195 NTSTATUS status;
196 FILE *f = NULL;
197 uint8_t *buffer = NULL;
198 const size_t BUFF_SIZE = 1048576;
199 size_t len;
200 int ret;
201 struct ldap_request_limits limits = {
202 .max_search_size = 256000,
206 buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
207 f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r");
208 assert_not_ferror(f);
209 len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
210 assert_not_ferror(f);
211 assert_true(len > 0);
213 asn1 = asn1_init(test_ctx, 4);
214 assert_non_null(asn1);
215 asn1_load_nocopy(asn1, buffer, len);
217 ldap_msg = talloc(test_ctx, struct ldap_message);
218 assert_non_null(ldap_msg);
220 status = ldap_decode(
221 asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
222 assert_true(NT_STATUS_IS_OK(status));
224 ret = fclose(f);
225 f = NULL;
226 assert_true(ret == 0);
230 * Check that a request is rejected it it's recursion depth is greater than the
231 * maximum value
233 static void test_recursion_depth_greater_than_max(void **state)
235 struct test_ctx *test_ctx = talloc_get_type_abort(
236 *state,
237 struct test_ctx);
238 struct asn1_data *asn1;
239 struct ldap_message *ldap_msg;
240 NTSTATUS status;
241 FILE *f = NULL;
242 uint8_t *buffer = NULL;
243 const size_t BUFF_SIZE = 1048576;
244 size_t len;
245 int ret;
246 struct ldap_request_limits limits = {
247 .max_search_size = 256000,
251 buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
252 f = fopen("./libcli/ldap/tests/data/ldap-recursive.dat", "r");
253 assert_not_ferror(f);
254 len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
255 assert_not_ferror(f);
256 assert_true(len > 0);
258 asn1 = asn1_init(test_ctx, 3);
259 assert_non_null(asn1);
260 asn1_load_nocopy(asn1, buffer, len);
262 ldap_msg = talloc(test_ctx, struct ldap_message);
263 assert_non_null(ldap_msg);
265 status = ldap_decode(
266 asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
267 assert_ldap_status_equal(LDAP_PROTOCOL_ERROR, status);
269 ret = fclose(f);
270 f = NULL;
271 assert_true(ret == 0);
275 * Check we can decode an exop response
277 static void test_decode_exop_response(void **state)
279 struct test_ctx *test_ctx = talloc_get_type_abort(
280 *state,
281 struct test_ctx);
282 struct asn1_data *asn1;
283 struct ldap_message *ldap_msg;
284 NTSTATUS status;
285 FILE *f = NULL;
286 uint8_t *buffer = NULL;
287 const size_t BUFF_SIZE = 1048576;
288 size_t len;
289 int ret;
290 struct ldap_request_limits limits = {
291 .max_search_size = 256000,
295 buffer = talloc_zero_array(test_ctx, uint8_t, BUFF_SIZE);
296 f = fopen("./libcli/ldap/tests/data/ldap-starttls-response.dat", "r");
297 assert_not_ferror(f);
298 len = fread(buffer, sizeof(uint8_t), BUFF_SIZE, f);
299 assert_not_ferror(f);
300 assert_true(len > 0);
302 asn1 = asn1_init(test_ctx, 3);
303 assert_non_null(asn1);
304 asn1_load_nocopy(asn1, buffer, len);
306 ldap_msg = talloc(test_ctx, struct ldap_message);
307 assert_non_null(ldap_msg);
309 status = ldap_decode(
310 asn1, &limits, samba_ldap_control_handlers(), ldap_msg);
311 assert_true(NT_STATUS_IS_OK(status));
313 ret = fclose(f);
314 f = NULL;
315 assert_true(ret == 0);
318 int main(_UNUSED_ int argc, _UNUSED_ const char **argv)
320 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),
343 cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
344 return cmocka_run_group_tests(tests, NULL, NULL);