r11786: move all SMB protocol specific stuff to smb_server/smb/
[Samba/aatanasov.git] / source / smb_server / smb / receive.c
blob0ee87698c8a32d852a92f55d7ff0a9e3299ee0ac
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
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.
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.
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.
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"
34 send an oplock break request to a client
36 BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
38 struct smbsrv_request *req;
40 req = init_smb_request(tcon->smb_conn);
42 req_setup_reply(req, 8, 0);
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);
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);
61 req_send_reply(req);
62 return True;
65 static void switch_message(int type, struct smbsrv_request *req);
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)
73 struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
74 struct smbsrv_request *req;
75 uint8_t command;
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);
82 ZERO_STRUCT(req->in);
84 req->in.buffer = talloc_steal(req, blob.data);
85 req->in.size = blob.length;
86 req->request_time = timeval_current();
88 reply_special(req);
89 return NT_STATUS_OK;
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;
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;
106 req = init_smb_request(smb_conn);
107 NT_STATUS_HAVE_NO_MEMORY(req);
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));
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);
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;
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;
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);
151 if (!req_signing_check_incoming(req)) {
152 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
153 return NT_STATUS_OK;
156 command = CVAL(req->in.hdr, HDR_COM);
157 switch_message(command, req);
158 return NT_STATUS_OK;
162 These flags determine some of the permissions required to do an operation
164 #define AS_USER (1<<0)
165 #define SIGNING_NO_REPLY (1<<1)
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!
172 static const struct smb_message_struct
174 const char *name;
175 void (*fn)(struct smbsrv_request *);
176 int flags;
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 }
437 /****************************************************************************
438 return a string containing the function name of a SMB command
439 ****************************************************************************/
440 static const char *smb_fn_name(uint8_t type)
442 const char *unknown_name = "SMBunknown";
444 if (smb_messages[type].name == NULL)
445 return unknown_name;
447 return smb_messages[type].name;
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)
460 int flags;
461 struct smbsrv_connection *smb_conn = req->smb_conn;
462 NTSTATUS status;
464 type &= 0xff;
466 errno = 0;
468 if (smb_messages[type].fn == NULL) {
469 DEBUG(0,("Unknown message type %d!\n",type));
470 reply_unknown(req);
471 return;
474 flags = smb_messages[type].flags;
476 req->tcon = smbsrv_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
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) */
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;
488 } else {
489 req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID));
493 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id));
495 /* this must be called before we do any reply */
496 if (flags & SIGNING_NO_REPLY) {
497 req_signing_no_reply(req);
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;
513 * TODO:
514 * don't know how to handle smb signing for this case
515 * so just skip the reply
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;
524 req_reply_error(req, status);
525 return;
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;
541 * TODO:
542 * don't know how to handle smb signing for this case
543 * so just skip the reply
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;
552 req_reply_error(req, status);
553 return;
556 smb_messages[type].fn(req);
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
563 void chain_reply(struct smbsrv_request *req)
565 uint16_t chain_cmd, chain_offset;
566 uint8_t *vwv, *data;
567 uint16_t wct;
568 uint16_t data_size;
570 if (req->in.wct < 2 || req->out.wct < 2) {
571 req_reply_dos_error(req, ERRSRV, ERRerror);
572 return;
575 chain_cmd = CVAL(req->in.vwv, VWV(0));
576 chain_offset = SVAL(req->in.vwv, VWV(1));
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;
586 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
587 goto error;
590 wct = CVAL(req->in.hdr, chain_offset);
591 vwv = req->in.hdr + chain_offset + 1;
593 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
594 goto error;
597 data_size = SVAL(vwv, VWV(wct));
598 data = vwv + VWV(wct) + 2;
600 if (data + data_size > req->in.buffer + req->in.size) {
601 goto error;
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;
611 req->chain_count++;
613 SSVAL(req->out.vwv, VWV(0), chain_cmd);
614 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
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);
620 switch_message(chain_cmd, req);
621 return;
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);
630 * init the SMB protocol related stuff
632 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn)
634 NTSTATUS status;
636 /* now initialise a few default values associated with this smb socket */
637 smb_conn->negotiate.max_send = 0xFFFF;
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();
643 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
645 smb_conn->config.security = lp_security();
646 smb_conn->config.nt_status_support = lp_nt_status_support();
648 status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
649 NT_STATUS_NOT_OK_RETURN(status);
651 status = smbsrv_init_tcons(smb_conn, UINT16_MAX);
652 NT_STATUS_NOT_OK_RETURN(status);
654 srv_init_signing(smb_conn);
656 return NT_STATUS_OK;