2 Unix SMB/CIFS implementation.
3 process incoming packets - main loop
4 Copyright (C) Andrew Tridgell 1992-2003
5 Copyright (C) James J Myers 2003 <myersjj@samba.org>
6 Copyright (C) Stefan Metzmacher 2004
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.
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"
33 send an oplock break request to a client
35 BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
37 struct smbsrv_request *req;
39 req = init_smb_request(tcon->smb_conn);
41 req_setup_reply(req, 8, 0);
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);
51 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
52 SSVAL(req->out.vwv, VWV(1), 0);
53 SSVAL(req->out.vwv, VWV(2), fnum);
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);
65 static void construct_reply(struct smbsrv_request *req);
67 /****************************************************************************
68 receive a SMB request header from the wire, forming a request_context
70 ****************************************************************************/
71 static NTSTATUS receive_smb_request(struct smbsrv_connection *smb_conn)
75 struct smbsrv_request *req;
78 /* allocate the request if needed */
79 if (smb_conn->partial_req == NULL) {
80 req = init_smb_request(smb_conn);
82 return NT_STATUS_NO_MEMORY;
85 req->in.buffer = talloc_array(req, uint8_t, NBT_HDR_SIZE);
86 if (req->in.buffer == NULL) {
88 return NT_STATUS_NO_MEMORY;
91 smb_conn->partial_req = req;
94 req = smb_conn->partial_req;
96 /* read in the header */
97 if (req->in.size < NBT_HDR_SIZE) {
98 status = socket_recv(smb_conn->connection->socket,
99 req->in.buffer + req->in.size,
100 NBT_HDR_SIZE - req->in.size,
102 if (NT_STATUS_IS_ERR(status)) {
105 if (!NT_STATUS_IS_OK(status)) {
109 return NT_STATUS_END_OF_FILE;
111 req->in.size += nread;
113 /* when we have a full NBT header, then allocate the packet */
114 if (req->in.size == NBT_HDR_SIZE) {
115 len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
116 req->in.buffer = talloc_realloc(req, req->in.buffer,
118 if (req->in.buffer == NULL) {
119 return NT_STATUS_NO_MEMORY;
126 /* read in the main packet */
127 len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
129 status = socket_recv(smb_conn->connection->socket,
130 req->in.buffer + req->in.size,
133 if (NT_STATUS_IS_ERR(status)) {
136 if (!NT_STATUS_IS_OK(status)) {
140 return NT_STATUS_END_OF_FILE;
143 req->in.size += nread;
145 if (req->in.size != len) {
149 /* we have a full packet */
150 req->request_time = timeval_current();
151 req->chained_fnum = -1;
152 req->in.allocated = req->in.size;
153 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
154 req->in.vwv = req->in.hdr + HDR_VWV;
155 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
156 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
157 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
158 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
160 /* the bcc length is only 16 bits, but some packets
161 (such as SMBwriteX) can be much larger than 64k. We
162 detect this by looking for a large non-chained NBT
163 packet (at least 64k bigger than what is
164 specified). If it is detected then the NBT size is
165 used instead of the bcc size */
166 if (req->in.data_size + 0x10000 <=
167 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
168 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
169 /* its an oversized packet! fun for all the family */
170 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
174 smb_conn->partial_req = NULL;
176 construct_reply(req);
182 These flags determine some of the permissions required to do an operation
184 #define AS_USER (1<<0)
187 define a list of possible SMB messages and their corresponding
188 functions. Any message that has a NULL function is unimplemented -
189 please feel free to contribute implementations!
191 static const struct smb_message_struct
194 void (*fn)(struct smbsrv_request *);
197 smb_messages[256] = {
198 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER},
199 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER},
200 /* 0x02 */ { "SMBopen",reply_open,AS_USER},
201 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
202 /* 0x04 */ { "SMBclose",reply_close,AS_USER},
203 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
204 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER},
205 /* 0x07 */ { "SMBmv",reply_mv,AS_USER},
206 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
207 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER},
208 /* 0x0a */ { "SMBread",reply_read,AS_USER},
209 /* 0x0b */ { "SMBwrite",reply_write,AS_USER},
210 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
211 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
212 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
213 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
214 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
215 /* 0x11 */ { "SMBexit",reply_exit,0},
216 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
217 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
218 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
219 /* 0x15 */ { NULL, NULL, 0 },
220 /* 0x16 */ { NULL, NULL, 0 },
221 /* 0x17 */ { NULL, NULL, 0 },
222 /* 0x18 */ { NULL, NULL, 0 },
223 /* 0x19 */ { NULL, NULL, 0 },
224 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
225 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
226 /* 0x1c */ { "SMBreadBs",NULL,0 },
227 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
228 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
229 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
230 /* 0x20 */ { "SMBwritec",NULL,0},
231 /* 0x21 */ { NULL, NULL, 0 },
232 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER},
233 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER},
234 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER},
235 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER},
236 /* 0x26 */ { "SMBtranss",reply_transs,AS_USER},
237 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
238 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
239 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER},
240 /* 0x2a */ { "SMBmove",NULL,AS_USER},
241 /* 0x2b */ { "SMBecho",reply_echo,0},
242 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
243 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER},
244 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER},
245 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER},
246 /* 0x30 */ { NULL, NULL, 0 },
247 /* 0x31 */ { NULL, NULL, 0 },
248 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER},
249 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
250 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
251 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
252 /* 0x36 */ { NULL, NULL, 0 },
253 /* 0x37 */ { NULL, NULL, 0 },
254 /* 0x38 */ { NULL, NULL, 0 },
255 /* 0x39 */ { NULL, NULL, 0 },
256 /* 0x3a */ { NULL, NULL, 0 },
257 /* 0x3b */ { NULL, NULL, 0 },
258 /* 0x3c */ { NULL, NULL, 0 },
259 /* 0x3d */ { NULL, NULL, 0 },
260 /* 0x3e */ { NULL, NULL, 0 },
261 /* 0x3f */ { NULL, NULL, 0 },
262 /* 0x40 */ { NULL, NULL, 0 },
263 /* 0x41 */ { NULL, NULL, 0 },
264 /* 0x42 */ { NULL, NULL, 0 },
265 /* 0x43 */ { NULL, NULL, 0 },
266 /* 0x44 */ { NULL, NULL, 0 },
267 /* 0x45 */ { NULL, NULL, 0 },
268 /* 0x46 */ { NULL, NULL, 0 },
269 /* 0x47 */ { NULL, NULL, 0 },
270 /* 0x48 */ { NULL, NULL, 0 },
271 /* 0x49 */ { NULL, NULL, 0 },
272 /* 0x4a */ { NULL, NULL, 0 },
273 /* 0x4b */ { NULL, NULL, 0 },
274 /* 0x4c */ { NULL, NULL, 0 },
275 /* 0x4d */ { NULL, NULL, 0 },
276 /* 0x4e */ { NULL, NULL, 0 },
277 /* 0x4f */ { NULL, NULL, 0 },
278 /* 0x50 */ { NULL, NULL, 0 },
279 /* 0x51 */ { NULL, NULL, 0 },
280 /* 0x52 */ { NULL, NULL, 0 },
281 /* 0x53 */ { NULL, NULL, 0 },
282 /* 0x54 */ { NULL, NULL, 0 },
283 /* 0x55 */ { NULL, NULL, 0 },
284 /* 0x56 */ { NULL, NULL, 0 },
285 /* 0x57 */ { NULL, NULL, 0 },
286 /* 0x58 */ { NULL, NULL, 0 },
287 /* 0x59 */ { NULL, NULL, 0 },
288 /* 0x5a */ { NULL, NULL, 0 },
289 /* 0x5b */ { NULL, NULL, 0 },
290 /* 0x5c */ { NULL, NULL, 0 },
291 /* 0x5d */ { NULL, NULL, 0 },
292 /* 0x5e */ { NULL, NULL, 0 },
293 /* 0x5f */ { NULL, NULL, 0 },
294 /* 0x60 */ { NULL, NULL, 0 },
295 /* 0x61 */ { NULL, NULL, 0 },
296 /* 0x62 */ { NULL, NULL, 0 },
297 /* 0x63 */ { NULL, NULL, 0 },
298 /* 0x64 */ { NULL, NULL, 0 },
299 /* 0x65 */ { NULL, NULL, 0 },
300 /* 0x66 */ { NULL, NULL, 0 },
301 /* 0x67 */ { NULL, NULL, 0 },
302 /* 0x68 */ { NULL, NULL, 0 },
303 /* 0x69 */ { NULL, NULL, 0 },
304 /* 0x6a */ { NULL, NULL, 0 },
305 /* 0x6b */ { NULL, NULL, 0 },
306 /* 0x6c */ { NULL, NULL, 0 },
307 /* 0x6d */ { NULL, NULL, 0 },
308 /* 0x6e */ { NULL, NULL, 0 },
309 /* 0x6f */ { NULL, NULL, 0 },
310 /* 0x70 */ { "SMBtcon",reply_tcon,0},
311 /* 0x71 */ { "SMBtdis",reply_tdis,0},
312 /* 0x72 */ { "SMBnegprot",reply_negprot,0},
313 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,0},
314 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
315 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
316 /* 0x76 */ { NULL, NULL, 0 },
317 /* 0x77 */ { NULL, NULL, 0 },
318 /* 0x78 */ { NULL, NULL, 0 },
319 /* 0x79 */ { NULL, NULL, 0 },
320 /* 0x7a */ { NULL, NULL, 0 },
321 /* 0x7b */ { NULL, NULL, 0 },
322 /* 0x7c */ { NULL, NULL, 0 },
323 /* 0x7d */ { NULL, NULL, 0 },
324 /* 0x7e */ { NULL, NULL, 0 },
325 /* 0x7f */ { NULL, NULL, 0 },
326 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
327 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
328 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
329 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
330 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
331 /* 0x85 */ { NULL, NULL, 0 },
332 /* 0x86 */ { NULL, NULL, 0 },
333 /* 0x87 */ { NULL, NULL, 0 },
334 /* 0x88 */ { NULL, NULL, 0 },
335 /* 0x89 */ { NULL, NULL, 0 },
336 /* 0x8a */ { NULL, NULL, 0 },
337 /* 0x8b */ { NULL, NULL, 0 },
338 /* 0x8c */ { NULL, NULL, 0 },
339 /* 0x8d */ { NULL, NULL, 0 },
340 /* 0x8e */ { NULL, NULL, 0 },
341 /* 0x8f */ { NULL, NULL, 0 },
342 /* 0x90 */ { NULL, NULL, 0 },
343 /* 0x91 */ { NULL, NULL, 0 },
344 /* 0x92 */ { NULL, NULL, 0 },
345 /* 0x93 */ { NULL, NULL, 0 },
346 /* 0x94 */ { NULL, NULL, 0 },
347 /* 0x95 */ { NULL, NULL, 0 },
348 /* 0x96 */ { NULL, NULL, 0 },
349 /* 0x97 */ { NULL, NULL, 0 },
350 /* 0x98 */ { NULL, NULL, 0 },
351 /* 0x99 */ { NULL, NULL, 0 },
352 /* 0x9a */ { NULL, NULL, 0 },
353 /* 0x9b */ { NULL, NULL, 0 },
354 /* 0x9c */ { NULL, NULL, 0 },
355 /* 0x9d */ { NULL, NULL, 0 },
356 /* 0x9e */ { NULL, NULL, 0 },
357 /* 0x9f */ { NULL, NULL, 0 },
358 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER},
359 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER},
360 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER},
361 /* 0xa3 */ { NULL, NULL, 0 },
362 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
363 /* 0xa5 */ { "SMBntrename", reply_ntrename, 0 },
364 /* 0xa6 */ { NULL, NULL, 0 },
365 /* 0xa7 */ { NULL, NULL, 0 },
366 /* 0xa8 */ { NULL, NULL, 0 },
367 /* 0xa9 */ { NULL, NULL, 0 },
368 /* 0xaa */ { NULL, NULL, 0 },
369 /* 0xab */ { NULL, NULL, 0 },
370 /* 0xac */ { NULL, NULL, 0 },
371 /* 0xad */ { NULL, NULL, 0 },
372 /* 0xae */ { NULL, NULL, 0 },
373 /* 0xaf */ { NULL, NULL, 0 },
374 /* 0xb0 */ { NULL, NULL, 0 },
375 /* 0xb1 */ { NULL, NULL, 0 },
376 /* 0xb2 */ { NULL, NULL, 0 },
377 /* 0xb3 */ { NULL, NULL, 0 },
378 /* 0xb4 */ { NULL, NULL, 0 },
379 /* 0xb5 */ { NULL, NULL, 0 },
380 /* 0xb6 */ { NULL, NULL, 0 },
381 /* 0xb7 */ { NULL, NULL, 0 },
382 /* 0xb8 */ { NULL, NULL, 0 },
383 /* 0xb9 */ { NULL, NULL, 0 },
384 /* 0xba */ { NULL, NULL, 0 },
385 /* 0xbb */ { NULL, NULL, 0 },
386 /* 0xbc */ { NULL, NULL, 0 },
387 /* 0xbd */ { NULL, NULL, 0 },
388 /* 0xbe */ { NULL, NULL, 0 },
389 /* 0xbf */ { NULL, NULL, 0 },
390 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
391 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
392 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
393 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
394 /* 0xc4 */ { NULL, NULL, 0 },
395 /* 0xc5 */ { NULL, NULL, 0 },
396 /* 0xc6 */ { NULL, NULL, 0 },
397 /* 0xc7 */ { NULL, NULL, 0 },
398 /* 0xc8 */ { NULL, NULL, 0 },
399 /* 0xc9 */ { NULL, NULL, 0 },
400 /* 0xca */ { NULL, NULL, 0 },
401 /* 0xcb */ { NULL, NULL, 0 },
402 /* 0xcc */ { NULL, NULL, 0 },
403 /* 0xcd */ { NULL, NULL, 0 },
404 /* 0xce */ { NULL, NULL, 0 },
405 /* 0xcf */ { NULL, NULL, 0 },
406 /* 0xd0 */ { "SMBsends",reply_sends,0},
407 /* 0xd1 */ { "SMBsendb",NULL,0},
408 /* 0xd2 */ { "SMBfwdname",NULL,0},
409 /* 0xd3 */ { "SMBcancelf",NULL,0},
410 /* 0xd4 */ { "SMBgetmac",NULL,0},
411 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,0},
412 /* 0xd6 */ { "SMBsendend",reply_sendend,0},
413 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,0},
414 /* 0xd8 */ { NULL, NULL, 0 },
415 /* 0xd9 */ { NULL, NULL, 0 },
416 /* 0xda */ { NULL, NULL, 0 },
417 /* 0xdb */ { NULL, NULL, 0 },
418 /* 0xdc */ { NULL, NULL, 0 },
419 /* 0xdd */ { NULL, NULL, 0 },
420 /* 0xde */ { NULL, NULL, 0 },
421 /* 0xdf */ { NULL, NULL, 0 },
422 /* 0xe0 */ { NULL, NULL, 0 },
423 /* 0xe1 */ { NULL, NULL, 0 },
424 /* 0xe2 */ { NULL, NULL, 0 },
425 /* 0xe3 */ { NULL, NULL, 0 },
426 /* 0xe4 */ { NULL, NULL, 0 },
427 /* 0xe5 */ { NULL, NULL, 0 },
428 /* 0xe6 */ { NULL, NULL, 0 },
429 /* 0xe7 */ { NULL, NULL, 0 },
430 /* 0xe8 */ { NULL, NULL, 0 },
431 /* 0xe9 */ { NULL, NULL, 0 },
432 /* 0xea */ { NULL, NULL, 0 },
433 /* 0xeb */ { NULL, NULL, 0 },
434 /* 0xec */ { NULL, NULL, 0 },
435 /* 0xed */ { NULL, NULL, 0 },
436 /* 0xee */ { NULL, NULL, 0 },
437 /* 0xef */ { NULL, NULL, 0 },
438 /* 0xf0 */ { NULL, NULL, 0 },
439 /* 0xf1 */ { NULL, NULL, 0 },
440 /* 0xf2 */ { NULL, NULL, 0 },
441 /* 0xf3 */ { NULL, NULL, 0 },
442 /* 0xf4 */ { NULL, NULL, 0 },
443 /* 0xf5 */ { NULL, NULL, 0 },
444 /* 0xf6 */ { NULL, NULL, 0 },
445 /* 0xf7 */ { NULL, NULL, 0 },
446 /* 0xf8 */ { NULL, NULL, 0 },
447 /* 0xf9 */ { NULL, NULL, 0 },
448 /* 0xfa */ { NULL, NULL, 0 },
449 /* 0xfb */ { NULL, NULL, 0 },
450 /* 0xfc */ { NULL, NULL, 0 },
451 /* 0xfd */ { NULL, NULL, 0 },
452 /* 0xfe */ { NULL, NULL, 0 },
453 /* 0xff */ { NULL, NULL, 0 }
456 /****************************************************************************
457 return a string containing the function name of a SMB command
458 ****************************************************************************/
459 static const char *smb_fn_name(uint8_t type)
461 const char *unknown_name = "SMBunknown";
463 if (smb_messages[type].name == NULL)
466 return smb_messages[type].name;
470 /****************************************************************************
471 Do a switch on the message type and call the specific reply function for this
472 message. Unlike earlier versions of Samba the reply functions are responsible
473 for sending the reply themselves, rather than returning a size to this function
474 The reply functions may also choose to delay the processing by pushing the message
475 onto the message queue
476 ****************************************************************************/
477 static void switch_message(int type, struct smbsrv_request *req)
480 struct smbsrv_connection *smb_conn = req->smb_conn;
481 uint16_t session_tag;
487 if (smb_messages[type].fn == NULL) {
488 DEBUG(0,("Unknown message type %d!\n",type));
493 flags = smb_messages[type].flags;
495 req->tcon = smbsrv_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
497 if (req->session == NULL) {
498 /* setup the user context for this request if it
499 hasn't already been initialised (to cope with SMB
502 /* In share mode security we must ignore the vuid. */
503 if (lp_security() == SEC_SHARE) {
504 session_tag = UID_FIELD_INVALID;
506 session_tag = SVAL(req->in.hdr,HDR_UID);
509 req->session = smbsrv_session_find(req->smb_conn, session_tag);
511 req->session->vuid = session_tag;
514 session_tag = req->session->vuid;
517 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id));
519 /* does this protocol need a valid tree connection? */
520 if ((flags & AS_USER) && !req->tcon) {
521 if (type == SMBntcreateX) {
522 /* amazingly, the error code depends on the command */
523 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRinvnid));
525 req_reply_error(req, NT_STATUS_INVALID_HANDLE);
530 /* see if the vuid is valid */
531 if ((flags & AS_USER) && !req->session) {
532 req_reply_error(req, NT_STATUS_INVALID_HANDLE);
536 smb_messages[type].fn(req);
540 /****************************************************************************
541 Construct a reply to the incoming packet.
542 ****************************************************************************/
543 static void construct_reply(struct smbsrv_request *req)
545 uint8_t type = CVAL(req->in.hdr,HDR_COM);
547 /* see if its a special NBT packet */
548 if (CVAL(req->in.buffer,0) != 0) {
553 /* Make sure this is an SMB packet */
554 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
555 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
557 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
561 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
562 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
563 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
567 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
568 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
569 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
573 req->flags = CVAL(req->in.hdr, HDR_FLG);
574 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
575 req->smbpid = SVAL(req->in.hdr,HDR_PID);
577 if (!req_signing_check_incoming(req)) {
578 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
582 switch_message(type, req);
587 we call this when first first part of a possibly chained request has been completed
588 and we need to call the 2nd part, if any
590 void chain_reply(struct smbsrv_request *req)
592 uint16_t chain_cmd, chain_offset;
597 if (req->in.wct < 2 || req->out.wct < 2) {
598 req_reply_dos_error(req, ERRSRV, ERRerror);
602 chain_cmd = CVAL(req->in.vwv, VWV(0));
603 chain_offset = SVAL(req->in.vwv, VWV(1));
605 if (chain_cmd == SMB_CHAIN_NONE) {
607 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
608 SSVAL(req->out.vwv, VWV(1), 0);
613 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
617 wct = CVAL(req->in.hdr, chain_offset);
618 vwv = req->in.hdr + chain_offset + 1;
620 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
624 data_size = SVAL(vwv, VWV(wct));
625 data = vwv + VWV(wct) + 2;
627 if (data + data_size > req->in.buffer + req->in.size) {
631 /* all seems legit */
635 req->in.data_size = data_size;
640 SSVAL(req->out.vwv, VWV(0), chain_cmd);
641 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
643 /* the current request in the chain might have used an async reply,
644 but that doesn't mean the next element needs to */
645 ZERO_STRUCTP(req->async_states);
647 switch_message(chain_cmd, req);
651 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
652 SSVAL(req->out.vwv, VWV(1), 0);
653 req_reply_dos_error(req, ERRSRV, ERRerror);
658 close the socket and shutdown a server_context
660 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
662 stream_terminate_connection(smb_conn->connection, reason);
666 called when a SMB socket becomes readable
668 static void smbsrv_recv(struct stream_connection *conn, uint16_t flags)
670 struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
673 DEBUG(10,("smbsrv_recv\n"));
675 /* our backends are designed to process one request at a time,
676 unless they deliberately mark the request as async and
677 process it later on a timer or other event. This enforces
679 if (smb_conn->processing) {
680 EVENT_FD_NOT_READABLE(conn->event.fde);
684 smb_conn->processing = True;
685 status = receive_smb_request(smb_conn);
686 smb_conn->processing = False;
687 if (NT_STATUS_IS_ERR(status)) {
688 talloc_free(conn->event.fde);
689 conn->event.fde = NULL;
690 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
694 EVENT_FD_READABLE(conn->event.fde);
696 /* free up temporary memory */
701 called when a SMB socket becomes writable
703 static void smbsrv_send(struct stream_connection *conn, uint16_t flags)
705 struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
707 while (smb_conn->pending_send) {
708 struct smbsrv_request *req = smb_conn->pending_send;
713 blob.data = req->out.buffer;
714 blob.length = req->out.size;
716 /* send as much of this request as we can */
717 status = socket_send(conn->socket, &blob, &sendlen, 0);
718 if (NT_STATUS_IS_ERR(status)) {
719 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
726 req->out.buffer += sendlen;
727 req->out.size -= sendlen;
729 /* is the whole request gone? */
730 if (req->out.size == 0) {
731 DLIST_REMOVE(smb_conn->pending_send, req);
736 /* if no more requests are pending to be sent then
737 we should stop select for write */
738 if (smb_conn->pending_send == NULL) {
739 EVENT_FD_NOT_WRITEABLE(conn->event.fde);
744 initialise a server_context from a open socket and register a event handler
745 for reading from that socket
747 static void smbsrv_accept(struct stream_connection *conn)
749 struct smbsrv_connection *smb_conn;
751 DEBUG(5,("smbsrv_accept\n"));
753 smb_conn = talloc_zero(conn, struct smbsrv_connection);
754 if (!smb_conn) return;
756 /* now initialise a few default values associated with this smb socket */
757 smb_conn->negotiate.max_send = 0xFFFF;
759 /* this is the size that w2k uses, and it appears to be important for
761 smb_conn->negotiate.max_recv = lp_max_xmit();
763 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
765 smbsrv_vuid_init(smb_conn);
767 srv_init_signing(smb_conn);
769 smbsrv_tcon_init(smb_conn);
771 smb_conn->connection = conn;
772 smb_conn->processing = False;
774 conn->private = smb_conn;
776 irpc_add_name(conn->msg_ctx, "smb_server");
778 smbsrv_management_init(smb_conn);
782 static const struct stream_server_ops smb_stream_ops = {
784 .accept_connection = smbsrv_accept,
785 .recv_handler = smbsrv_recv,
786 .send_handler = smbsrv_send,
790 setup a listening socket on all the SMB ports for a particular address
792 static NTSTATUS smb_add_socket(struct event_context *event_context,
793 const struct model_ops *model_ops,
796 const char **ports = lp_smb_ports();
800 for (i=0;ports[i];i++) {
801 uint16_t port = atoi(ports[i]);
802 if (port == 0) continue;
803 status = stream_setup_socket(event_context, model_ops, &smb_stream_ops,
804 "ipv4", address, &port, NULL);
805 NT_STATUS_NOT_OK_RETURN(status);
812 called on startup of the smb server service It's job is to start
813 listening on all configured SMB server sockets
815 static NTSTATUS smbsrv_init(struct event_context *event_context, const struct model_ops *model_ops)
819 if (lp_interfaces() && lp_bind_interfaces_only()) {
820 int num_interfaces = iface_count();
823 /* We have been given an interfaces line, and been
824 told to only bind to those interfaces. Create a
825 socket per interface and bind to only these.
827 for(i = 0; i < num_interfaces; i++) {
828 const char *address = iface_n_ip(i);
829 status = smb_add_socket(event_context, model_ops, address);
830 NT_STATUS_NOT_OK_RETURN(status);
833 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
834 status = smb_add_socket(event_context, model_ops, lp_socket_address());
835 NT_STATUS_NOT_OK_RETURN(status);
841 /* called at smbd startup - register ourselves as a server service */
842 NTSTATUS server_service_smb_init(void)
844 return register_server_service("smb", smbsrv_init);