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