Release alpha15.
[nivanova/samba-autobuild/.git] / source4 / smb_server / smb / receive.c
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 */
33 NTSTATUS 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
64 static 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 */
82 static 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 /****************************************************************************
349 receive a SMB request header from the wire, forming a request_context
350 from the result
351 ****************************************************************************/
352 NTSTATUS 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 /****************************************************************************
449 return a string containing the function name of a SMB command
450 ****************************************************************************/
451 static 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 
464 message. Unlike earlier versions of Samba the reply functions are responsible
465 for sending the reply themselves, rather than returning a size to this function
466 The reply functions may also choose to delay the processing by pushing the message
467 onto the message queue
468 ****************************************************************************/
469 static 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 */
583 void 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
648 error:
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  */
657 NTSTATUS 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 = lpcfg_max_xmit(lp_ctx);
667
668         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
669
670         smb_conn->config.security = lpcfg_security(lp_ctx);
671         smb_conn->config.nt_status_support = lpcfg_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 }