source: branches/samba-3.5.x/source4/smb_server/smb/receive.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 22.4 KB
Line 
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}
Note: See TracBrowser for help on using the repository browser.