LCOV - code coverage report
Current view: top level - source4/torture/smb2 - credits.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 105 137 76.6 %
Date: 2024-04-21 15:09:00 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    test suite for SMB2 credits
       5             : 
       6             :    Copyright (C) Ralph Boehme 2017
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "libcli/smb2/smb2.h"
      24             : #include "libcli/smb2/smb2_calls.h"
      25             : #include "torture/torture.h"
      26             : #include "torture/smb2/proto.h"
      27             : #include "../libcli/smb/smbXcli_base.h"
      28             : #include "lib/param/param.h"
      29             : 
      30             : /**
      31             :  * Request 64k credits in negprot/sessionsetup and require at least 8k
      32             :  *
      33             :  * This passes against Windows 2016
      34             :  **/
      35           6 : static bool test_session_setup_credits_granted(struct torture_context *tctx,
      36             :                                                struct smb2_tree *_tree)
      37             : {
      38           0 :         struct smbcli_options options;
      39           6 :         struct smb2_transport *transport = NULL;
      40           6 :         struct smb2_tree *tree = NULL;
      41           0 :         uint16_t cur_credits;
      42           0 :         NTSTATUS status;
      43           6 :         bool ret = true;
      44             : 
      45           6 :         transport = _tree->session->transport;
      46           6 :         options = transport->options;
      47             : 
      48           6 :         status = smb2_logoff(_tree->session);
      49           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
      50             :                                         "smb2_logoff failed\n");
      51           6 :         TALLOC_FREE(_tree);
      52             : 
      53           6 :         options.max_credits = 65535;
      54             : 
      55           6 :         ret = torture_smb2_connection_ext(tctx, 0, &options, &tree);
      56           6 :         torture_assert_goto(tctx, ret == true, ret, done,
      57             :                             "torture_smb2_connection_ext failed\n");
      58             : 
      59           6 :         transport = tree->session->transport;
      60             : 
      61           6 :         cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
      62           6 :         if (cur_credits < 8192) {
      63           0 :                 torture_result(tctx, TORTURE_FAIL,
      64             :                                "Server only granted %" PRIu16" credits\n",
      65             :                                cur_credits);
      66           0 :                 ret = false;
      67           0 :                 goto done;
      68             :         }
      69             : 
      70           6 : done:
      71           6 :         TALLOC_FREE(tree);
      72           6 :         return ret;
      73             : }
      74             : 
      75             : /**
      76             :  * Request 64K credits in a single SMB2 request and requite at least 8192
      77             :  *
      78             :  * This passes against Windows 2016
      79             :  **/
      80           6 : static bool test_single_req_credits_granted(struct torture_context *tctx,
      81             :                                             struct smb2_tree *_tree)
      82             : {
      83           0 :         struct smbcli_options options;
      84           6 :         struct smb2_transport *transport = NULL;
      85           6 :         struct smb2_tree *tree = NULL;
      86           6 :         struct smb2_handle h = {{0}};
      87           0 :         struct smb2_create create;
      88           6 :         const char *fname = "single_req_credits_granted.dat";
      89           0 :         uint16_t cur_credits;
      90           0 :         NTSTATUS status;
      91           6 :         bool ret = true;
      92             : 
      93           6 :         smb2_util_unlink(_tree, fname);
      94             : 
      95           6 :         transport = _tree->session->transport;
      96           6 :         options = transport->options;
      97             : 
      98           6 :         status = smb2_logoff(_tree->session);
      99           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     100             :                                         "smb2_logoff failed\n");
     101           6 :         TALLOC_FREE(_tree);
     102             : 
     103           6 :         options.max_credits = 1;
     104             : 
     105           6 :         ret = torture_smb2_connection_ext(tctx, 0, &options, &tree);
     106           6 :         torture_assert_goto(tctx, ret == true, ret, done,
     107             :                             "torture_smb2_connection_ext failed\n");
     108             : 
     109           6 :         transport = tree->session->transport;
     110             : 
     111           6 :         cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
     112           6 :         if (cur_credits != 1) {
     113           0 :                 torture_result(tctx, TORTURE_FAIL,
     114             :                                "Only wanted 1 credit but server granted %" PRIu16"\n",
     115             :                                cur_credits);
     116           0 :                 ret = false;
     117           0 :                 goto done;
     118             :         }
     119             : 
     120           6 :         smb2cli_conn_set_max_credits(transport->conn, 65535);
     121             : 
     122           6 :         ZERO_STRUCT(create);
     123           6 :         create.in.impersonation_level   = NTCREATEX_IMPERSONATION_IMPERSONATION;
     124           6 :         create.in.desired_access        = SEC_RIGHTS_FILE_ALL;
     125           6 :         create.in.file_attributes       = FILE_ATTRIBUTE_NORMAL;
     126           6 :         create.in.create_disposition    = NTCREATEX_DISP_OPEN_IF;
     127           6 :         create.in.fname                 = fname;
     128             : 
     129           6 :         status = smb2_create(tree, tctx, &create);
     130           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
     131             :                                         "smb2_create failed\n");
     132           6 :         h = create.out.file.handle;
     133             : 
     134           6 :         cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
     135           6 :         if (cur_credits < 8192) {
     136           0 :                 torture_result(tctx, TORTURE_FAIL,
     137             :                                "Server only granted %" PRIu16" credits\n",
     138             :                                cur_credits);
     139           0 :                 ret = false;
     140           0 :                 goto done;
     141             :         }
     142             : 
     143           6 : done:
     144           6 :         if (!smb2_util_handle_empty(h)) {
     145           6 :                 smb2_util_close(tree, h);
     146             :         }
     147           6 :         smb2_util_unlink(tree, fname);
     148           6 :         TALLOC_FREE(tree);
     149           6 :         return ret;
     150             : }
     151             : 
     152           6 : static bool test_crediting_skipped_mid(struct torture_context *tctx,
     153             :                                        struct smb2_tree *_tree)
     154             : {
     155           0 :         struct smbcli_options options;
     156           6 :         struct smb2_transport *transport = NULL;
     157           6 :         struct smb2_tree *tree = NULL;
     158           6 :         struct smb2_handle h = {{0}};
     159           0 :         struct smb2_create create;
     160           6 :         const char *fname = "skipped_mid.dat";
     161           0 :         uint64_t mid;
     162           0 :         uint16_t cur_credits;
     163           0 :         NTSTATUS status;
     164           6 :         bool ret = true;
     165           0 :         int i;
     166             : 
     167           6 :         smb2_util_unlink(_tree, fname);
     168             : 
     169           6 :         transport = _tree->session->transport;
     170           6 :         options = transport->options;
     171             : 
     172           6 :         status = smb2_logoff(_tree->session);
     173           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_logoff failed\n");
     174           6 :         TALLOC_FREE(_tree);
     175             : 
     176           6 :         options.max_credits = 8192;
     177             : 
     178           6 :         ret = torture_smb2_connection_ext(tctx, 0, &options, &tree);
     179           6 :         torture_assert_goto(tctx, ret == true, ret, done, "torture_smb2_connection_ext failed\n");
     180             : 
     181           6 :         transport = tree->session->transport;
     182             : 
     183           6 :         cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
     184           6 :         if (cur_credits != 8192) {
     185           0 :                 torture_result(tctx, TORTURE_FAIL, "Server only granted %" PRIu16" credits\n", cur_credits);
     186           0 :                 ret = false;
     187           0 :                 goto done;
     188             :         }
     189             : 
     190           6 :         ZERO_STRUCT(create);
     191           6 :         create.in.impersonation_level   = NTCREATEX_IMPERSONATION_IMPERSONATION;
     192           6 :         create.in.desired_access        = SEC_RIGHTS_FILE_ALL;
     193           6 :         create.in.file_attributes       = FILE_ATTRIBUTE_NORMAL;
     194           6 :         create.in.create_disposition    = NTCREATEX_DISP_OPEN_IF;
     195           6 :         create.in.fname                 = fname;
     196             : 
     197           6 :         status = smb2_create(tree, tctx, &create);
     198           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_create failed\n");
     199           6 :         h = create.out.file.handle;
     200             : 
     201             :         /*
     202             :          * See what happens if we skip a mid. As we want to avoid triggering our
     203             :          * client side mid window check we keep conn->smb2.cur_credits
     204             :          * unchanged so the server keeps granting credits until it's max mid
     205             :          * windows size is reached at which point it will disconnect us:
     206             :          *
     207             :          * o Windows 2016 currently has a maximum mid window size of 8192 by
     208             :          *   default
     209             :          *
     210             :          * o Samba's limit is 512
     211             :          *
     212             :          * o Windows 2008r2 uses some special algorithm (MS-SMB2 3.3.1.1
     213             :          *   footnote <167>) that kicks in once a mid is skipped, resulting in a
     214             :          *   maximum window size of 100-300 depending on the number of granted
     215             :          *   credits at the moment of skipping a mid.
     216             :          */
     217             : 
     218           6 :         mid = smb2cli_conn_get_mid(tree->session->transport->conn);
     219           6 :         smb2cli_conn_set_mid(tree->session->transport->conn, mid + 1);
     220             : 
     221       49152 :         for (i = 0; i < 8191; i++) {
     222       49146 :                 status = smb2_util_write(tree, h, "\0", 0, 1);
     223       49146 :                 if (!NT_STATUS_IS_OK(status)) {
     224           0 :                         torture_result(tctx, TORTURE_FAIL, "Server only allowed %d writes\n", i);
     225           0 :                         ret = false;
     226           0 :                         goto done;
     227             :                 }
     228             :         }
     229             : 
     230             :         /*
     231             :          * Now use the skipped mid (the smb2_util_close...), we should
     232             :          * immediately get a full mid window of size 8192.
     233             :          */
     234           6 :         smb2cli_conn_set_mid(tree->session->transport->conn, mid);
     235           6 :         status = smb2_util_close(tree, h);
     236           6 :         torture_assert_ntstatus_ok_goto(tctx, status, ret, done, "smb2_close failed\n");
     237           6 :         ZERO_STRUCT(h);
     238             : 
     239           6 :         cur_credits = smb2cli_conn_get_cur_credits(transport->conn);
     240           6 :         if (cur_credits != 8192) {
     241           0 :                 torture_result(tctx, TORTURE_FAIL, "Server only granted %" PRIu16" credits\n", cur_credits);
     242           0 :                 ret = false;
     243           0 :                 goto done;
     244             :         }
     245             : 
     246           6 :         smb2cli_conn_set_mid(tree->session->transport->conn, mid + 8192);
     247             : 
     248           6 : done:
     249           6 :         if (!smb2_util_handle_empty(h)) {
     250           0 :                 smb2_util_close(tree, h);
     251             :         }
     252           6 :         smb2_util_unlink(tree, fname);
     253           6 :         TALLOC_FREE(tree);
     254           6 :         return ret;
     255             : }
     256             : 
     257        2354 : struct torture_suite *torture_smb2_crediting_init(TALLOC_CTX *ctx)
     258             : {
     259        2354 :         struct torture_suite *suite = torture_suite_create(ctx, "credits");
     260             : 
     261        2354 :         torture_suite_add_1smb2_test(suite, "session_setup_credits_granted", test_session_setup_credits_granted);
     262        2354 :         torture_suite_add_1smb2_test(suite, "single_req_credits_granted", test_single_req_credits_granted);
     263        2354 :         torture_suite_add_1smb2_test(suite, "skipped_mid", test_crediting_skipped_mid);
     264             : 
     265        2354 :         suite->description = talloc_strdup(suite, "SMB2-CREDITS tests");
     266             : 
     267        2354 :         return suite;
     268             : }

Generated by: LCOV version 1.14