• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source4/smb_server/smb/
1/*
2   Unix SMB/CIFS implementation.
3   process incoming packets - main loop
4   Copyright (C) Andrew Tridgell 1992-2005
5   Copyright (C) James J Myers 2003 <myersjj@samba.org>
6   Copyright (C) Stefan Metzmacher 2004-2005
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 "system/time.h"
24#include "smbd/service_stream.h"
25#include "smb_server/smb_server.h"
26#include "system/filesys.h"
27#include "param/param.h"
28
29
30/*
31  send an oplock break request to a client
32*/
33NTSTATUS smbsrv_send_oplock_break(void *p, struct ntvfs_handle *ntvfs, uint8_t level)
34{
35	struct smbsrv_tcon *tcon = talloc_get_type(p, struct smbsrv_tcon);
36	struct smbsrv_request *req;
37
38	req = smbsrv_init_request(tcon->smb_conn);
39	NT_STATUS_HAVE_NO_MEMORY(req);
40
41	smbsrv_setup_reply(req, 8, 0);
42
43	SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
44	SSVAL(req->out.hdr,HDR_TID,tcon->tid);
45	SSVAL(req->out.hdr,HDR_PID,0xFFFF);
46	SSVAL(req->out.hdr,HDR_UID,0);
47	SSVAL(req->out.hdr,HDR_MID,0xFFFF);
48	SCVAL(req->out.hdr,HDR_FLG,0);
49	SSVAL(req->out.hdr,HDR_FLG2,0);
50
51	SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
52	SSVAL(req->out.vwv, VWV(1), 0);
53	smbsrv_push_fnum(req->out.vwv, VWV(2), ntvfs);
54	SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
55	SCVAL(req->out.vwv, VWV(3)+1, level);
56	SIVAL(req->out.vwv, VWV(4), 0);
57	SSVAL(req->out.vwv, VWV(6), 0);
58	SSVAL(req->out.vwv, VWV(7), 0);
59
60	smbsrv_send_reply(req);
61	return NT_STATUS_OK;
62}
63
64static void switch_message(int type, struct smbsrv_request *req);
65
66/*
67  These flags determine some of the permissions required to do an operation
68*/
69#define NEED_SESS		(1<<0)
70#define NEED_TCON		(1<<1)
71#define SIGNING_NO_REPLY	(1<<2)
72/* does VWV(0) of the request hold chaining information */
73#define AND_X			(1<<3)
74/* The 64Kb question: are requests > 64K valid? */
75#define LARGE_REQUEST	(1<<4)
76
77/*
78   define a list of possible SMB messages and their corresponding
79   functions. Any message that has a NULL function is unimplemented -
80   please feel free to contribute implementations!
81*/
82static const struct smb_message_struct
83{
84	const char *name;
85	void (*fn)(struct smbsrv_request *);
86#define message_flags(type) smb_messages[(type) & 0xff].flags
87	int flags;
88}
89 smb_messages[256] = {
90/* 0x00 */ { "SMBmkdir",	smbsrv_reply_mkdir,		NEED_SESS|NEED_TCON },
91/* 0x01 */ { "SMBrmdir",	smbsrv_reply_rmdir,		NEED_SESS|NEED_TCON },
92/* 0x02 */ { "SMBopen",		smbsrv_reply_open,		NEED_SESS|NEED_TCON },
93/* 0x03 */ { "SMBcreate",	smbsrv_reply_mknew,		NEED_SESS|NEED_TCON },
94/* 0x04 */ { "SMBclose",	smbsrv_reply_close,		NEED_SESS|NEED_TCON },
95/* 0x05 */ { "SMBflush",	smbsrv_reply_flush,		NEED_SESS|NEED_TCON },
96/* 0x06 */ { "SMBunlink",	smbsrv_reply_unlink,		NEED_SESS|NEED_TCON },
97/* 0x07 */ { "SMBmv",		smbsrv_reply_mv,		NEED_SESS|NEED_TCON },
98/* 0x08 */ { "SMBgetatr",	smbsrv_reply_getatr,		NEED_SESS|NEED_TCON },
99/* 0x09 */ { "SMBsetatr",	smbsrv_reply_setatr,		NEED_SESS|NEED_TCON },
100/* 0x0a */ { "SMBread",		smbsrv_reply_read,		NEED_SESS|NEED_TCON },
101/* 0x0b */ { "SMBwrite",	smbsrv_reply_write,		NEED_SESS|NEED_TCON },
102/* 0x0c */ { "SMBlock",		smbsrv_reply_lock,		NEED_SESS|NEED_TCON },
103/* 0x0d */ { "SMBunlock",	smbsrv_reply_unlock,		NEED_SESS|NEED_TCON },
104/* 0x0e */ { "SMBctemp",	smbsrv_reply_ctemp,		NEED_SESS|NEED_TCON },
105/* 0x0f */ { "SMBmknew",	smbsrv_reply_mknew,		NEED_SESS|NEED_TCON },
106/* 0x10 */ { "SMBchkpth",	smbsrv_reply_chkpth,		NEED_SESS|NEED_TCON },
107/* 0x11 */ { "SMBexit",		smbsrv_reply_exit,		NEED_SESS },
108/* 0x12 */ { "SMBlseek",	smbsrv_reply_lseek,		NEED_SESS|NEED_TCON },
109/* 0x13 */ { "SMBlockread",	smbsrv_reply_lockread,		NEED_SESS|NEED_TCON },
110/* 0x14 */ { "SMBwriteunlock",	smbsrv_reply_writeunlock,	NEED_SESS|NEED_TCON },
111/* 0x15 */ { NULL, NULL, 0 },
112/* 0x16 */ { NULL, NULL, 0 },
113/* 0x17 */ { NULL, NULL, 0 },
114/* 0x18 */ { NULL, NULL, 0 },
115/* 0x19 */ { NULL, NULL, 0 },
116/* 0x1a */ { "SMBreadbraw",	smbsrv_reply_readbraw,		NEED_SESS|NEED_TCON },
117/* 0x1b */ { "SMBreadBmpx",	smbsrv_reply_readbmpx,		NEED_SESS|NEED_TCON },
118/* 0x1c */ { "SMBreadBs",	NULL,				0 },
119/* 0x1d */ { "SMBwritebraw",	smbsrv_reply_writebraw,		NEED_SESS|NEED_TCON },
120/* 0x1e */ { "SMBwriteBmpx",	smbsrv_reply_writebmpx,		NEED_SESS|NEED_TCON },
121/* 0x1f */ { "SMBwriteBs",	smbsrv_reply_writebs,		NEED_SESS|NEED_TCON },
122/* 0x20 */ { "SMBwritec",	NULL,				0 },
123/* 0x21 */ { NULL, NULL, 0 },
124/* 0x22 */ { "SMBsetattrE",	smbsrv_reply_setattrE,		NEED_SESS|NEED_TCON },
125/* 0x23 */ { "SMBgetattrE",	smbsrv_reply_getattrE,		NEED_SESS|NEED_TCON },
126/* 0x24 */ { "SMBlockingX",	smbsrv_reply_lockingX,		NEED_SESS|NEED_TCON|AND_X },
127/* 0x25 */ { "SMBtrans",	smbsrv_reply_trans,		NEED_SESS|NEED_TCON },
128/* 0x26 */ { "SMBtranss",	smbsrv_reply_transs,		NEED_SESS|NEED_TCON },
129/* 0x27 */ { "SMBioctl",	smbsrv_reply_ioctl,		NEED_SESS|NEED_TCON },
130/* 0x28 */ { "SMBioctls",	NULL,				NEED_SESS|NEED_TCON },
131/* 0x29 */ { "SMBcopy",		smbsrv_reply_copy,		NEED_SESS|NEED_TCON },
132/* 0x2a */ { "SMBmove",		NULL,				NEED_SESS|NEED_TCON },
133/* 0x2b */ { "SMBecho",		smbsrv_reply_echo,		0 },
134/* 0x2c */ { "SMBwriteclose",	smbsrv_reply_writeclose,	NEED_SESS|NEED_TCON },
135/* 0x2d */ { "SMBopenX",	smbsrv_reply_open_and_X,	NEED_SESS|NEED_TCON|AND_X },
136/* 0x2e */ { "SMBreadX",	smbsrv_reply_read_and_X,	NEED_SESS|NEED_TCON|AND_X },
137/* 0x2f */ { "SMBwriteX",	smbsrv_reply_write_and_X,	NEED_SESS|NEED_TCON|AND_X|LARGE_REQUEST},
138/* 0x30 */ { NULL, NULL, 0 },
139/* 0x31 */ { NULL, NULL, 0 },
140/* 0x32 */ { "SMBtrans2",	smbsrv_reply_trans2,		NEED_SESS|NEED_TCON },
141/* 0x33 */ { "SMBtranss2",	smbsrv_reply_transs2,		NEED_SESS|NEED_TCON },
142/* 0x34 */ { "SMBfindclose",	smbsrv_reply_findclose,		NEED_SESS|NEED_TCON },
143/* 0x35 */ { "SMBfindnclose",	smbsrv_reply_findnclose,	NEED_SESS|NEED_TCON },
144/* 0x36 */ { NULL, NULL, 0 },
145/* 0x37 */ { NULL, NULL, 0 },
146/* 0x38 */ { NULL, NULL, 0 },
147/* 0x39 */ { NULL, NULL, 0 },
148/* 0x3a */ { NULL, NULL, 0 },
149/* 0x3b */ { NULL, NULL, 0 },
150/* 0x3c */ { NULL, NULL, 0 },
151/* 0x3d */ { NULL, NULL, 0 },
152/* 0x3e */ { NULL, NULL, 0 },
153/* 0x3f */ { NULL, NULL, 0 },
154/* 0x40 */ { NULL, NULL, 0 },
155/* 0x41 */ { NULL, NULL, 0 },
156/* 0x42 */ { NULL, NULL, 0 },
157/* 0x43 */ { NULL, NULL, 0 },
158/* 0x44 */ { NULL, NULL, 0 },
159/* 0x45 */ { NULL, NULL, 0 },
160/* 0x46 */ { NULL, NULL, 0 },
161/* 0x47 */ { NULL, NULL, 0 },
162/* 0x48 */ { NULL, NULL, 0 },
163/* 0x49 */ { NULL, NULL, 0 },
164/* 0x4a */ { NULL, NULL, 0 },
165/* 0x4b */ { NULL, NULL, 0 },
166/* 0x4c */ { NULL, NULL, 0 },
167/* 0x4d */ { NULL, NULL, 0 },
168/* 0x4e */ { NULL, NULL, 0 },
169/* 0x4f */ { NULL, NULL, 0 },
170/* 0x50 */ { NULL, NULL, 0 },
171/* 0x51 */ { NULL, NULL, 0 },
172/* 0x52 */ { NULL, NULL, 0 },
173/* 0x53 */ { NULL, NULL, 0 },
174/* 0x54 */ { NULL, NULL, 0 },
175/* 0x55 */ { NULL, NULL, 0 },
176/* 0x56 */ { NULL, NULL, 0 },
177/* 0x57 */ { NULL, NULL, 0 },
178/* 0x58 */ { NULL, NULL, 0 },
179/* 0x59 */ { NULL, NULL, 0 },
180/* 0x5a */ { NULL, NULL, 0 },
181/* 0x5b */ { NULL, NULL, 0 },
182/* 0x5c */ { NULL, NULL, 0 },
183/* 0x5d */ { NULL, NULL, 0 },
184/* 0x5e */ { NULL, NULL, 0 },
185/* 0x5f */ { NULL, NULL, 0 },
186/* 0x60 */ { NULL, NULL, 0 },
187/* 0x61 */ { NULL, NULL, 0 },
188/* 0x62 */ { NULL, NULL, 0 },
189/* 0x63 */ { NULL, NULL, 0 },
190/* 0x64 */ { NULL, NULL, 0 },
191/* 0x65 */ { NULL, NULL, 0 },
192/* 0x66 */ { NULL, NULL, 0 },
193/* 0x67 */ { NULL, NULL, 0 },
194/* 0x68 */ { NULL, NULL, 0 },
195/* 0x69 */ { NULL, NULL, 0 },
196/* 0x6a */ { NULL, NULL, 0 },
197/* 0x6b */ { NULL, NULL, 0 },
198/* 0x6c */ { NULL, NULL, 0 },
199/* 0x6d */ { NULL, NULL, 0 },
200/* 0x6e */ { NULL, NULL, 0 },
201/* 0x6f */ { NULL, NULL, 0 },
202/* 0x70 */ { "SMBtcon",		smbsrv_reply_tcon,		NEED_SESS },
203/* 0x71 */ { "SMBtdis",		smbsrv_reply_tdis,		NEED_TCON },
204/* 0x72 */ { "SMBnegprot",	smbsrv_reply_negprot,		0 },
205/* 0x73 */ { "SMBsesssetupX",	smbsrv_reply_sesssetup,		AND_X },
206/* 0x74 */ { "SMBulogoffX",	smbsrv_reply_ulogoffX,		NEED_SESS|AND_X }, /* ulogoff doesn't give a valid TID */
207/* 0x75 */ { "SMBtconX",	smbsrv_reply_tcon_and_X,	NEED_SESS|AND_X },
208/* 0x76 */ { NULL, NULL, 0 },
209/* 0x77 */ { NULL, NULL, 0 },
210/* 0x78 */ { NULL, NULL, 0 },
211/* 0x79 */ { NULL, NULL, 0 },
212/* 0x7a */ { NULL, NULL, 0 },
213/* 0x7b */ { NULL, NULL, 0 },
214/* 0x7c */ { NULL, NULL, 0 },
215/* 0x7d */ { NULL, NULL, 0 },
216/* 0x7e */ { NULL, NULL, 0 },
217/* 0x7f */ { NULL, NULL, 0 },
218/* 0x80 */ { "SMBdskattr",	smbsrv_reply_dskattr,		NEED_SESS|NEED_TCON },
219/* 0x81 */ { "SMBsearch",	smbsrv_reply_search,		NEED_SESS|NEED_TCON },
220/* 0x82 */ { "SMBffirst",	smbsrv_reply_search,		NEED_SESS|NEED_TCON },
221/* 0x83 */ { "SMBfunique",	smbsrv_reply_search,		NEED_SESS|NEED_TCON },
222/* 0x84 */ { "SMBfclose",	smbsrv_reply_fclose,		NEED_SESS|NEED_TCON },
223/* 0x85 */ { NULL, NULL, 0 },
224/* 0x86 */ { NULL, NULL, 0 },
225/* 0x87 */ { NULL, NULL, 0 },
226/* 0x88 */ { NULL, NULL, 0 },
227/* 0x89 */ { NULL, NULL, 0 },
228/* 0x8a */ { NULL, NULL, 0 },
229/* 0x8b */ { NULL, NULL, 0 },
230/* 0x8c */ { NULL, NULL, 0 },
231/* 0x8d */ { NULL, NULL, 0 },
232/* 0x8e */ { NULL, NULL, 0 },
233/* 0x8f */ { NULL, NULL, 0 },
234/* 0x90 */ { NULL, NULL, 0 },
235/* 0x91 */ { NULL, NULL, 0 },
236/* 0x92 */ { NULL, NULL, 0 },
237/* 0x93 */ { NULL, NULL, 0 },
238/* 0x94 */ { NULL, NULL, 0 },
239/* 0x95 */ { NULL, NULL, 0 },
240/* 0x96 */ { NULL, NULL, 0 },
241/* 0x97 */ { NULL, NULL, 0 },
242/* 0x98 */ { NULL, NULL, 0 },
243/* 0x99 */ { NULL, NULL, 0 },
244/* 0x9a */ { NULL, NULL, 0 },
245/* 0x9b */ { NULL, NULL, 0 },
246/* 0x9c */ { NULL, NULL, 0 },
247/* 0x9d */ { NULL, NULL, 0 },
248/* 0x9e */ { NULL, NULL, 0 },
249/* 0x9f */ { NULL, NULL, 0 },
250/* 0xa0 */ { "SMBnttrans",	smbsrv_reply_nttrans,		NEED_SESS|NEED_TCON|LARGE_REQUEST },
251/* 0xa1 */ { "SMBnttranss",	smbsrv_reply_nttranss,		NEED_SESS|NEED_TCON },
252/* 0xa2 */ { "SMBntcreateX",	smbsrv_reply_ntcreate_and_X,	NEED_SESS|NEED_TCON|AND_X },
253/* 0xa3 */ { NULL, NULL, 0 },
254/* 0xa4 */ { "SMBntcancel",	smbsrv_reply_ntcancel,		NEED_SESS|NEED_TCON|SIGNING_NO_REPLY },
255/* 0xa5 */ { "SMBntrename",	smbsrv_reply_ntrename,		NEED_SESS|NEED_TCON },
256/* 0xa6 */ { NULL, NULL, 0 },
257/* 0xa7 */ { NULL, NULL, 0 },
258/* 0xa8 */ { NULL, NULL, 0 },
259/* 0xa9 */ { NULL, NULL, 0 },
260/* 0xaa */ { NULL, NULL, 0 },
261/* 0xab */ { NULL, NULL, 0 },
262/* 0xac */ { NULL, NULL, 0 },
263/* 0xad */ { NULL, NULL, 0 },
264/* 0xae */ { NULL, NULL, 0 },
265/* 0xaf */ { NULL, NULL, 0 },
266/* 0xb0 */ { NULL, NULL, 0 },
267/* 0xb1 */ { NULL, NULL, 0 },
268/* 0xb2 */ { NULL, NULL, 0 },
269/* 0xb3 */ { NULL, NULL, 0 },
270/* 0xb4 */ { NULL, NULL, 0 },
271/* 0xb5 */ { NULL, NULL, 0 },
272/* 0xb6 */ { NULL, NULL, 0 },
273/* 0xb7 */ { NULL, NULL, 0 },
274/* 0xb8 */ { NULL, NULL, 0 },
275/* 0xb9 */ { NULL, NULL, 0 },
276/* 0xba */ { NULL, NULL, 0 },
277/* 0xbb */ { NULL, NULL, 0 },
278/* 0xbc */ { NULL, NULL, 0 },
279/* 0xbd */ { NULL, NULL, 0 },
280/* 0xbe */ { NULL, NULL, 0 },
281/* 0xbf */ { NULL, NULL, 0 },
282/* 0xc0 */ { "SMBsplopen",	smbsrv_reply_printopen,		NEED_SESS|NEED_TCON },
283/* 0xc1 */ { "SMBsplwr",	smbsrv_reply_printwrite,	NEED_SESS|NEED_TCON },
284/* 0xc2 */ { "SMBsplclose",	smbsrv_reply_printclose,	NEED_SESS|NEED_TCON },
285/* 0xc3 */ { "SMBsplretq",	smbsrv_reply_printqueue,	NEED_SESS|NEED_TCON },
286/* 0xc4 */ { NULL, NULL, 0 },
287/* 0xc5 */ { NULL, NULL, 0 },
288/* 0xc6 */ { NULL, NULL, 0 },
289/* 0xc7 */ { NULL, NULL, 0 },
290/* 0xc8 */ { NULL, NULL, 0 },
291/* 0xc9 */ { NULL, NULL, 0 },
292/* 0xca */ { NULL, NULL, 0 },
293/* 0xcb */ { NULL, NULL, 0 },
294/* 0xcc */ { NULL, NULL, 0 },
295/* 0xcd */ { NULL, NULL, 0 },
296/* 0xce */ { NULL, NULL, 0 },
297/* 0xcf */ { NULL, NULL, 0 },
298/* 0xd0 */ { "SMBsends",	NULL,				0 },
299/* 0xd1 */ { "SMBsendb",	NULL,				0 },
300/* 0xd2 */ { "SMBfwdname",	NULL,				0 },
301/* 0xd3 */ { "SMBcancelf",	NULL,				0 },
302/* 0xd4 */ { "SMBgetmac",	NULL,				0 },
303/* 0xd5 */ { "SMBsendstrt",	NULL,				0 },
304/* 0xd6 */ { "SMBsendend",	NULL,				0 },
305/* 0xd7 */ { "SMBsendtxt",	NULL,				0 },
306/* 0xd8 */ { NULL, NULL, 0 },
307/* 0xd9 */ { NULL, NULL, 0 },
308/* 0xda */ { NULL, NULL, 0 },
309/* 0xdb */ { NULL, NULL, 0 },
310/* 0xdc */ { NULL, NULL, 0 },
311/* 0xdd */ { NULL, NULL, 0 },
312/* 0xde */ { NULL, NULL, 0 },
313/* 0xdf */ { NULL, NULL, 0 },
314/* 0xe0 */ { NULL, NULL, 0 },
315/* 0xe1 */ { NULL, NULL, 0 },
316/* 0xe2 */ { NULL, NULL, 0 },
317/* 0xe3 */ { NULL, NULL, 0 },
318/* 0xe4 */ { NULL, NULL, 0 },
319/* 0xe5 */ { NULL, NULL, 0 },
320/* 0xe6 */ { NULL, NULL, 0 },
321/* 0xe7 */ { NULL, NULL, 0 },
322/* 0xe8 */ { NULL, NULL, 0 },
323/* 0xe9 */ { NULL, NULL, 0 },
324/* 0xea */ { NULL, NULL, 0 },
325/* 0xeb */ { NULL, NULL, 0 },
326/* 0xec */ { NULL, NULL, 0 },
327/* 0xed */ { NULL, NULL, 0 },
328/* 0xee */ { NULL, NULL, 0 },
329/* 0xef */ { NULL, NULL, 0 },
330/* 0xf0 */ { NULL, NULL, 0 },
331/* 0xf1 */ { NULL, NULL, 0 },
332/* 0xf2 */ { NULL, NULL, 0 },
333/* 0xf3 */ { NULL, NULL, 0 },
334/* 0xf4 */ { NULL, NULL, 0 },
335/* 0xf5 */ { NULL, NULL, 0 },
336/* 0xf6 */ { NULL, NULL, 0 },
337/* 0xf7 */ { NULL, NULL, 0 },
338/* 0xf8 */ { NULL, NULL, 0 },
339/* 0xf9 */ { NULL, NULL, 0 },
340/* 0xfa */ { NULL, NULL, 0 },
341/* 0xfb */ { NULL, NULL, 0 },
342/* 0xfc */ { NULL, NULL, 0 },
343/* 0xfd */ { NULL, NULL, 0 },
344/* 0xfe */ { NULL, NULL, 0 },
345/* 0xff */ { NULL, NULL, 0 }
346};
347
348/****************************************************************************
349receive a SMB request header from the wire, forming a request_context
350from the result
351****************************************************************************/
352NTSTATUS smbsrv_recv_smb_request(void *private_data, DATA_BLOB blob)
353{
354	struct smbsrv_connection *smb_conn = talloc_get_type(private_data, struct smbsrv_connection);
355	struct smbsrv_request *req;
356	struct timeval cur_time = timeval_current();
357	uint8_t command;
358
359	smb_conn->statistics.last_request_time = cur_time;
360
361	/* see if its a special NBT packet */
362	if (CVAL(blob.data, 0) != 0) {
363		req = smbsrv_init_request(smb_conn);
364		NT_STATUS_HAVE_NO_MEMORY(req);
365
366		ZERO_STRUCT(req->in);
367
368		req->in.buffer = talloc_steal(req, blob.data);
369		req->in.size = blob.length;
370		req->request_time = cur_time;
371
372		smbsrv_reply_special(req);
373		return NT_STATUS_OK;
374	}
375
376	if ((NBT_HDR_SIZE + MIN_SMB_SIZE) > blob.length) {
377		DEBUG(2,("Invalid SMB packet: length %ld\n", (long)blob.length));
378		smbsrv_terminate_connection(smb_conn, "Invalid SMB packet");
379		return NT_STATUS_OK;
380	}
381
382	/* Make sure this is an SMB packet */
383	if (IVAL(blob.data, NBT_HDR_SIZE) != SMB_MAGIC) {
384		DEBUG(2,("Non-SMB packet of length %ld. Terminating connection\n",
385			 (long)blob.length));
386		smbsrv_terminate_connection(smb_conn, "Non-SMB packet");
387		return NT_STATUS_OK;
388	}
389
390	req = smbsrv_init_request(smb_conn);
391	NT_STATUS_HAVE_NO_MEMORY(req);
392
393	req->in.buffer = talloc_steal(req, blob.data);
394	req->in.size = blob.length;
395	req->request_time = cur_time;
396	req->chained_fnum = -1;
397	req->in.allocated = req->in.size;
398	req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
399	req->in.vwv = req->in.hdr + HDR_VWV;
400	req->in.wct = CVAL(req->in.hdr, HDR_WCT);
401
402	command = CVAL(req->in.hdr, HDR_COM);
403
404	if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
405		req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
406		req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
407
408		/* special handling for oversize calls. Windows seems
409		   to take the maximum of the BCC value and the
410		   computed buffer size. This handles oversized writeX
411		   calls, and possibly oversized SMBtrans calls */
412		if ((message_flags(command) & LARGE_REQUEST) &&
413		    ( !(message_flags(command) & AND_X) ||
414		      (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) &&
415		    req->in.data_size < req->in.size - PTR_DIFF(req->in.data,req->in.buffer)) {
416			req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
417		}
418	}
419
420	if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
421		DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
422		smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
423		return NT_STATUS_OK;
424	}
425
426	if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
427		DEBUG(2,("Invalid SMB buffer length count %d\n",
428			 (int)req->in.data_size));
429		smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
430		return NT_STATUS_OK;
431	}
432
433	req->flags2	= SVAL(req->in.hdr, HDR_FLG2);
434
435	/* fix the bufinfo */
436	smbsrv_setup_bufinfo(req);
437
438	if (!smbsrv_signing_check_incoming(req)) {
439		smbsrv_send_error(req, NT_STATUS_ACCESS_DENIED);
440		return NT_STATUS_OK;
441	}
442
443	command = CVAL(req->in.hdr, HDR_COM);
444	switch_message(command, req);
445	return NT_STATUS_OK;
446}
447
448/****************************************************************************
449return a string containing the function name of a SMB command
450****************************************************************************/
451static const char *smb_fn_name(uint8_t type)
452{
453	const char *unknown_name = "SMBunknown";
454
455	if (smb_messages[type].name == NULL)
456		return unknown_name;
457
458	return smb_messages[type].name;
459}
460
461
462/****************************************************************************
463 Do a switch on the message type and call the specific reply function for this
464message. Unlike earlier versions of Samba the reply functions are responsible
465for sending the reply themselves, rather than returning a size to this function
466The reply functions may also choose to delay the processing by pushing the message
467onto the message queue
468****************************************************************************/
469static void switch_message(int type, struct smbsrv_request *req)
470{
471	int flags;
472	struct smbsrv_connection *smb_conn = req->smb_conn;
473	NTSTATUS status;
474
475	type &= 0xff;
476
477	errno = 0;
478
479	if (smb_messages[type].fn == NULL) {
480		DEBUG(0,("Unknown message type %d!\n",type));
481		smbsrv_reply_unknown(req);
482		return;
483	}
484
485	flags = smb_messages[type].flags;
486
487	req->tcon = smbsrv_smb_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID), req->request_time);
488
489	if (!req->session) {
490		/* setup the user context for this request if it
491		   hasn't already been initialised (to cope with SMB
492		   chaining) */
493
494		/* In share mode security we must ignore the vuid. */
495		if (smb_conn->config.security == SEC_SHARE) {
496			if (req->tcon) {
497				req->session = req->tcon->sec_share.session;
498			}
499 		} else {
500			req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID), req->request_time);
501		}
502	}
503
504	DEBUG(5,("switch message %s (task_id %u)\n",
505		 smb_fn_name(type), (unsigned)req->smb_conn->connection->server_id.id));
506
507	/* this must be called before we do any reply */
508	if (flags & SIGNING_NO_REPLY) {
509		smbsrv_signing_no_reply(req);
510	}
511
512	/* see if the vuid is valid */
513	if ((flags & NEED_SESS) && !req->session) {
514		status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
515		/* amazingly, the error code depends on the command */
516		switch (type) {
517		case SMBntcreateX:
518		case SMBntcancel:
519		case SMBulogoffX:
520			break;
521		default:
522			if (req->smb_conn->config.nt_status_support &&
523			    req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
524				status = NT_STATUS_INVALID_HANDLE;
525			}
526			break;
527		}
528		/*
529		 * TODO:
530		 * don't know how to handle smb signing for this case
531		 * so just skip the reply
532		 */
533		if ((flags & SIGNING_NO_REPLY) &&
534		    (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
535			DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
536				smb_fn_name(type), nt_errstr(status)));
537			talloc_free(req);
538			return;
539		}
540		smbsrv_send_error(req, status);
541		return;
542	}
543
544	/* does this protocol need a valid tree connection? */
545	if ((flags & NEED_TCON) && !req->tcon) {
546		status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
547		/* amazingly, the error code depends on the command */
548		switch (type) {
549		case SMBntcreateX:
550		case SMBntcancel:
551		case SMBtdis:
552			break;
553		default:
554			if (req->smb_conn->config.nt_status_support &&
555			    req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
556				status = NT_STATUS_INVALID_HANDLE;
557			}
558			break;
559		}
560		/*
561		 * TODO:
562		 * don't know how to handle smb signing for this case
563		 * so just skip the reply
564		 */
565		if ((flags & SIGNING_NO_REPLY) &&
566		    (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
567			DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
568				smb_fn_name(type), nt_errstr(status)));
569			talloc_free(req);
570			return;
571		}
572		smbsrv_send_error(req, status);
573		return;
574	}
575
576	smb_messages[type].fn(req);
577}
578
579/*
580  we call this when first first part of a possibly chained request has been completed
581  and we need to call the 2nd part, if any
582*/
583void smbsrv_chain_reply(struct smbsrv_request *req)
584{
585	uint16_t chain_cmd, chain_offset;
586	uint8_t *vwv, *data;
587	uint16_t wct;
588	uint16_t data_size;
589
590	if (req->in.wct < 2 || req->out.wct < 2) {
591		smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
592		return;
593	}
594
595	chain_cmd    = CVAL(req->in.vwv, VWV(0));
596	chain_offset = SVAL(req->in.vwv, VWV(1));
597
598	if (chain_cmd == SMB_CHAIN_NONE) {
599		/* end of chain */
600		SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
601		SSVAL(req->out.vwv, VWV(1), 0);
602		smbsrv_send_reply(req);
603		return;
604	}
605
606	if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
607		goto error;
608	}
609
610	wct = CVAL(req->in.hdr, chain_offset);
611	vwv = req->in.hdr + chain_offset + 1;
612
613	if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
614		goto error;
615	}
616
617	data_size = SVAL(vwv, VWV(wct));
618	data = vwv + VWV(wct) + 2;
619
620	if (data + data_size > req->in.buffer + req->in.size) {
621		goto error;
622	}
623
624	/* all seems legit */
625	req->in.vwv = vwv;
626	req->in.wct = wct;
627	req->in.data = data;
628	req->in.data_size = data_size;
629	req->in.ptr = data;
630
631	/* fix the bufinfo */
632	smbsrv_setup_bufinfo(req);
633
634	req->chain_count++;
635
636	SSVAL(req->out.vwv, VWV(0), chain_cmd);
637	SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
638
639	/* cleanup somestuff for the next request */
640	talloc_free(req->ntvfs);
641	req->ntvfs = NULL;
642	talloc_free(req->io_ptr);
643	req->io_ptr = NULL;
644
645	switch_message(chain_cmd, req);
646	return;
647
648error:
649	SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
650	SSVAL(req->out.vwv, VWV(1), 0);
651	smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
652}
653
654/*
655 * init the SMB protocol related stuff
656 */
657NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn, struct loadparm_context *lp_ctx)
658{
659	NTSTATUS status;
660
661	/* now initialise a few default values associated with this smb socket */
662	smb_conn->negotiate.max_send = 0xFFFF;
663
664	/* this is the size that w2k uses, and it appears to be important for
665	   good performance */
666	smb_conn->negotiate.max_recv = lp_max_xmit(lp_ctx);
667
668	smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
669
670	smb_conn->config.security = lp_security(lp_ctx);
671	smb_conn->config.nt_status_support = lp_nt_status_support(lp_ctx);
672
673	status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
674	NT_STATUS_NOT_OK_RETURN(status);
675
676	status = smbsrv_smb_init_tcons(smb_conn);
677	NT_STATUS_NOT_OK_RETURN(status);
678
679	smbsrv_init_signing(smb_conn);
680
681	return NT_STATUS_OK;
682}
683