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"
32 send an oplock break request to a client
34 BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
36 struct smbsrv_request *req;
38 req = init_smb_request(tcon->smb_conn);
40 req_setup_reply(req, 8, 0);
42 SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
43 SSVAL(req->out.hdr,HDR_TID,tcon->tid);
44 SSVAL(req->out.hdr,HDR_PID,0xFFFF);
45 SSVAL(req->out.hdr,HDR_UID,0);
46 SSVAL(req->out.hdr,HDR_MID,0xFFFF);
47 SCVAL(req->out.hdr,HDR_FLG,0);
48 SSVAL(req->out.hdr,HDR_FLG2,0);
50 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
51 SSVAL(req->out.vwv, VWV(1), 0);
52 SSVAL(req->out.vwv, VWV(2), fnum);
53 SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
54 SCVAL(req->out.vwv, VWV(3)+1, level);
55 SIVAL(req->out.vwv, VWV(4), 0);
56 SSVAL(req->out.vwv, VWV(6), 0);
57 SSVAL(req->out.vwv, VWV(7), 0);
64 static void construct_reply(struct smbsrv_request *req);
66 /****************************************************************************
67 receive a SMB request header from the wire, forming a request_context
69 ****************************************************************************/
70 static NTSTATUS receive_smb_request(struct smbsrv_connection *smb_conn)
74 struct smbsrv_request *req;
77 /* allocate the request if needed */
78 if (smb_conn->partial_req == NULL) {
79 req = init_smb_request(smb_conn);
81 return NT_STATUS_NO_MEMORY;
84 req->in.buffer = talloc_array(req, uint8_t, NBT_HDR_SIZE);
85 if (req->in.buffer == NULL) {
87 return NT_STATUS_NO_MEMORY;
90 smb_conn->partial_req = req;
93 req = smb_conn->partial_req;
95 /* read in the header */
96 if (req->in.size < NBT_HDR_SIZE) {
97 status = socket_recv(smb_conn->connection->socket,
98 req->in.buffer + req->in.size,
99 NBT_HDR_SIZE - req->in.size,
101 if (NT_STATUS_IS_ERR(status)) {
107 req->in.size += nread;
109 /* when we have a full NBT header, then allocate the packet */
110 if (req->in.size == NBT_HDR_SIZE) {
111 len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
112 req->in.buffer = talloc_realloc(req, req->in.buffer,
114 if (req->in.buffer == NULL) {
115 return NT_STATUS_NO_MEMORY;
122 /* read in the main packet */
123 len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
125 status = socket_recv(smb_conn->connection->socket,
126 req->in.buffer + req->in.size,
129 if (NT_STATUS_IS_ERR(status)) {
136 req->in.size += nread;
138 if (req->in.size != len) {
142 /* we have a full packet */
143 req->request_time = timeval_current();
144 req->chained_fnum = -1;
145 req->in.allocated = req->in.size;
146 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
147 req->in.vwv = req->in.hdr + HDR_VWV;
148 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
149 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
150 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
151 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
153 /* the bcc length is only 16 bits, but some packets
154 (such as SMBwriteX) can be much larger than 64k. We
155 detect this by looking for a large non-chained NBT
156 packet (at least 64k bigger than what is
157 specified). If it is detected then the NBT size is
158 used instead of the bcc size */
159 if (req->in.data_size + 0x10000 <=
160 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
161 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
162 /* its an oversized packet! fun for all the family */
163 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
167 smb_conn->partial_req = NULL;
169 construct_reply(req);
175 These flags determine some of the permissions required to do an operation
177 #define AS_USER (1<<0)
180 define a list of possible SMB messages and their corresponding
181 functions. Any message that has a NULL function is unimplemented -
182 please feel free to contribute implementations!
184 static const struct smb_message_struct
187 void (*fn)(struct smbsrv_request *);
190 smb_messages[256] = {
191 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER},
192 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER},
193 /* 0x02 */ { "SMBopen",reply_open,AS_USER},
194 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
195 /* 0x04 */ { "SMBclose",reply_close,AS_USER},
196 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
197 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER},
198 /* 0x07 */ { "SMBmv",reply_mv,AS_USER},
199 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
200 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER},
201 /* 0x0a */ { "SMBread",reply_read,AS_USER},
202 /* 0x0b */ { "SMBwrite",reply_write,AS_USER},
203 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
204 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
205 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
206 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
207 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
208 /* 0x11 */ { "SMBexit",reply_exit,0},
209 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
210 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
211 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
212 /* 0x15 */ { NULL, NULL, 0 },
213 /* 0x16 */ { NULL, NULL, 0 },
214 /* 0x17 */ { NULL, NULL, 0 },
215 /* 0x18 */ { NULL, NULL, 0 },
216 /* 0x19 */ { NULL, NULL, 0 },
217 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
218 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
219 /* 0x1c */ { "SMBreadBs",NULL,0 },
220 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
221 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
222 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
223 /* 0x20 */ { "SMBwritec",NULL,0},
224 /* 0x21 */ { NULL, NULL, 0 },
225 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER},
226 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER},
227 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER},
228 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER},
229 /* 0x26 */ { "SMBtranss",reply_transs,AS_USER},
230 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
231 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
232 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER},
233 /* 0x2a */ { "SMBmove",NULL,AS_USER},
234 /* 0x2b */ { "SMBecho",reply_echo,0},
235 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
236 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER},
237 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER},
238 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER},
239 /* 0x30 */ { NULL, NULL, 0 },
240 /* 0x31 */ { NULL, NULL, 0 },
241 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER},
242 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
243 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
244 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
245 /* 0x36 */ { NULL, NULL, 0 },
246 /* 0x37 */ { NULL, NULL, 0 },
247 /* 0x38 */ { NULL, NULL, 0 },
248 /* 0x39 */ { NULL, NULL, 0 },
249 /* 0x3a */ { NULL, NULL, 0 },
250 /* 0x3b */ { NULL, NULL, 0 },
251 /* 0x3c */ { NULL, NULL, 0 },
252 /* 0x3d */ { NULL, NULL, 0 },
253 /* 0x3e */ { NULL, NULL, 0 },
254 /* 0x3f */ { NULL, NULL, 0 },
255 /* 0x40 */ { NULL, NULL, 0 },
256 /* 0x41 */ { NULL, NULL, 0 },
257 /* 0x42 */ { NULL, NULL, 0 },
258 /* 0x43 */ { NULL, NULL, 0 },
259 /* 0x44 */ { NULL, NULL, 0 },
260 /* 0x45 */ { NULL, NULL, 0 },
261 /* 0x46 */ { NULL, NULL, 0 },
262 /* 0x47 */ { NULL, NULL, 0 },
263 /* 0x48 */ { NULL, NULL, 0 },
264 /* 0x49 */ { NULL, NULL, 0 },
265 /* 0x4a */ { NULL, NULL, 0 },
266 /* 0x4b */ { NULL, NULL, 0 },
267 /* 0x4c */ { NULL, NULL, 0 },
268 /* 0x4d */ { NULL, NULL, 0 },
269 /* 0x4e */ { NULL, NULL, 0 },
270 /* 0x4f */ { NULL, NULL, 0 },
271 /* 0x50 */ { NULL, NULL, 0 },
272 /* 0x51 */ { NULL, NULL, 0 },
273 /* 0x52 */ { NULL, NULL, 0 },
274 /* 0x53 */ { NULL, NULL, 0 },
275 /* 0x54 */ { NULL, NULL, 0 },
276 /* 0x55 */ { NULL, NULL, 0 },
277 /* 0x56 */ { NULL, NULL, 0 },
278 /* 0x57 */ { NULL, NULL, 0 },
279 /* 0x58 */ { NULL, NULL, 0 },
280 /* 0x59 */ { NULL, NULL, 0 },
281 /* 0x5a */ { NULL, NULL, 0 },
282 /* 0x5b */ { NULL, NULL, 0 },
283 /* 0x5c */ { NULL, NULL, 0 },
284 /* 0x5d */ { NULL, NULL, 0 },
285 /* 0x5e */ { NULL, NULL, 0 },
286 /* 0x5f */ { NULL, NULL, 0 },
287 /* 0x60 */ { NULL, NULL, 0 },
288 /* 0x61 */ { NULL, NULL, 0 },
289 /* 0x62 */ { NULL, NULL, 0 },
290 /* 0x63 */ { NULL, NULL, 0 },
291 /* 0x64 */ { NULL, NULL, 0 },
292 /* 0x65 */ { NULL, NULL, 0 },
293 /* 0x66 */ { NULL, NULL, 0 },
294 /* 0x67 */ { NULL, NULL, 0 },
295 /* 0x68 */ { NULL, NULL, 0 },
296 /* 0x69 */ { NULL, NULL, 0 },
297 /* 0x6a */ { NULL, NULL, 0 },
298 /* 0x6b */ { NULL, NULL, 0 },
299 /* 0x6c */ { NULL, NULL, 0 },
300 /* 0x6d */ { NULL, NULL, 0 },
301 /* 0x6e */ { NULL, NULL, 0 },
302 /* 0x6f */ { NULL, NULL, 0 },
303 /* 0x70 */ { "SMBtcon",reply_tcon,0},
304 /* 0x71 */ { "SMBtdis",reply_tdis,0},
305 /* 0x72 */ { "SMBnegprot",reply_negprot,0},
306 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,0},
307 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
308 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
309 /* 0x76 */ { NULL, NULL, 0 },
310 /* 0x77 */ { NULL, NULL, 0 },
311 /* 0x78 */ { NULL, NULL, 0 },
312 /* 0x79 */ { NULL, NULL, 0 },
313 /* 0x7a */ { NULL, NULL, 0 },
314 /* 0x7b */ { NULL, NULL, 0 },
315 /* 0x7c */ { NULL, NULL, 0 },
316 /* 0x7d */ { NULL, NULL, 0 },
317 /* 0x7e */ { NULL, NULL, 0 },
318 /* 0x7f */ { NULL, NULL, 0 },
319 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
320 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
321 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
322 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
323 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
324 /* 0x85 */ { NULL, NULL, 0 },
325 /* 0x86 */ { NULL, NULL, 0 },
326 /* 0x87 */ { NULL, NULL, 0 },
327 /* 0x88 */ { NULL, NULL, 0 },
328 /* 0x89 */ { NULL, NULL, 0 },
329 /* 0x8a */ { NULL, NULL, 0 },
330 /* 0x8b */ { NULL, NULL, 0 },
331 /* 0x8c */ { NULL, NULL, 0 },
332 /* 0x8d */ { NULL, NULL, 0 },
333 /* 0x8e */ { NULL, NULL, 0 },
334 /* 0x8f */ { NULL, NULL, 0 },
335 /* 0x90 */ { NULL, NULL, 0 },
336 /* 0x91 */ { NULL, NULL, 0 },
337 /* 0x92 */ { NULL, NULL, 0 },
338 /* 0x93 */ { NULL, NULL, 0 },
339 /* 0x94 */ { NULL, NULL, 0 },
340 /* 0x95 */ { NULL, NULL, 0 },
341 /* 0x96 */ { NULL, NULL, 0 },
342 /* 0x97 */ { NULL, NULL, 0 },
343 /* 0x98 */ { NULL, NULL, 0 },
344 /* 0x99 */ { NULL, NULL, 0 },
345 /* 0x9a */ { NULL, NULL, 0 },
346 /* 0x9b */ { NULL, NULL, 0 },
347 /* 0x9c */ { NULL, NULL, 0 },
348 /* 0x9d */ { NULL, NULL, 0 },
349 /* 0x9e */ { NULL, NULL, 0 },
350 /* 0x9f */ { NULL, NULL, 0 },
351 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER},
352 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER},
353 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER},
354 /* 0xa3 */ { NULL, NULL, 0 },
355 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
356 /* 0xa5 */ { "SMBntrename", reply_ntrename, 0 },
357 /* 0xa6 */ { NULL, NULL, 0 },
358 /* 0xa7 */ { NULL, NULL, 0 },
359 /* 0xa8 */ { NULL, NULL, 0 },
360 /* 0xa9 */ { NULL, NULL, 0 },
361 /* 0xaa */ { NULL, NULL, 0 },
362 /* 0xab */ { NULL, NULL, 0 },
363 /* 0xac */ { NULL, NULL, 0 },
364 /* 0xad */ { NULL, NULL, 0 },
365 /* 0xae */ { NULL, NULL, 0 },
366 /* 0xaf */ { NULL, NULL, 0 },
367 /* 0xb0 */ { NULL, NULL, 0 },
368 /* 0xb1 */ { NULL, NULL, 0 },
369 /* 0xb2 */ { NULL, NULL, 0 },
370 /* 0xb3 */ { NULL, NULL, 0 },
371 /* 0xb4 */ { NULL, NULL, 0 },
372 /* 0xb5 */ { NULL, NULL, 0 },
373 /* 0xb6 */ { NULL, NULL, 0 },
374 /* 0xb7 */ { NULL, NULL, 0 },
375 /* 0xb8 */ { NULL, NULL, 0 },
376 /* 0xb9 */ { NULL, NULL, 0 },
377 /* 0xba */ { NULL, NULL, 0 },
378 /* 0xbb */ { NULL, NULL, 0 },
379 /* 0xbc */ { NULL, NULL, 0 },
380 /* 0xbd */ { NULL, NULL, 0 },
381 /* 0xbe */ { NULL, NULL, 0 },
382 /* 0xbf */ { NULL, NULL, 0 },
383 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
384 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
385 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
386 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
387 /* 0xc4 */ { NULL, NULL, 0 },
388 /* 0xc5 */ { NULL, NULL, 0 },
389 /* 0xc6 */ { NULL, NULL, 0 },
390 /* 0xc7 */ { NULL, NULL, 0 },
391 /* 0xc8 */ { NULL, NULL, 0 },
392 /* 0xc9 */ { NULL, NULL, 0 },
393 /* 0xca */ { NULL, NULL, 0 },
394 /* 0xcb */ { NULL, NULL, 0 },
395 /* 0xcc */ { NULL, NULL, 0 },
396 /* 0xcd */ { NULL, NULL, 0 },
397 /* 0xce */ { NULL, NULL, 0 },
398 /* 0xcf */ { NULL, NULL, 0 },
399 /* 0xd0 */ { "SMBsends",reply_sends,0},
400 /* 0xd1 */ { "SMBsendb",NULL,0},
401 /* 0xd2 */ { "SMBfwdname",NULL,0},
402 /* 0xd3 */ { "SMBcancelf",NULL,0},
403 /* 0xd4 */ { "SMBgetmac",NULL,0},
404 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,0},
405 /* 0xd6 */ { "SMBsendend",reply_sendend,0},
406 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,0},
407 /* 0xd8 */ { NULL, NULL, 0 },
408 /* 0xd9 */ { NULL, NULL, 0 },
409 /* 0xda */ { NULL, NULL, 0 },
410 /* 0xdb */ { NULL, NULL, 0 },
411 /* 0xdc */ { NULL, NULL, 0 },
412 /* 0xdd */ { NULL, NULL, 0 },
413 /* 0xde */ { NULL, NULL, 0 },
414 /* 0xdf */ { NULL, NULL, 0 },
415 /* 0xe0 */ { NULL, NULL, 0 },
416 /* 0xe1 */ { NULL, NULL, 0 },
417 /* 0xe2 */ { NULL, NULL, 0 },
418 /* 0xe3 */ { NULL, NULL, 0 },
419 /* 0xe4 */ { NULL, NULL, 0 },
420 /* 0xe5 */ { NULL, NULL, 0 },
421 /* 0xe6 */ { NULL, NULL, 0 },
422 /* 0xe7 */ { NULL, NULL, 0 },
423 /* 0xe8 */ { NULL, NULL, 0 },
424 /* 0xe9 */ { NULL, NULL, 0 },
425 /* 0xea */ { NULL, NULL, 0 },
426 /* 0xeb */ { NULL, NULL, 0 },
427 /* 0xec */ { NULL, NULL, 0 },
428 /* 0xed */ { NULL, NULL, 0 },
429 /* 0xee */ { NULL, NULL, 0 },
430 /* 0xef */ { NULL, NULL, 0 },
431 /* 0xf0 */ { NULL, NULL, 0 },
432 /* 0xf1 */ { NULL, NULL, 0 },
433 /* 0xf2 */ { NULL, NULL, 0 },
434 /* 0xf3 */ { NULL, NULL, 0 },
435 /* 0xf4 */ { NULL, NULL, 0 },
436 /* 0xf5 */ { NULL, NULL, 0 },
437 /* 0xf6 */ { NULL, NULL, 0 },
438 /* 0xf7 */ { NULL, NULL, 0 },
439 /* 0xf8 */ { NULL, NULL, 0 },
440 /* 0xf9 */ { NULL, NULL, 0 },
441 /* 0xfa */ { NULL, NULL, 0 },
442 /* 0xfb */ { NULL, NULL, 0 },
443 /* 0xfc */ { NULL, NULL, 0 },
444 /* 0xfd */ { NULL, NULL, 0 },
445 /* 0xfe */ { NULL, NULL, 0 },
446 /* 0xff */ { NULL, NULL, 0 }
449 /****************************************************************************
450 return a string containing the function name of a SMB command
451 ****************************************************************************/
452 static const char *smb_fn_name(uint8_t type)
454 const char *unknown_name = "SMBunknown";
456 if (smb_messages[type].name == NULL)
459 return smb_messages[type].name;
463 /****************************************************************************
464 Do a switch on the message type and call the specific reply function for this
465 message. Unlike earlier versions of Samba the reply functions are responsible
466 for sending the reply themselves, rather than returning a size to this function
467 The reply functions may also choose to delay the processing by pushing the message
468 onto the message queue
469 ****************************************************************************/
470 static void switch_message(int type, struct smbsrv_request *req)
473 struct smbsrv_connection *smb_conn = req->smb_conn;
474 uint16_t session_tag;
480 if (smb_messages[type].fn == NULL) {
481 DEBUG(0,("Unknown message type %d!\n",type));
486 flags = smb_messages[type].flags;
488 req->tcon = smbsrv_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
490 if (req->session == NULL) {
491 /* setup the user context for this request if it
492 hasn't already been initialised (to cope with SMB
495 /* In share mode security we must ignore the vuid. */
496 if (lp_security() == SEC_SHARE) {
497 session_tag = UID_FIELD_INVALID;
499 session_tag = SVAL(req->in.hdr,HDR_UID);
502 req->session = smbsrv_session_find(req->smb_conn, session_tag);
504 req->session->vuid = session_tag;
507 session_tag = req->session->vuid;
510 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id));
512 /* does this protocol need a valid tree connection? */
513 if ((flags & AS_USER) && !req->tcon) {
514 if (type == SMBntcreateX) {
515 /* amazingly, the error code depends on the command */
516 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRinvnid));
518 req_reply_error(req, NT_STATUS_INVALID_HANDLE);
523 /* see if the vuid is valid */
524 if ((flags & AS_USER) && !req->session) {
525 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
529 smb_messages[type].fn(req);
533 /****************************************************************************
534 Construct a reply to the incoming packet.
535 ****************************************************************************/
536 static void construct_reply(struct smbsrv_request *req)
538 uint8_t type = CVAL(req->in.hdr,HDR_COM);
540 /* see if its a special NBT packet */
541 if (CVAL(req->in.buffer,0) != 0) {
546 /* Make sure this is an SMB packet */
547 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
548 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
550 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
554 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
555 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
556 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
560 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
561 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
562 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
566 req->flags = CVAL(req->in.hdr, HDR_FLG);
567 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
568 req->smbpid = SVAL(req->in.hdr,HDR_PID);
570 if (!req_signing_check_incoming(req)) {
571 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
575 switch_message(type, req);
580 we call this when first first part of a possibly chained request has been completed
581 and we need to call the 2nd part, if any
583 void chain_reply(struct smbsrv_request *req)
585 uint16_t chain_cmd, chain_offset;
590 if (req->in.wct < 2 || req->out.wct < 2) {
591 req_reply_dos_error(req, ERRSRV, ERRerror);
595 chain_cmd = CVAL(req->in.vwv, VWV(0));
596 chain_offset = SVAL(req->in.vwv, VWV(1));
598 if (chain_cmd == SMB_CHAIN_NONE) {
600 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
601 SSVAL(req->out.vwv, VWV(1), 0);
606 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
610 wct = CVAL(req->in.hdr, chain_offset);
611 vwv = req->in.hdr + chain_offset + 1;
613 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
617 data_size = SVAL(vwv, VWV(wct));
618 data = vwv + VWV(wct) + 2;
620 if (data + data_size > req->in.buffer + req->in.size) {
624 /* all seems legit */
628 req->in.data_size = data_size;
633 SSVAL(req->out.vwv, VWV(0), chain_cmd);
634 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
636 /* the current request in the chain might have used an async reply,
637 but that doesn't mean the next element needs to */
638 ZERO_STRUCTP(req->async_states);
640 switch_message(chain_cmd, req);
644 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
645 SSVAL(req->out.vwv, VWV(1), 0);
646 req_reply_dos_error(req, ERRSRV, ERRerror);
651 close the socket and shutdown a server_context
653 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
655 stream_terminate_connection(smb_conn->connection, reason);
659 called when a SMB socket becomes readable
661 static void smbsrv_recv(struct stream_connection *conn, uint16_t flags)
663 struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
666 DEBUG(10,("smbsrv_recv\n"));
668 status = receive_smb_request(smb_conn);
669 if (NT_STATUS_IS_ERR(status)) {
670 talloc_free(conn->event.fde);
671 conn->event.fde = NULL;
672 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
676 /* free up temporary memory */
681 called when a SMB socket becomes writable
683 static void smbsrv_send(struct stream_connection *conn, uint16_t flags)
685 struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
687 while (smb_conn->pending_send) {
688 struct smbsrv_request *req = smb_conn->pending_send;
693 blob.data = req->out.buffer;
694 blob.length = req->out.size;
696 /* send as much of this request as we can */
697 status = socket_send(conn->socket, &blob, &sendlen, 0);
698 if (NT_STATUS_IS_ERR(status)) {
699 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
706 req->out.buffer += sendlen;
707 req->out.size -= sendlen;
709 /* is the whole request gone? */
710 if (req->out.size == 0) {
711 DLIST_REMOVE(smb_conn->pending_send, req);
716 /* if no more requests are pending to be sent then
717 we should stop select for write */
718 if (smb_conn->pending_send == NULL) {
719 EVENT_FD_NOT_WRITEABLE(conn->event.fde);
724 initialise a server_context from a open socket and register a event handler
725 for reading from that socket
727 static void smbsrv_accept(struct stream_connection *conn)
729 struct smbsrv_connection *smb_conn;
731 DEBUG(5,("smbsrv_accept\n"));
733 smb_conn = talloc_zero(conn, struct smbsrv_connection);
734 if (!smb_conn) return;
736 /* now initialise a few default values associated with this smb socket */
737 smb_conn->negotiate.max_send = 0xFFFF;
739 /* this is the size that w2k uses, and it appears to be important for
741 smb_conn->negotiate.max_recv = lp_max_xmit();
743 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
745 smbsrv_vuid_init(smb_conn);
747 srv_init_signing(smb_conn);
749 smbsrv_tcon_init(smb_conn);
751 smb_conn->connection = conn;
753 conn->private = smb_conn;
757 static const struct stream_server_ops smb_stream_ops = {
759 .accept_connection = smbsrv_accept,
760 .recv_handler = smbsrv_recv,
761 .send_handler = smbsrv_send,
765 setup a listening socket on all the SMB ports for a particular address
767 static NTSTATUS smb_add_socket(struct event_context *event_context,
768 const struct model_ops *model_ops,
771 const char **ports = lp_smb_ports();
775 for (i=0;ports[i];i++) {
776 uint16_t port = atoi(ports[i]);
777 if (port == 0) continue;
778 status = stream_setup_socket(event_context, model_ops, &smb_stream_ops,
779 "ipv4", address, &port, NULL);
780 NT_STATUS_NOT_OK_RETURN(status);
787 called on startup of the smb server service It's job is to start
788 listening on all configured SMB server sockets
790 static NTSTATUS smbsrv_init(struct event_context *event_context, const struct model_ops *model_ops)
794 if (lp_interfaces() && lp_bind_interfaces_only()) {
795 int num_interfaces = iface_count();
798 /* We have been given an interfaces line, and been
799 told to only bind to those interfaces. Create a
800 socket per interface and bind to only these.
802 for(i = 0; i < num_interfaces; i++) {
803 const char *address = iface_n_ip(i);
804 status = smb_add_socket(event_context, model_ops, address);
805 NT_STATUS_NOT_OK_RETURN(status);
808 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
809 status = smb_add_socket(event_context, model_ops, lp_socket_address());
810 NT_STATUS_NOT_OK_RETURN(status);
816 /* called at smbd startup - register ourselves as a server service */
817 NTSTATUS server_service_smb_init(void)
819 return register_server_service("smb", smbsrv_init);