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, &param[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, &param[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, &param[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, &param[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, &param[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, &param[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