1/* 2 Unix SMB/CIFS implementation. 3 SMB torture tester - scanning functions 4 Copyright (C) Andrew Tridgell 2001 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#include "includes.h" 21 22#define VERBOSE 0 23#define OP_MIN 0 24#define OP_MAX 20 25 26#define DATA_SIZE 1024 27#define PARAM_SIZE 1024 28 29/**************************************************************************** 30look for a partial hit 31****************************************************************************/ 32static void trans2_check_hit(const char *format, int op, int level, NTSTATUS status) 33{ 34 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) || 35 NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) || 36 NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) || 37 NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) || 38 NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) { 39 return; 40 } 41#if VERBOSE 42 printf("possible %s hit op=%3d level=%5d status=%s\n", 43 format, op, level, nt_errstr(status)); 44#endif 45} 46 47/**************************************************************************** 48check for existance of a trans2 call 49****************************************************************************/ 50static NTSTATUS try_trans2(struct cli_state *cli, 51 int op, 52 char *param, char *data, 53 int param_len, int data_len, 54 unsigned int *rparam_len, unsigned int *rdata_len) 55{ 56 uint16 setup = op; 57 char *rparam=NULL, *rdata=NULL; 58 59 if (!cli_send_trans(cli, SMBtrans2, 60 NULL, /* name */ 61 -1, 0, /* fid, flags */ 62 &setup, 1, 0, /* setup, length, max */ 63 param, param_len, 2, /* param, length, max */ 64 data, data_len, cli->max_xmit /* data, length, max */ 65 )) { 66 return cli_nt_error(cli); 67 } 68 69 cli_receive_trans(cli, SMBtrans2, 70 &rparam, rparam_len, 71 &rdata, rdata_len); 72 73 SAFE_FREE(rdata); 74 SAFE_FREE(rparam); 75 76 return cli_nt_error(cli); 77} 78 79 80static NTSTATUS try_trans2_len(struct cli_state *cli, 81 const char *format, 82 int op, int level, 83 char *param, char *data, 84 int param_len, int *data_len, 85 unsigned int *rparam_len, unsigned int *rdata_len) 86{ 87 NTSTATUS ret=NT_STATUS_OK; 88 89 ret = try_trans2(cli, op, param, data, param_len, 90 DATA_SIZE, rparam_len, rdata_len); 91#if VERBOSE 92 printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret)); 93#endif 94 if (!NT_STATUS_IS_OK(ret)) return ret; 95 96 *data_len = 0; 97 while (*data_len < DATA_SIZE) { 98 ret = try_trans2(cli, op, param, data, param_len, 99 *data_len, rparam_len, rdata_len); 100 if (NT_STATUS_IS_OK(ret)) break; 101 *data_len += 2; 102 } 103 if (NT_STATUS_IS_OK(ret)) { 104 printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n", 105 format, level, *data_len, *rparam_len, *rdata_len); 106 } else { 107 trans2_check_hit(format, op, level, ret); 108 } 109 return ret; 110} 111 112/**************************************************************************** 113check for existance of a trans2 call 114****************************************************************************/ 115static bool scan_trans2(struct cli_state *cli, int op, int level, 116 int fnum, int dnum, const char *fname) 117{ 118 int data_len = 0; 119 int param_len = 0; 120 unsigned int rparam_len, rdata_len; 121 char param[PARAM_SIZE], data[DATA_SIZE]; 122 NTSTATUS status; 123 124 memset(data, 0, sizeof(data)); 125 data_len = 4; 126 127 /* try with a info level only */ 128 param_len = 2; 129 SSVAL(param, 0, level); 130 status = try_trans2_len(cli, "void", op, level, param, data, param_len, &data_len, 131 &rparam_len, &rdata_len); 132 if (NT_STATUS_IS_OK(status)) return True; 133 134 /* try with a file descriptor */ 135 param_len = 6; 136 SSVAL(param, 0, fnum); 137 SSVAL(param, 2, level); 138 SSVAL(param, 4, 0); 139 status = try_trans2_len(cli, "fnum", op, level, param, data, param_len, &data_len, 140 &rparam_len, &rdata_len); 141 if (NT_STATUS_IS_OK(status)) return True; 142 143 144 /* try with a notify style */ 145 param_len = 6; 146 SSVAL(param, 0, dnum); 147 SSVAL(param, 2, dnum); 148 SSVAL(param, 4, level); 149 status = try_trans2_len(cli, "notify", op, level, param, data, param_len, &data_len, 150 &rparam_len, &rdata_len); 151 if (NT_STATUS_IS_OK(status)) return True; 152 153 /* try with a file name */ 154 param_len = 6; 155 SSVAL(param, 0, level); 156 SSVAL(param, 2, 0); 157 SSVAL(param, 4, 0); 158 param_len += clistr_push(cli, ¶m[6], fname, -1, STR_TERMINATE); 159 160 status = try_trans2_len(cli, "fname", op, level, param, data, param_len, &data_len, 161 &rparam_len, &rdata_len); 162 if (NT_STATUS_IS_OK(status)) return True; 163 164 /* try with a new file name */ 165 param_len = 6; 166 SSVAL(param, 0, level); 167 SSVAL(param, 2, 0); 168 SSVAL(param, 4, 0); 169 param_len += clistr_push(cli, ¶m[6], "\\newfile.dat", -1, STR_TERMINATE); 170 171 status = try_trans2_len(cli, "newfile", op, level, param, data, param_len, &data_len, 172 &rparam_len, &rdata_len); 173 cli_unlink(cli, "\\newfile.dat", aSYSTEM | aHIDDEN); 174 cli_rmdir(cli, "\\newfile.dat"); 175 if (NT_STATUS_IS_OK(status)) return True; 176 177 /* try dfs style */ 178 cli_mkdir(cli, "\\testdir"); 179 param_len = 2; 180 SSVAL(param, 0, level); 181 param_len += clistr_push(cli, ¶m[2], "\\testdir", -1, STR_TERMINATE); 182 183 status = try_trans2_len(cli, "dfs", op, level, param, data, param_len, &data_len, 184 &rparam_len, &rdata_len); 185 cli_rmdir(cli, "\\testdir"); 186 if (NT_STATUS_IS_OK(status)) return True; 187 188 return False; 189} 190 191 192bool torture_trans2_scan(int dummy) 193{ 194 static struct cli_state *cli; 195 int op, level; 196 const char *fname = "\\scanner.dat"; 197 uint16_t fnum, dnum; 198 199 printf("starting trans2 scan test\n"); 200 201 if (!torture_open_connection(&cli, 0)) { 202 return False; 203 } 204 205 if (!NT_STATUS_IS_OK(cli_open(cli, fname, O_RDWR | O_CREAT | O_TRUNC, 206 DENY_NONE, &fnum))) { 207 printf("open of %s failed\n", fname); 208 return false; 209 } 210 if (!NT_STATUS_IS_OK(cli_open(cli, "\\", O_RDONLY, DENY_NONE, &dnum))) { 211 printf("open of \\ failed\n"); 212 return false; 213 } 214 215 for (op=OP_MIN; op<=OP_MAX; op++) { 216 printf("Scanning op=%d\n", op); 217 for (level = 0; level <= 50; level++) { 218 scan_trans2(cli, op, level, fnum, dnum, fname); 219 } 220 221 for (level = 0x100; level <= 0x130; level++) { 222 scan_trans2(cli, op, level, fnum, dnum, fname); 223 } 224 225 for (level = 1000; level < 1050; level++) { 226 scan_trans2(cli, op, level, fnum, dnum, fname); 227 } 228 } 229 230 torture_close_connection(cli); 231 232 printf("trans2 scan finished\n"); 233 return True; 234} 235 236 237 238 239/**************************************************************************** 240look for a partial hit 241****************************************************************************/ 242static void nttrans_check_hit(const char *format, int op, int level, NTSTATUS status) 243{ 244 if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) || 245 NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) || 246 NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) || 247 NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) || 248 NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) { 249 return; 250 } 251#if VERBOSE 252 printf("possible %s hit op=%3d level=%5d status=%s\n", 253 format, op, level, nt_errstr(status)); 254#endif 255} 256 257/**************************************************************************** 258check for existance of a nttrans call 259****************************************************************************/ 260static NTSTATUS try_nttrans(struct cli_state *cli, 261 int op, 262 char *param, char *data, 263 int param_len, int data_len, 264 unsigned int *rparam_len, unsigned int *rdata_len) 265{ 266 char *rparam=NULL, *rdata=NULL; 267 268 if (!cli_send_nt_trans(cli, op, 269 0, 270 NULL, 0, 0, 271 param, param_len, 2, /* param, length, max */ 272 data, data_len, cli->max_xmit /* data, length, max */ 273 )) { 274 return cli_nt_error(cli); 275 } 276 277 cli_receive_nt_trans(cli, 278 &rparam, rparam_len, 279 &rdata, rdata_len); 280 281 SAFE_FREE(rdata); 282 SAFE_FREE(rparam); 283 284 return cli_nt_error(cli); 285} 286 287 288static NTSTATUS try_nttrans_len(struct cli_state *cli, 289 const char *format, 290 int op, int level, 291 char *param, char *data, 292 int param_len, int *data_len, 293 unsigned int *rparam_len, unsigned int *rdata_len) 294{ 295 NTSTATUS ret=NT_STATUS_OK; 296 297 ret = try_nttrans(cli, op, param, data, param_len, 298 DATA_SIZE, rparam_len, rdata_len); 299#if VERBOSE 300 printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret)); 301#endif 302 if (!NT_STATUS_IS_OK(ret)) return ret; 303 304 *data_len = 0; 305 while (*data_len < DATA_SIZE) { 306 ret = try_nttrans(cli, op, param, data, param_len, 307 *data_len, rparam_len, rdata_len); 308 if (NT_STATUS_IS_OK(ret)) break; 309 *data_len += 2; 310 } 311 if (NT_STATUS_IS_OK(ret)) { 312 printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n", 313 format, level, *data_len, *rparam_len, *rdata_len); 314 } else { 315 nttrans_check_hit(format, op, level, ret); 316 } 317 return ret; 318} 319 320/**************************************************************************** 321check for existance of a nttrans call 322****************************************************************************/ 323static bool scan_nttrans(struct cli_state *cli, int op, int level, 324 int fnum, int dnum, const char *fname) 325{ 326 int data_len = 0; 327 int param_len = 0; 328 unsigned int rparam_len, rdata_len; 329 char param[PARAM_SIZE], data[DATA_SIZE]; 330 NTSTATUS status; 331 332 memset(data, 0, sizeof(data)); 333 data_len = 4; 334 335 /* try with a info level only */ 336 param_len = 2; 337 SSVAL(param, 0, level); 338 status = try_nttrans_len(cli, "void", op, level, param, data, param_len, &data_len, 339 &rparam_len, &rdata_len); 340 if (NT_STATUS_IS_OK(status)) return True; 341 342 /* try with a file descriptor */ 343 param_len = 6; 344 SSVAL(param, 0, fnum); 345 SSVAL(param, 2, level); 346 SSVAL(param, 4, 0); 347 status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len, &data_len, 348 &rparam_len, &rdata_len); 349 if (NT_STATUS_IS_OK(status)) return True; 350 351 352 /* try with a notify style */ 353 param_len = 6; 354 SSVAL(param, 0, dnum); 355 SSVAL(param, 2, dnum); 356 SSVAL(param, 4, level); 357 status = try_nttrans_len(cli, "notify", op, level, param, data, param_len, &data_len, 358 &rparam_len, &rdata_len); 359 if (NT_STATUS_IS_OK(status)) return True; 360 361 /* try with a file name */ 362 param_len = 6; 363 SSVAL(param, 0, level); 364 SSVAL(param, 2, 0); 365 SSVAL(param, 4, 0); 366 param_len += clistr_push(cli, ¶m[6], fname, -1, STR_TERMINATE); 367 368 status = try_nttrans_len(cli, "fname", op, level, param, data, param_len, &data_len, 369 &rparam_len, &rdata_len); 370 if (NT_STATUS_IS_OK(status)) return True; 371 372 /* try with a new file name */ 373 param_len = 6; 374 SSVAL(param, 0, level); 375 SSVAL(param, 2, 0); 376 SSVAL(param, 4, 0); 377 param_len += clistr_push(cli, ¶m[6], "\\newfile.dat", -1, STR_TERMINATE); 378 379 status = try_nttrans_len(cli, "newfile", op, level, param, data, param_len, &data_len, 380 &rparam_len, &rdata_len); 381 cli_unlink(cli, "\\newfile.dat", aSYSTEM | aHIDDEN); 382 cli_rmdir(cli, "\\newfile.dat"); 383 if (NT_STATUS_IS_OK(status)) return True; 384 385 /* try dfs style */ 386 cli_mkdir(cli, "\\testdir"); 387 param_len = 2; 388 SSVAL(param, 0, level); 389 param_len += clistr_push(cli, ¶m[2], "\\testdir", -1, STR_TERMINATE); 390 391 status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len, &data_len, 392 &rparam_len, &rdata_len); 393 cli_rmdir(cli, "\\testdir"); 394 if (NT_STATUS_IS_OK(status)) return True; 395 396 return False; 397} 398 399 400bool torture_nttrans_scan(int dummy) 401{ 402 static struct cli_state *cli; 403 int op, level; 404 const char *fname = "\\scanner.dat"; 405 uint16_t fnum, dnum; 406 407 printf("starting nttrans scan test\n"); 408 409 if (!torture_open_connection(&cli, 0)) { 410 return False; 411 } 412 413 cli_open(cli, fname, O_RDWR | O_CREAT | O_TRUNC, 414 DENY_NONE, &fnum); 415 cli_open(cli, "\\", O_RDONLY, DENY_NONE, &dnum); 416 417 for (op=OP_MIN; op<=OP_MAX; op++) { 418 printf("Scanning op=%d\n", op); 419 for (level = 0; level <= 50; level++) { 420 scan_nttrans(cli, op, level, fnum, dnum, fname); 421 } 422 423 for (level = 0x100; level <= 0x130; level++) { 424 scan_nttrans(cli, op, level, fnum, dnum, fname); 425 } 426 427 for (level = 1000; level < 1050; level++) { 428 scan_nttrans(cli, op, level, fnum, dnum, fname); 429 } 430 } 431 432 torture_close_connection(cli); 433 434 printf("nttrans scan finished\n"); 435 return True; 436} 437