LCOV - code coverage report
Current view: top level - libcli/ldap/tests - ldap_message_test.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 142 144 98.6 %
Date: 2024-02-28 12:06:22 Functions: 9 9 100.0 %

          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             : }

Generated by: LCOV version 1.14