r11786: move all SMB protocol specific stuff to smb_server/smb/
[kai/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 2 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, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "lib/events/events.h"
25 #include "system/time.h"
26 #include "dlinklist.h"
27 #include "smbd/service_stream.h"
28 #include "smb_server/smb_server.h"
29 #include "lib/messaging/irpc.h"
30 #include "lib/stream/packet.h"
31
32
33 /*
34   send an oplock break request to a client
35 */
36 BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
37 {
38         struct smbsrv_request *req;
39
40         req = init_smb_request(tcon->smb_conn);
41
42         req_setup_reply(req, 8, 0);
43         
44         SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
45         SSVAL(req->out.hdr,HDR_TID,tcon->tid);
46         SSVAL(req->out.hdr,HDR_PID,0xFFFF);
47         SSVAL(req->out.hdr,HDR_UID,0);
48         SSVAL(req->out.hdr,HDR_MID,0xFFFF);
49         SCVAL(req->out.hdr,HDR_FLG,0);
50         SSVAL(req->out.hdr,HDR_FLG2,0);
51
52         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
53         SSVAL(req->out.vwv, VWV(1), 0);
54         SSVAL(req->out.vwv, VWV(2), fnum);
55         SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
56         SCVAL(req->out.vwv, VWV(3)+1, level);
57         SIVAL(req->out.vwv, VWV(4), 0);
58         SSVAL(req->out.vwv, VWV(6), 0);
59         SSVAL(req->out.vwv, VWV(7), 0);
60
61         req_send_reply(req);
62         return True;
63 }
64
65 static void switch_message(int type, struct smbsrv_request *req);
66
67 /****************************************************************************
68 receive a SMB request header from the wire, forming a request_context
69 from the result
70 ****************************************************************************/
71 NTSTATUS smbsrv_recv_smb_request(void *private, DATA_BLOB blob)
72 {
73         struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
74         struct smbsrv_request *req;
75         uint8_t command;
76
77         /* see if its a special NBT packet */
78         if (CVAL(blob.data, 0) != 0) {
79                 req = init_smb_request(smb_conn);
80                 NT_STATUS_HAVE_NO_MEMORY(req);
81
82                 ZERO_STRUCT(req->in);
83
84                 req->in.buffer = talloc_steal(req, blob.data);
85                 req->in.size = blob.length;
86                 req->request_time = timeval_current();
87
88                 reply_special(req);
89                 return NT_STATUS_OK;
90         }
91
92         if ((NBT_HDR_SIZE + MIN_SMB_SIZE) > blob.length) {
93                 DEBUG(2,("Invalid SMB packet: length %d\n", blob.length));
94                 smbsrv_terminate_connection(smb_conn, "Invalid SMB packet");
95                 return NT_STATUS_OK;
96         }
97
98         /* Make sure this is an SMB packet */
99         if (IVAL(blob.data, NBT_HDR_SIZE) != SMB_MAGIC) {
100                 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
101                          blob.length));
102                 smbsrv_terminate_connection(smb_conn, "Non-SMB packet");
103                 return NT_STATUS_OK;
104         }
105
106         req = init_smb_request(smb_conn);
107         NT_STATUS_HAVE_NO_MEMORY(req);
108
109         req->in.buffer = talloc_steal(req, blob.data);
110         req->in.size = blob.length;
111         req->request_time = timeval_current();
112         req->chained_fnum = -1;
113         req->in.allocated = req->in.size;
114         req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
115         req->in.vwv = req->in.hdr + HDR_VWV;
116         req->in.wct = CVAL(req->in.hdr, HDR_WCT);
117         if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
118                 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
119                 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
120
121                 /* the bcc length is only 16 bits, but some packets
122                    (such as SMBwriteX) can be much larger than 64k. We
123                    detect this by looking for a large non-chained NBT
124                    packet (at least 64k bigger than what is
125                    specified). If it is detected then the NBT size is
126                    used instead of the bcc size */
127                 if (req->in.data_size + 0x10000 <= 
128                     req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
129                     (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
130                         /* its an oversized packet! fun for all the family */
131                         req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
132                 }
133         }
134
135         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
136                 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
137                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
138                 return NT_STATUS_OK;
139         }
140  
141         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
142                 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
143                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
144                 return NT_STATUS_OK;
145         }
146
147         req->flags      = CVAL(req->in.hdr, HDR_FLG);
148         req->flags2     = SVAL(req->in.hdr, HDR_FLG2);
149         req->smbpid     = SVAL(req->in.hdr, HDR_PID);
150
151         if (!req_signing_check_incoming(req)) {
152                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
153                 return NT_STATUS_OK;
154         }
155
156         command = CVAL(req->in.hdr, HDR_COM);
157         switch_message(command, req);
158         return NT_STATUS_OK;
159 }
160
161 /*
162   These flags determine some of the permissions required to do an operation 
163 */
164 #define AS_USER (1<<0)
165 #define SIGNING_NO_REPLY (1<<1)
166
167 /* 
168    define a list of possible SMB messages and their corresponding
169    functions. Any message that has a NULL function is unimplemented -
170    please feel free to contribute implementations!
171 */
172 static const struct smb_message_struct
173 {
174         const char *name;
175         void (*fn)(struct smbsrv_request *);
176         int flags;
177 }
178  smb_messages[256] = {
179 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER},
180 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER},
181 /* 0x02 */ { "SMBopen",reply_open,AS_USER},
182 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
183 /* 0x04 */ { "SMBclose",reply_close,AS_USER},
184 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
185 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER},
186 /* 0x07 */ { "SMBmv",reply_mv,AS_USER},
187 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
188 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER},
189 /* 0x0a */ { "SMBread",reply_read,AS_USER},
190 /* 0x0b */ { "SMBwrite",reply_write,AS_USER},
191 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
192 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
193 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
194 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER}, 
195 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
196 /* 0x11 */ { "SMBexit",reply_exit,0},
197 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
198 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
199 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
200 /* 0x15 */ { NULL, NULL, 0 },
201 /* 0x16 */ { NULL, NULL, 0 },
202 /* 0x17 */ { NULL, NULL, 0 },
203 /* 0x18 */ { NULL, NULL, 0 },
204 /* 0x19 */ { NULL, NULL, 0 },
205 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
206 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
207 /* 0x1c */ { "SMBreadBs",NULL,0 },
208 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
209 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
210 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
211 /* 0x20 */ { "SMBwritec",NULL,0},
212 /* 0x21 */ { NULL, NULL, 0 },
213 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER},
214 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER},
215 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER},
216 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER},
217 /* 0x26 */ { "SMBtranss",reply_transs,AS_USER},
218 /* 0x27 */ { "SMBioctl",reply_ioctl,AS_USER},
219 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
220 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER},
221 /* 0x2a */ { "SMBmove",NULL,AS_USER},
222 /* 0x2b */ { "SMBecho",reply_echo,0},
223 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
224 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER},
225 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER},
226 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER},
227 /* 0x30 */ { NULL, NULL, 0 },
228 /* 0x31 */ { NULL, NULL, 0 },
229 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER},
230 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
231 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
232 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
233 /* 0x36 */ { NULL, NULL, 0 },
234 /* 0x37 */ { NULL, NULL, 0 },
235 /* 0x38 */ { NULL, NULL, 0 },
236 /* 0x39 */ { NULL, NULL, 0 },
237 /* 0x3a */ { NULL, NULL, 0 },
238 /* 0x3b */ { NULL, NULL, 0 },
239 /* 0x3c */ { NULL, NULL, 0 },
240 /* 0x3d */ { NULL, NULL, 0 },
241 /* 0x3e */ { NULL, NULL, 0 },
242 /* 0x3f */ { NULL, NULL, 0 },
243 /* 0x40 */ { NULL, NULL, 0 },
244 /* 0x41 */ { NULL, NULL, 0 },
245 /* 0x42 */ { NULL, NULL, 0 },
246 /* 0x43 */ { NULL, NULL, 0 },
247 /* 0x44 */ { NULL, NULL, 0 },
248 /* 0x45 */ { NULL, NULL, 0 },
249 /* 0x46 */ { NULL, NULL, 0 },
250 /* 0x47 */ { NULL, NULL, 0 },
251 /* 0x48 */ { NULL, NULL, 0 },
252 /* 0x49 */ { NULL, NULL, 0 },
253 /* 0x4a */ { NULL, NULL, 0 },
254 /* 0x4b */ { NULL, NULL, 0 },
255 /* 0x4c */ { NULL, NULL, 0 },
256 /* 0x4d */ { NULL, NULL, 0 },
257 /* 0x4e */ { NULL, NULL, 0 },
258 /* 0x4f */ { NULL, NULL, 0 },
259 /* 0x50 */ { NULL, NULL, 0 },
260 /* 0x51 */ { NULL, NULL, 0 },
261 /* 0x52 */ { NULL, NULL, 0 },
262 /* 0x53 */ { NULL, NULL, 0 },
263 /* 0x54 */ { NULL, NULL, 0 },
264 /* 0x55 */ { NULL, NULL, 0 },
265 /* 0x56 */ { NULL, NULL, 0 },
266 /* 0x57 */ { NULL, NULL, 0 },
267 /* 0x58 */ { NULL, NULL, 0 },
268 /* 0x59 */ { NULL, NULL, 0 },
269 /* 0x5a */ { NULL, NULL, 0 },
270 /* 0x5b */ { NULL, NULL, 0 },
271 /* 0x5c */ { NULL, NULL, 0 },
272 /* 0x5d */ { NULL, NULL, 0 },
273 /* 0x5e */ { NULL, NULL, 0 },
274 /* 0x5f */ { NULL, NULL, 0 },
275 /* 0x60 */ { NULL, NULL, 0 },
276 /* 0x61 */ { NULL, NULL, 0 },
277 /* 0x62 */ { NULL, NULL, 0 },
278 /* 0x63 */ { NULL, NULL, 0 },
279 /* 0x64 */ { NULL, NULL, 0 },
280 /* 0x65 */ { NULL, NULL, 0 },
281 /* 0x66 */ { NULL, NULL, 0 },
282 /* 0x67 */ { NULL, NULL, 0 },
283 /* 0x68 */ { NULL, NULL, 0 },
284 /* 0x69 */ { NULL, NULL, 0 },
285 /* 0x6a */ { NULL, NULL, 0 },
286 /* 0x6b */ { NULL, NULL, 0 },
287 /* 0x6c */ { NULL, NULL, 0 },
288 /* 0x6d */ { NULL, NULL, 0 },
289 /* 0x6e */ { NULL, NULL, 0 },
290 /* 0x6f */ { NULL, NULL, 0 },
291 /* 0x70 */ { "SMBtcon",reply_tcon,0},
292 /* 0x71 */ { "SMBtdis",reply_tdis,0},
293 /* 0x72 */ { "SMBnegprot",reply_negprot,0},
294 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,0},
295 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
296 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
297 /* 0x76 */ { NULL, NULL, 0 },
298 /* 0x77 */ { NULL, NULL, 0 },
299 /* 0x78 */ { NULL, NULL, 0 },
300 /* 0x79 */ { NULL, NULL, 0 },
301 /* 0x7a */ { NULL, NULL, 0 },
302 /* 0x7b */ { NULL, NULL, 0 },
303 /* 0x7c */ { NULL, NULL, 0 },
304 /* 0x7d */ { NULL, NULL, 0 },
305 /* 0x7e */ { NULL, NULL, 0 },
306 /* 0x7f */ { NULL, NULL, 0 },
307 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
308 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
309 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
310 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
311 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
312 /* 0x85 */ { NULL, NULL, 0 },
313 /* 0x86 */ { NULL, NULL, 0 },
314 /* 0x87 */ { NULL, NULL, 0 },
315 /* 0x88 */ { NULL, NULL, 0 },
316 /* 0x89 */ { NULL, NULL, 0 },
317 /* 0x8a */ { NULL, NULL, 0 },
318 /* 0x8b */ { NULL, NULL, 0 },
319 /* 0x8c */ { NULL, NULL, 0 },
320 /* 0x8d */ { NULL, NULL, 0 },
321 /* 0x8e */ { NULL, NULL, 0 },
322 /* 0x8f */ { NULL, NULL, 0 },
323 /* 0x90 */ { NULL, NULL, 0 },
324 /* 0x91 */ { NULL, NULL, 0 },
325 /* 0x92 */ { NULL, NULL, 0 },
326 /* 0x93 */ { NULL, NULL, 0 },
327 /* 0x94 */ { NULL, NULL, 0 },
328 /* 0x95 */ { NULL, NULL, 0 },
329 /* 0x96 */ { NULL, NULL, 0 },
330 /* 0x97 */ { NULL, NULL, 0 },
331 /* 0x98 */ { NULL, NULL, 0 },
332 /* 0x99 */ { NULL, NULL, 0 },
333 /* 0x9a */ { NULL, NULL, 0 },
334 /* 0x9b */ { NULL, NULL, 0 },
335 /* 0x9c */ { NULL, NULL, 0 },
336 /* 0x9d */ { NULL, NULL, 0 },
337 /* 0x9e */ { NULL, NULL, 0 },
338 /* 0x9f */ { NULL, NULL, 0 },
339 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER},
340 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER},
341 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER},
342 /* 0xa3 */ { NULL, NULL, 0 },
343 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, AS_USER|SIGNING_NO_REPLY},
344 /* 0xa5 */ { "SMBntrename", reply_ntrename, AS_USER},
345 /* 0xa6 */ { NULL, NULL, 0 },
346 /* 0xa7 */ { NULL, NULL, 0 },
347 /* 0xa8 */ { NULL, NULL, 0 },
348 /* 0xa9 */ { NULL, NULL, 0 },
349 /* 0xaa */ { NULL, NULL, 0 },
350 /* 0xab */ { NULL, NULL, 0 },
351 /* 0xac */ { NULL, NULL, 0 },
352 /* 0xad */ { NULL, NULL, 0 },
353 /* 0xae */ { NULL, NULL, 0 },
354 /* 0xaf */ { NULL, NULL, 0 },
355 /* 0xb0 */ { NULL, NULL, 0 },
356 /* 0xb1 */ { NULL, NULL, 0 },
357 /* 0xb2 */ { NULL, NULL, 0 },
358 /* 0xb3 */ { NULL, NULL, 0 },
359 /* 0xb4 */ { NULL, NULL, 0 },
360 /* 0xb5 */ { NULL, NULL, 0 },
361 /* 0xb6 */ { NULL, NULL, 0 },
362 /* 0xb7 */ { NULL, NULL, 0 },
363 /* 0xb8 */ { NULL, NULL, 0 },
364 /* 0xb9 */ { NULL, NULL, 0 },
365 /* 0xba */ { NULL, NULL, 0 },
366 /* 0xbb */ { NULL, NULL, 0 },
367 /* 0xbc */ { NULL, NULL, 0 },
368 /* 0xbd */ { NULL, NULL, 0 },
369 /* 0xbe */ { NULL, NULL, 0 },
370 /* 0xbf */ { NULL, NULL, 0 },
371 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
372 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
373 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
374 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
375 /* 0xc4 */ { NULL, NULL, 0 },
376 /* 0xc5 */ { NULL, NULL, 0 },
377 /* 0xc6 */ { NULL, NULL, 0 },
378 /* 0xc7 */ { NULL, NULL, 0 },
379 /* 0xc8 */ { NULL, NULL, 0 },
380 /* 0xc9 */ { NULL, NULL, 0 },
381 /* 0xca */ { NULL, NULL, 0 },
382 /* 0xcb */ { NULL, NULL, 0 },
383 /* 0xcc */ { NULL, NULL, 0 },
384 /* 0xcd */ { NULL, NULL, 0 },
385 /* 0xce */ { NULL, NULL, 0 },
386 /* 0xcf */ { NULL, NULL, 0 },
387 /* 0xd0 */ { "SMBsends",reply_sends,0},
388 /* 0xd1 */ { "SMBsendb",NULL,0},
389 /* 0xd2 */ { "SMBfwdname",NULL,0},
390 /* 0xd3 */ { "SMBcancelf",NULL,0},
391 /* 0xd4 */ { "SMBgetmac",NULL,0},
392 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,0},
393 /* 0xd6 */ { "SMBsendend",reply_sendend,0},
394 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,0},
395 /* 0xd8 */ { NULL, NULL, 0 },
396 /* 0xd9 */ { NULL, NULL, 0 },
397 /* 0xda */ { NULL, NULL, 0 },
398 /* 0xdb */ { NULL, NULL, 0 },
399 /* 0xdc */ { NULL, NULL, 0 },
400 /* 0xdd */ { NULL, NULL, 0 },
401 /* 0xde */ { NULL, NULL, 0 },
402 /* 0xdf */ { NULL, NULL, 0 },
403 /* 0xe0 */ { NULL, NULL, 0 },
404 /* 0xe1 */ { NULL, NULL, 0 },
405 /* 0xe2 */ { NULL, NULL, 0 },
406 /* 0xe3 */ { NULL, NULL, 0 },
407 /* 0xe4 */ { NULL, NULL, 0 },
408 /* 0xe5 */ { NULL, NULL, 0 },
409 /* 0xe6 */ { NULL, NULL, 0 },
410 /* 0xe7 */ { NULL, NULL, 0 },
411 /* 0xe8 */ { NULL, NULL, 0 },
412 /* 0xe9 */ { NULL, NULL, 0 },
413 /* 0xea */ { NULL, NULL, 0 },
414 /* 0xeb */ { NULL, NULL, 0 },
415 /* 0xec */ { NULL, NULL, 0 },
416 /* 0xed */ { NULL, NULL, 0 },
417 /* 0xee */ { NULL, NULL, 0 },
418 /* 0xef */ { NULL, NULL, 0 },
419 /* 0xf0 */ { NULL, NULL, 0 },
420 /* 0xf1 */ { NULL, NULL, 0 },
421 /* 0xf2 */ { NULL, NULL, 0 },
422 /* 0xf3 */ { NULL, NULL, 0 },
423 /* 0xf4 */ { NULL, NULL, 0 },
424 /* 0xf5 */ { NULL, NULL, 0 },
425 /* 0xf6 */ { NULL, NULL, 0 },
426 /* 0xf7 */ { NULL, NULL, 0 },
427 /* 0xf8 */ { NULL, NULL, 0 },
428 /* 0xf9 */ { NULL, NULL, 0 },
429 /* 0xfa */ { NULL, NULL, 0 },
430 /* 0xfb */ { NULL, NULL, 0 },
431 /* 0xfc */ { NULL, NULL, 0 },
432 /* 0xfd */ { NULL, NULL, 0 },
433 /* 0xfe */ { NULL, NULL, 0 },
434 /* 0xff */ { NULL, NULL, 0 }
435 };
436
437 /****************************************************************************
438 return a string containing the function name of a SMB command
439 ****************************************************************************/
440 static const char *smb_fn_name(uint8_t type)
441 {
442         const char *unknown_name = "SMBunknown";
443
444         if (smb_messages[type].name == NULL)
445                 return unknown_name;
446
447         return smb_messages[type].name;
448 }
449
450
451 /****************************************************************************
452  Do a switch on the message type and call the specific reply function for this 
453 message. Unlike earlier versions of Samba the reply functions are responsible
454 for sending the reply themselves, rather than returning a size to this function
455 The reply functions may also choose to delay the processing by pushing the message
456 onto the message queue
457 ****************************************************************************/
458 static void switch_message(int type, struct smbsrv_request *req)
459 {
460         int flags;
461         struct smbsrv_connection *smb_conn = req->smb_conn;
462         NTSTATUS status;
463
464         type &= 0xff;
465
466         errno = 0;
467
468         if (smb_messages[type].fn == NULL) {
469                 DEBUG(0,("Unknown message type %d!\n",type));
470                 reply_unknown(req);
471                 return;
472         }
473
474         flags = smb_messages[type].flags;
475
476         req->tcon = smbsrv_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
477
478         if (!req->session) {
479                 /* setup the user context for this request if it
480                    hasn't already been initialised (to cope with SMB
481                    chaining) */
482
483                 /* In share mode security we must ignore the vuid. */
484                 if (smb_conn->config.security == SEC_SHARE) {
485                         if (req->tcon) {
486                                 req->session = req->tcon->sec_share.session;
487                         }
488                 } else {
489                         req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID));
490                 }
491         }
492
493         DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id));
494
495         /* this must be called before we do any reply */
496         if (flags & SIGNING_NO_REPLY) {
497                 req_signing_no_reply(req);
498         }
499
500         /* see if the vuid is valid */
501         if ((flags & AS_USER) && !req->session) {
502                 /* amazingly, the error code depends on the command */
503                 switch (type) {
504                         case SMBntcreateX:
505                         case SMBntcancel:
506                                 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
507                                 break;
508                         default:
509                                 status = NT_STATUS_INVALID_HANDLE;
510                                 break;
511                 }
512                 /* 
513                  * TODO:
514                  * don't know how to handle smb signing for this case 
515                  * so just skip the reply
516                  */
517                 if ((flags & SIGNING_NO_REPLY) &&
518                     (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
519                         DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
520                                 smb_fn_name(type), nt_errstr(status)));
521                         req_destroy(req);
522                         return;
523                 }
524                 req_reply_error(req, status);
525                 return;
526         }
527
528         /* does this protocol need a valid tree connection? */
529         if ((flags & AS_USER) && !req->tcon) {
530                 /* amazingly, the error code depends on the command */
531                 switch (type) {
532                         case SMBntcreateX:
533                         case SMBntcancel:
534                                 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
535                                 break;
536                         default:
537                                 status = NT_STATUS_INVALID_HANDLE;
538                                 break;
539                 }
540                 /* 
541                  * TODO:
542                  * don't know how to handle smb signing for this case 
543                  * so just skip the reply
544                  */
545                 if ((flags & SIGNING_NO_REPLY) &&
546                     (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
547                         DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
548                                 smb_fn_name(type), nt_errstr(status)));
549                         req_destroy(req);
550                         return;
551                 }
552                 req_reply_error(req, status);
553                 return;
554         }
555
556         smb_messages[type].fn(req);
557 }
558
559 /*
560   we call this when first first part of a possibly chained request has been completed
561   and we need to call the 2nd part, if any
562 */
563 void chain_reply(struct smbsrv_request *req)
564 {
565         uint16_t chain_cmd, chain_offset;
566         uint8_t *vwv, *data;
567         uint16_t wct;
568         uint16_t data_size;
569
570         if (req->in.wct < 2 || req->out.wct < 2) {
571                 req_reply_dos_error(req, ERRSRV, ERRerror);
572                 return;
573         }
574
575         chain_cmd    = CVAL(req->in.vwv, VWV(0));
576         chain_offset = SVAL(req->in.vwv, VWV(1));
577
578         if (chain_cmd == SMB_CHAIN_NONE) {
579                 /* end of chain */
580                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
581                 SSVAL(req->out.vwv, VWV(1), 0);
582                 req_send_reply(req);
583                 return;
584         }
585
586         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
587                 goto error;
588         }
589
590         wct = CVAL(req->in.hdr, chain_offset);
591         vwv = req->in.hdr + chain_offset + 1;
592
593         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
594                 goto error;
595         }
596
597         data_size = SVAL(vwv, VWV(wct));
598         data = vwv + VWV(wct) + 2;
599
600         if (data + data_size > req->in.buffer + req->in.size) {
601                 goto error;
602         }
603
604         /* all seems legit */
605         req->in.vwv = vwv;
606         req->in.wct = wct;
607         req->in.data = data;
608         req->in.data_size = data_size;
609         req->in.ptr = data;
610
611         req->chain_count++;
612
613         SSVAL(req->out.vwv, VWV(0), chain_cmd);
614         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
615
616         /* the current request in the chain might have used an async reply,
617            but that doesn't mean the next element needs to */
618         ZERO_STRUCTP(req->async_states);
619
620         switch_message(chain_cmd, req);
621         return;
622
623 error:
624         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
625         SSVAL(req->out.vwv, VWV(1), 0);
626         req_reply_dos_error(req, ERRSRV, ERRerror);
627 }
628
629 /*
630  * init the SMB protocol related stuff
631  */
632 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn)
633 {
634         NTSTATUS status;
635
636         /* now initialise a few default values associated with this smb socket */
637         smb_conn->negotiate.max_send = 0xFFFF;
638
639         /* this is the size that w2k uses, and it appears to be important for
640            good performance */
641         smb_conn->negotiate.max_recv = lp_max_xmit();
642
643         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
644
645         smb_conn->config.security = lp_security();
646         smb_conn->config.nt_status_support = lp_nt_status_support();
647
648         status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
649         NT_STATUS_NOT_OK_RETURN(status);
650
651         status = smbsrv_init_tcons(smb_conn, UINT16_MAX);
652         NT_STATUS_NOT_OK_RETURN(status);
653
654         srv_init_signing(smb_conn);
655
656         return NT_STATUS_OK;
657 }