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 req_reply_error(req, NT_STATUS_INVALID_HANDLE);
518 /* see if the vuid is valid */
519 if ((flags & AS_USER) && !req->session) {
520 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
524 smb_messages[type].fn(req);
528 /****************************************************************************
529 Construct a reply to the incoming packet.
530 ****************************************************************************/
531 static void construct_reply(struct smbsrv_request *req)
533 uint8_t type = CVAL(req->in.hdr,HDR_COM);
535 /* see if its a special NBT packet */
536 if (CVAL(req->in.buffer,0) != 0) {
541 /* Make sure this is an SMB packet */
542 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
543 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
545 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
549 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
550 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
551 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
555 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
556 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
557 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
561 req->flags = CVAL(req->in.hdr, HDR_FLG);
562 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
563 req->smbpid = SVAL(req->in.hdr,HDR_PID);
565 if (!req_signing_check_incoming(req)) {
566 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
570 switch_message(type, req);
575 we call this when first first part of a possibly chained request has been completed
576 and we need to call the 2nd part, if any
578 void chain_reply(struct smbsrv_request *req)
580 uint16_t chain_cmd, chain_offset;
585 if (req->in.wct < 2 || req->out.wct < 2) {
586 req_reply_dos_error(req, ERRSRV, ERRerror);
590 chain_cmd = CVAL(req->in.vwv, VWV(0));
591 chain_offset = SVAL(req->in.vwv, VWV(1));
593 if (chain_cmd == SMB_CHAIN_NONE) {
595 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
596 SSVAL(req->out.vwv, VWV(1), 0);
601 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
605 wct = CVAL(req->in.hdr, chain_offset);
606 vwv = req->in.hdr + chain_offset + 1;
608 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
612 data_size = SVAL(vwv, VWV(wct));
613 data = vwv + VWV(wct) + 2;
615 if (data + data_size > req->in.buffer + req->in.size) {
619 /* all seems legit */
623 req->in.data_size = data_size;
628 SSVAL(req->out.vwv, VWV(0), chain_cmd);
629 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
631 /* the current request in the chain might have used an async reply,
632 but that doesn't mean the next element needs to */
633 ZERO_STRUCTP(req->async_states);
635 switch_message(chain_cmd, req);
639 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
640 SSVAL(req->out.vwv, VWV(1), 0);
641 req_reply_dos_error(req, ERRSRV, ERRerror);
646 close the socket and shutdown a server_context
648 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
650 stream_terminate_connection(smb_conn->connection, reason);
654 called when a SMB socket becomes readable
656 static void smbsrv_recv(struct stream_connection *conn, uint16_t flags)
658 struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
661 DEBUG(10,("smbsrv_recv\n"));
663 status = receive_smb_request(smb_conn);
664 if (NT_STATUS_IS_ERR(status)) {
665 talloc_free(conn->event.fde);
666 conn->event.fde = NULL;
667 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
671 /* free up temporary memory */
676 called when a SMB socket becomes writable
678 static void smbsrv_send(struct stream_connection *conn, uint16_t flags)
680 struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
682 while (smb_conn->pending_send) {
683 struct smbsrv_request *req = smb_conn->pending_send;
688 blob.data = req->out.buffer;
689 blob.length = req->out.size;
691 /* send as much of this request as we can */
692 status = socket_send(conn->socket, &blob, &sendlen, 0);
693 if (NT_STATUS_IS_ERR(status)) {
694 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
701 req->out.buffer += sendlen;
702 req->out.size -= sendlen;
704 /* is the whole request gone? */
705 if (req->out.size == 0) {
706 DLIST_REMOVE(smb_conn->pending_send, req);
711 /* if no more requests are pending to be sent then
712 we should stop select for write */
713 if (smb_conn->pending_send == NULL) {
714 EVENT_FD_NOT_WRITEABLE(conn->event.fde);
719 initialise a server_context from a open socket and register a event handler
720 for reading from that socket
722 static void smbsrv_accept(struct stream_connection *conn)
724 struct smbsrv_connection *smb_conn;
726 DEBUG(5,("smbsrv_accept\n"));
728 smb_conn = talloc_zero(conn, struct smbsrv_connection);
729 if (!smb_conn) return;
731 /* now initialise a few default values associated with this smb socket */
732 smb_conn->negotiate.max_send = 0xFFFF;
734 /* this is the size that w2k uses, and it appears to be important for
736 smb_conn->negotiate.max_recv = lp_max_xmit();
738 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
740 smb_conn->sessions.next_vuid = VUID_OFFSET;
742 srv_init_signing(smb_conn);
744 smbsrv_tcon_init(smb_conn);
746 smb_conn->connection = conn;
748 conn->private = smb_conn;
752 static const struct stream_server_ops smb_stream_ops = {
754 .accept_connection = smbsrv_accept,
755 .recv_handler = smbsrv_recv,
756 .send_handler = smbsrv_send,
760 setup a listening socket on all the SMB ports for a particular address
762 static NTSTATUS smb_add_socket(struct event_context *event_context,
763 const struct model_ops *model_ops,
766 const char **ports = lp_smb_ports();
770 for (i=0;ports[i];i++) {
771 uint16_t port = atoi(ports[i]);
772 if (port == 0) continue;
773 status = stream_setup_socket(event_context, model_ops, &smb_stream_ops,
774 "ipv4", address, &port, NULL);
775 NT_STATUS_NOT_OK_RETURN(status);
782 called on startup of the smb server service It's job is to start
783 listening on all configured SMB server sockets
785 static NTSTATUS smbsrv_init(struct event_context *event_context, const struct model_ops *model_ops)
789 if (lp_interfaces() && lp_bind_interfaces_only()) {
790 int num_interfaces = iface_count();
793 /* We have been given an interfaces line, and been
794 told to only bind to those interfaces. Create a
795 socket per interface and bind to only these.
797 for(i = 0; i < num_interfaces; i++) {
798 const char *address = iface_n_ip(i);
799 status = smb_add_socket(event_context, model_ops, address);
800 NT_STATUS_NOT_OK_RETURN(status);
803 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
804 status = smb_add_socket(event_context, model_ops, lp_socket_address());
805 NT_STATUS_NOT_OK_RETURN(status);
811 /* called at smbd startup - register ourselves as a server service */
812 NTSTATUS server_service_smb_init(void)
814 return register_server_service("smb", smbsrv_init);