2 Unix SMB/CIFS implementation.
4 test suite for SMB2 credits
6 Copyright (C) Ralph Boehme 2017
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.
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.
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/>.
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"
31 * Request 64k credits in negprot/sessionsetup and require at least 8k
33 * This passes against Windows 2016
35 static bool test_session_setup_credits_granted(struct torture_context
*tctx
,
36 struct smb2_tree
*_tree
)
38 struct smbcli_options options
;
39 struct smb2_transport
*transport
= NULL
;
40 struct smb2_tree
*tree
= NULL
;
45 transport
= _tree
->session
->transport
;
46 options
= transport
->options
;
48 status
= smb2_logoff(_tree
->session
);
49 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
50 "smb2_logoff failed\n");
53 options
.max_credits
= 65535;
55 ret
= torture_smb2_connection_ext(tctx
, 0, &options
, &tree
);
56 torture_assert_goto(tctx
, ret
== true, ret
, done
,
57 "torture_smb2_connection_ext failed\n");
59 transport
= tree
->session
->transport
;
61 cur_credits
= smb2cli_conn_get_cur_credits(transport
->conn
);
62 if (cur_credits
< 8192) {
63 torture_result(tctx
, TORTURE_FAIL
,
64 "Server only granted %" PRIu16
" credits\n",
76 * Request 64K credits in a single SMB2 request and requite at least 8192
78 * This passes against Windows 2016
80 static bool test_single_req_credits_granted(struct torture_context
*tctx
,
81 struct smb2_tree
*_tree
)
83 struct smbcli_options options
;
84 struct smb2_transport
*transport
= NULL
;
85 struct smb2_tree
*tree
= NULL
;
86 struct smb2_handle h
= {{0}};
87 struct smb2_create create
;
88 const char *fname
= "single_req_credits_granted.dat";
93 smb2_util_unlink(_tree
, fname
);
95 transport
= _tree
->session
->transport
;
96 options
= transport
->options
;
98 status
= smb2_logoff(_tree
->session
);
99 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
100 "smb2_logoff failed\n");
103 options
.max_credits
= 1;
105 ret
= torture_smb2_connection_ext(tctx
, 0, &options
, &tree
);
106 torture_assert_goto(tctx
, ret
== true, ret
, done
,
107 "torture_smb2_connection_ext failed\n");
109 transport
= tree
->session
->transport
;
111 cur_credits
= smb2cli_conn_get_cur_credits(transport
->conn
);
112 if (cur_credits
!= 1) {
113 torture_result(tctx
, TORTURE_FAIL
,
114 "Only wanted 1 credit but server granted %" PRIu16
"\n",
120 smb2cli_conn_set_max_credits(transport
->conn
, 65535);
123 create
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
124 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
125 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
126 create
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
127 create
.in
.fname
= fname
;
129 status
= smb2_create(tree
, tctx
, &create
);
130 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
,
131 "smb2_create failed\n");
132 h
= create
.out
.file
.handle
;
134 cur_credits
= smb2cli_conn_get_cur_credits(transport
->conn
);
135 if (cur_credits
< 8192) {
136 torture_result(tctx
, TORTURE_FAIL
,
137 "Server only granted %" PRIu16
" credits\n",
144 if (!smb2_util_handle_empty(h
)) {
145 smb2_util_close(tree
, h
);
147 smb2_util_unlink(tree
, fname
);
152 static bool test_crediting_skipped_mid(struct torture_context
*tctx
,
153 struct smb2_tree
*_tree
)
155 struct smbcli_options options
;
156 struct smb2_transport
*transport
= NULL
;
157 struct smb2_tree
*tree
= NULL
;
158 struct smb2_handle h
= {{0}};
159 struct smb2_create create
;
160 const char *fname
= "skipped_mid.dat";
162 uint16_t cur_credits
;
167 smb2_util_unlink(_tree
, fname
);
169 transport
= _tree
->session
->transport
;
170 options
= transport
->options
;
172 status
= smb2_logoff(_tree
->session
);
173 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_logoff failed\n");
176 options
.max_credits
= 8192;
178 ret
= torture_smb2_connection_ext(tctx
, 0, &options
, &tree
);
179 torture_assert_goto(tctx
, ret
== true, ret
, done
, "torture_smb2_connection_ext failed\n");
181 transport
= tree
->session
->transport
;
183 cur_credits
= smb2cli_conn_get_cur_credits(transport
->conn
);
184 if (cur_credits
!= 8192) {
185 torture_result(tctx
, TORTURE_FAIL
, "Server only granted %" PRIu16
" credits\n", cur_credits
);
191 create
.in
.impersonation_level
= NTCREATEX_IMPERSONATION_IMPERSONATION
;
192 create
.in
.desired_access
= SEC_RIGHTS_FILE_ALL
;
193 create
.in
.file_attributes
= FILE_ATTRIBUTE_NORMAL
;
194 create
.in
.create_disposition
= NTCREATEX_DISP_OPEN_IF
;
195 create
.in
.fname
= fname
;
197 status
= smb2_create(tree
, tctx
, &create
);
198 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_create failed\n");
199 h
= create
.out
.file
.handle
;
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:
207 * o Windows 2016 currently has a maximum mid window size of 8192 by
210 * o Samba's limit is 512
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.
218 mid
= smb2cli_conn_get_mid(tree
->session
->transport
->conn
);
219 smb2cli_conn_set_mid(tree
->session
->transport
->conn
, mid
+ 1);
221 for (i
= 0; i
< 8191; i
++) {
222 status
= smb2_util_write(tree
, h
, "\0", 0, 1);
223 if (!NT_STATUS_IS_OK(status
)) {
224 torture_result(tctx
, TORTURE_FAIL
, "Server only allowed %d writes\n", i
);
231 * Now use the skipped mid (the smb2_util_close...), we should
232 * immediately get a full mid window of size 8192.
234 smb2cli_conn_set_mid(tree
->session
->transport
->conn
, mid
);
235 status
= smb2_util_close(tree
, h
);
236 torture_assert_ntstatus_ok_goto(tctx
, status
, ret
, done
, "smb2_close failed\n");
239 cur_credits
= smb2cli_conn_get_cur_credits(transport
->conn
);
240 if (cur_credits
!= 8192) {
241 torture_result(tctx
, TORTURE_FAIL
, "Server only granted %" PRIu16
" credits\n", cur_credits
);
246 smb2cli_conn_set_mid(tree
->session
->transport
->conn
, mid
+ 8192);
249 if (!smb2_util_handle_empty(h
)) {
250 smb2_util_close(tree
, h
);
252 smb2_util_unlink(tree
, fname
);
257 struct torture_suite
*torture_smb2_crediting_init(TALLOC_CTX
*ctx
)
259 struct torture_suite
*suite
= torture_suite_create(ctx
, "credits");
261 torture_suite_add_1smb2_test(suite
, "session_setup_credits_granted", test_session_setup_credits_granted
);
262 torture_suite_add_1smb2_test(suite
, "single_req_credits_granted", test_single_req_credits_granted
);
263 torture_suite_add_1smb2_test(suite
, "skipped_mid", test_crediting_skipped_mid
);
265 suite
->description
= talloc_strdup(suite
, "SMB2-CREDITS tests");