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.
25 #include "system/time.h"
26 #include "dlinklist.h"
27 #include "smb_server/smb_server.h"
31 send an oplock break request to a client
33 BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
35 struct smbsrv_request *req;
37 req = init_smb_request(tcon->smb_conn);
39 req_setup_reply(req, 8, 0);
41 SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
42 SSVAL(req->out.hdr,HDR_TID,tcon->tid);
43 SSVAL(req->out.hdr,HDR_PID,0xFFFF);
44 SSVAL(req->out.hdr,HDR_UID,0);
45 SSVAL(req->out.hdr,HDR_MID,0xFFFF);
46 SCVAL(req->out.hdr,HDR_FLG,0);
47 SSVAL(req->out.hdr,HDR_FLG2,0);
49 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
50 SSVAL(req->out.vwv, VWV(1), 0);
51 SSVAL(req->out.vwv, VWV(2), fnum);
52 SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
53 SCVAL(req->out.vwv, VWV(3)+1, level);
54 SIVAL(req->out.vwv, VWV(4), 0);
55 SSVAL(req->out.vwv, VWV(6), 0);
56 SSVAL(req->out.vwv, VWV(7), 0);
63 static void construct_reply(struct smbsrv_request *req);
65 /****************************************************************************
66 receive a SMB request header from the wire, forming a request_context
68 ****************************************************************************/
69 static NTSTATUS receive_smb_request(struct smbsrv_connection *smb_conn, struct timeval t)
73 struct smbsrv_request *req;
76 /* allocate the request if needed */
77 if (smb_conn->partial_req == NULL) {
78 req = init_smb_request(smb_conn);
80 return NT_STATUS_NO_MEMORY;
83 req->in.buffer = talloc_array_p(req, uint8_t, NBT_HDR_SIZE);
84 if (req->in.buffer == NULL) {
86 return NT_STATUS_NO_MEMORY;
89 smb_conn->partial_req = req;
92 req = smb_conn->partial_req;
94 /* read in the header */
95 if (req->in.size < NBT_HDR_SIZE) {
96 status = socket_recv(smb_conn->connection->socket,
97 req->in.buffer + req->in.size,
98 NBT_HDR_SIZE - req->in.size,
100 if (NT_STATUS_IS_ERR(status)) {
106 req->in.size += nread;
108 /* when we have a full NBT header, then allocate the packet */
109 if (req->in.size == NBT_HDR_SIZE) {
110 len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
111 req->in.buffer = talloc_realloc(req, req->in.buffer,
113 if (req->in.buffer == NULL) {
114 return NT_STATUS_NO_MEMORY;
121 /* read in the main packet */
122 len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
124 status = socket_recv(smb_conn->connection->socket,
125 req->in.buffer + req->in.size,
128 if (NT_STATUS_IS_ERR(status)) {
135 req->in.size += nread;
137 if (req->in.size != len) {
141 /* we have a full packet */
142 req->request_time = t;
143 req->chained_fnum = -1;
144 req->in.allocated = req->in.size;
145 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
146 req->in.vwv = req->in.hdr + HDR_VWV;
147 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
148 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
149 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
150 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
152 /* the bcc length is only 16 bits, but some packets
153 (such as SMBwriteX) can be much larger than 64k. We
154 detect this by looking for a large non-chained NBT
155 packet (at least 64k bigger than what is
156 specified). If it is detected then the NBT size is
157 used instead of the bcc size */
158 if (req->in.data_size + 0x10000 <=
159 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
160 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
161 /* its an oversized packet! fun for all the family */
162 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
166 smb_conn->partial_req = NULL;
168 construct_reply(req);
174 These flags determine some of the permissions required to do an operation
176 #define AS_USER (1<<0)
179 define a list of possible SMB messages and their corresponding
180 functions. Any message that has a NULL function is unimplemented -
181 please feel free to contribute implementations!
183 static const struct smb_message_struct
186 void (*fn)(struct smbsrv_request *);
189 smb_messages[256] = {
190 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER},
191 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER},
192 /* 0x02 */ { "SMBopen",reply_open,AS_USER},
193 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
194 /* 0x04 */ { "SMBclose",reply_close,AS_USER},
195 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
196 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER},
197 /* 0x07 */ { "SMBmv",reply_mv,AS_USER},
198 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
199 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER},
200 /* 0x0a */ { "SMBread",reply_read,AS_USER},
201 /* 0x0b */ { "SMBwrite",reply_write,AS_USER},
202 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
203 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
204 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
205 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
206 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
207 /* 0x11 */ { "SMBexit",reply_exit,0},
208 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
209 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
210 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
211 /* 0x15 */ { NULL, NULL, 0 },
212 /* 0x16 */ { NULL, NULL, 0 },
213 /* 0x17 */ { NULL, NULL, 0 },
214 /* 0x18 */ { NULL, NULL, 0 },
215 /* 0x19 */ { NULL, NULL, 0 },
216 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
217 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
218 /* 0x1c */ { "SMBreadBs",NULL,0 },
219 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
220 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
221 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
222 /* 0x20 */ { "SMBwritec",NULL,0},
223 /* 0x21 */ { NULL, NULL, 0 },
224 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER},
225 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER},
226 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER},
227 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER},
228 /* 0x26 */ { "SMBtranss",reply_transs,AS_USER},
229 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
230 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
231 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER},
232 /* 0x2a */ { "SMBmove",NULL,AS_USER},
233 /* 0x2b */ { "SMBecho",reply_echo,0},
234 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
235 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER},
236 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER},
237 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER},
238 /* 0x30 */ { NULL, NULL, 0 },
239 /* 0x31 */ { NULL, NULL, 0 },
240 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER},
241 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
242 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
243 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
244 /* 0x36 */ { NULL, NULL, 0 },
245 /* 0x37 */ { NULL, NULL, 0 },
246 /* 0x38 */ { NULL, NULL, 0 },
247 /* 0x39 */ { NULL, NULL, 0 },
248 /* 0x3a */ { NULL, NULL, 0 },
249 /* 0x3b */ { NULL, NULL, 0 },
250 /* 0x3c */ { NULL, NULL, 0 },
251 /* 0x3d */ { NULL, NULL, 0 },
252 /* 0x3e */ { NULL, NULL, 0 },
253 /* 0x3f */ { NULL, NULL, 0 },
254 /* 0x40 */ { NULL, NULL, 0 },
255 /* 0x41 */ { NULL, NULL, 0 },
256 /* 0x42 */ { NULL, NULL, 0 },
257 /* 0x43 */ { NULL, NULL, 0 },
258 /* 0x44 */ { NULL, NULL, 0 },
259 /* 0x45 */ { NULL, NULL, 0 },
260 /* 0x46 */ { NULL, NULL, 0 },
261 /* 0x47 */ { NULL, NULL, 0 },
262 /* 0x48 */ { NULL, NULL, 0 },
263 /* 0x49 */ { NULL, NULL, 0 },
264 /* 0x4a */ { NULL, NULL, 0 },
265 /* 0x4b */ { NULL, NULL, 0 },
266 /* 0x4c */ { NULL, NULL, 0 },
267 /* 0x4d */ { NULL, NULL, 0 },
268 /* 0x4e */ { NULL, NULL, 0 },
269 /* 0x4f */ { NULL, NULL, 0 },
270 /* 0x50 */ { NULL, NULL, 0 },
271 /* 0x51 */ { NULL, NULL, 0 },
272 /* 0x52 */ { NULL, NULL, 0 },
273 /* 0x53 */ { NULL, NULL, 0 },
274 /* 0x54 */ { NULL, NULL, 0 },
275 /* 0x55 */ { NULL, NULL, 0 },
276 /* 0x56 */ { NULL, NULL, 0 },
277 /* 0x57 */ { NULL, NULL, 0 },
278 /* 0x58 */ { NULL, NULL, 0 },
279 /* 0x59 */ { NULL, NULL, 0 },
280 /* 0x5a */ { NULL, NULL, 0 },
281 /* 0x5b */ { NULL, NULL, 0 },
282 /* 0x5c */ { NULL, NULL, 0 },
283 /* 0x5d */ { NULL, NULL, 0 },
284 /* 0x5e */ { NULL, NULL, 0 },
285 /* 0x5f */ { NULL, NULL, 0 },
286 /* 0x60 */ { NULL, NULL, 0 },
287 /* 0x61 */ { NULL, NULL, 0 },
288 /* 0x62 */ { NULL, NULL, 0 },
289 /* 0x63 */ { NULL, NULL, 0 },
290 /* 0x64 */ { NULL, NULL, 0 },
291 /* 0x65 */ { NULL, NULL, 0 },
292 /* 0x66 */ { NULL, NULL, 0 },
293 /* 0x67 */ { NULL, NULL, 0 },
294 /* 0x68 */ { NULL, NULL, 0 },
295 /* 0x69 */ { NULL, NULL, 0 },
296 /* 0x6a */ { NULL, NULL, 0 },
297 /* 0x6b */ { NULL, NULL, 0 },
298 /* 0x6c */ { NULL, NULL, 0 },
299 /* 0x6d */ { NULL, NULL, 0 },
300 /* 0x6e */ { NULL, NULL, 0 },
301 /* 0x6f */ { NULL, NULL, 0 },
302 /* 0x70 */ { "SMBtcon",reply_tcon,0},
303 /* 0x71 */ { "SMBtdis",reply_tdis,0},
304 /* 0x72 */ { "SMBnegprot",reply_negprot,0},
305 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,0},
306 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
307 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
308 /* 0x76 */ { NULL, NULL, 0 },
309 /* 0x77 */ { NULL, NULL, 0 },
310 /* 0x78 */ { NULL, NULL, 0 },
311 /* 0x79 */ { NULL, NULL, 0 },
312 /* 0x7a */ { NULL, NULL, 0 },
313 /* 0x7b */ { NULL, NULL, 0 },
314 /* 0x7c */ { NULL, NULL, 0 },
315 /* 0x7d */ { NULL, NULL, 0 },
316 /* 0x7e */ { NULL, NULL, 0 },
317 /* 0x7f */ { NULL, NULL, 0 },
318 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
319 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
320 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
321 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
322 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
323 /* 0x85 */ { NULL, NULL, 0 },
324 /* 0x86 */ { NULL, NULL, 0 },
325 /* 0x87 */ { NULL, NULL, 0 },
326 /* 0x88 */ { NULL, NULL, 0 },
327 /* 0x89 */ { NULL, NULL, 0 },
328 /* 0x8a */ { NULL, NULL, 0 },
329 /* 0x8b */ { NULL, NULL, 0 },
330 /* 0x8c */ { NULL, NULL, 0 },
331 /* 0x8d */ { NULL, NULL, 0 },
332 /* 0x8e */ { NULL, NULL, 0 },
333 /* 0x8f */ { NULL, NULL, 0 },
334 /* 0x90 */ { NULL, NULL, 0 },
335 /* 0x91 */ { NULL, NULL, 0 },
336 /* 0x92 */ { NULL, NULL, 0 },
337 /* 0x93 */ { NULL, NULL, 0 },
338 /* 0x94 */ { NULL, NULL, 0 },
339 /* 0x95 */ { NULL, NULL, 0 },
340 /* 0x96 */ { NULL, NULL, 0 },
341 /* 0x97 */ { NULL, NULL, 0 },
342 /* 0x98 */ { NULL, NULL, 0 },
343 /* 0x99 */ { NULL, NULL, 0 },
344 /* 0x9a */ { NULL, NULL, 0 },
345 /* 0x9b */ { NULL, NULL, 0 },
346 /* 0x9c */ { NULL, NULL, 0 },
347 /* 0x9d */ { NULL, NULL, 0 },
348 /* 0x9e */ { NULL, NULL, 0 },
349 /* 0x9f */ { NULL, NULL, 0 },
350 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER},
351 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER},
352 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER},
353 /* 0xa3 */ { NULL, NULL, 0 },
354 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
355 /* 0xa5 */ { "SMBntrename", reply_ntrename, 0 },
356 /* 0xa6 */ { NULL, NULL, 0 },
357 /* 0xa7 */ { NULL, NULL, 0 },
358 /* 0xa8 */ { NULL, NULL, 0 },
359 /* 0xa9 */ { NULL, NULL, 0 },
360 /* 0xaa */ { NULL, NULL, 0 },
361 /* 0xab */ { NULL, NULL, 0 },
362 /* 0xac */ { NULL, NULL, 0 },
363 /* 0xad */ { NULL, NULL, 0 },
364 /* 0xae */ { NULL, NULL, 0 },
365 /* 0xaf */ { NULL, NULL, 0 },
366 /* 0xb0 */ { NULL, NULL, 0 },
367 /* 0xb1 */ { NULL, NULL, 0 },
368 /* 0xb2 */ { NULL, NULL, 0 },
369 /* 0xb3 */ { NULL, NULL, 0 },
370 /* 0xb4 */ { NULL, NULL, 0 },
371 /* 0xb5 */ { NULL, NULL, 0 },
372 /* 0xb6 */ { NULL, NULL, 0 },
373 /* 0xb7 */ { NULL, NULL, 0 },
374 /* 0xb8 */ { NULL, NULL, 0 },
375 /* 0xb9 */ { NULL, NULL, 0 },
376 /* 0xba */ { NULL, NULL, 0 },
377 /* 0xbb */ { NULL, NULL, 0 },
378 /* 0xbc */ { NULL, NULL, 0 },
379 /* 0xbd */ { NULL, NULL, 0 },
380 /* 0xbe */ { NULL, NULL, 0 },
381 /* 0xbf */ { NULL, NULL, 0 },
382 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
383 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
384 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
385 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
386 /* 0xc4 */ { NULL, NULL, 0 },
387 /* 0xc5 */ { NULL, NULL, 0 },
388 /* 0xc6 */ { NULL, NULL, 0 },
389 /* 0xc7 */ { NULL, NULL, 0 },
390 /* 0xc8 */ { NULL, NULL, 0 },
391 /* 0xc9 */ { NULL, NULL, 0 },
392 /* 0xca */ { NULL, NULL, 0 },
393 /* 0xcb */ { NULL, NULL, 0 },
394 /* 0xcc */ { NULL, NULL, 0 },
395 /* 0xcd */ { NULL, NULL, 0 },
396 /* 0xce */ { NULL, NULL, 0 },
397 /* 0xcf */ { NULL, NULL, 0 },
398 /* 0xd0 */ { "SMBsends",reply_sends,0},
399 /* 0xd1 */ { "SMBsendb",NULL,0},
400 /* 0xd2 */ { "SMBfwdname",NULL,0},
401 /* 0xd3 */ { "SMBcancelf",NULL,0},
402 /* 0xd4 */ { "SMBgetmac",NULL,0},
403 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,0},
404 /* 0xd6 */ { "SMBsendend",reply_sendend,0},
405 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,0},
406 /* 0xd8 */ { NULL, NULL, 0 },
407 /* 0xd9 */ { NULL, NULL, 0 },
408 /* 0xda */ { NULL, NULL, 0 },
409 /* 0xdb */ { NULL, NULL, 0 },
410 /* 0xdc */ { NULL, NULL, 0 },
411 /* 0xdd */ { NULL, NULL, 0 },
412 /* 0xde */ { NULL, NULL, 0 },
413 /* 0xdf */ { NULL, NULL, 0 },
414 /* 0xe0 */ { NULL, NULL, 0 },
415 /* 0xe1 */ { NULL, NULL, 0 },
416 /* 0xe2 */ { NULL, NULL, 0 },
417 /* 0xe3 */ { NULL, NULL, 0 },
418 /* 0xe4 */ { NULL, NULL, 0 },
419 /* 0xe5 */ { NULL, NULL, 0 },
420 /* 0xe6 */ { NULL, NULL, 0 },
421 /* 0xe7 */ { NULL, NULL, 0 },
422 /* 0xe8 */ { NULL, NULL, 0 },
423 /* 0xe9 */ { NULL, NULL, 0 },
424 /* 0xea */ { NULL, NULL, 0 },
425 /* 0xeb */ { NULL, NULL, 0 },
426 /* 0xec */ { NULL, NULL, 0 },
427 /* 0xed */ { NULL, NULL, 0 },
428 /* 0xee */ { NULL, NULL, 0 },
429 /* 0xef */ { NULL, NULL, 0 },
430 /* 0xf0 */ { NULL, NULL, 0 },
431 /* 0xf1 */ { NULL, NULL, 0 },
432 /* 0xf2 */ { NULL, NULL, 0 },
433 /* 0xf3 */ { NULL, NULL, 0 },
434 /* 0xf4 */ { NULL, NULL, 0 },
435 /* 0xf5 */ { NULL, NULL, 0 },
436 /* 0xf6 */ { NULL, NULL, 0 },
437 /* 0xf7 */ { NULL, NULL, 0 },
438 /* 0xf8 */ { NULL, NULL, 0 },
439 /* 0xf9 */ { NULL, NULL, 0 },
440 /* 0xfa */ { NULL, NULL, 0 },
441 /* 0xfb */ { NULL, NULL, 0 },
442 /* 0xfc */ { NULL, NULL, 0 },
443 /* 0xfd */ { NULL, NULL, 0 },
444 /* 0xfe */ { NULL, NULL, 0 },
445 /* 0xff */ { NULL, NULL, 0 }
448 /****************************************************************************
449 return a string containing the function name of a SMB command
450 ****************************************************************************/
451 static const char *smb_fn_name(uint8_t type)
453 const char *unknown_name = "SMBunknown";
455 if (smb_messages[type].name == NULL)
458 return smb_messages[type].name;
462 /****************************************************************************
463 Do a switch on the message type and call the specific reply function for this
464 message. Unlike earlier versions of Samba the reply functions are responsible
465 for sending the reply themselves, rather than returning a size to this function
466 The reply functions may also choose to delay the processing by pushing the message
467 onto the message queue
468 ****************************************************************************/
469 static void switch_message(int type, struct smbsrv_request *req)
472 struct smbsrv_connection *smb_conn = req->smb_conn;
473 uint16_t session_tag;
479 if (smb_messages[type].fn == NULL) {
480 DEBUG(0,("Unknown message type %d!\n",type));
485 flags = smb_messages[type].flags;
487 req->tcon = smbsrv_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
489 if (req->session == NULL) {
490 /* setup the user context for this request if it
491 hasn't already been initialised (to cope with SMB
494 /* In share mode security we must ignore the vuid. */
495 if (lp_security() == SEC_SHARE) {
496 session_tag = UID_FIELD_INVALID;
498 session_tag = SVAL(req->in.hdr,HDR_UID);
501 req->session = smbsrv_session_find(req->smb_conn, session_tag);
503 req->session->vuid = session_tag;
506 session_tag = req->session->vuid;
509 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb_conn->connection->service->model_ops->get_id(req)));
511 /* does this protocol need a valid tree connection? */
512 if ((flags & AS_USER) && !req->tcon) {
513 req_reply_error(req, NT_STATUS_INVALID_HANDLE);
517 /* see if the vuid is valid */
518 if ((flags & AS_USER) && !req->session) {
519 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
523 smb_messages[type].fn(req);
527 /****************************************************************************
528 Construct a reply to the incoming packet.
529 ****************************************************************************/
530 static void construct_reply(struct smbsrv_request *req)
532 uint8_t type = CVAL(req->in.hdr,HDR_COM);
534 /* see if its a special NBT packet */
535 if (CVAL(req->in.buffer,0) != 0) {
540 /* Make sure this is an SMB packet */
541 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
542 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
544 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
548 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
549 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
550 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
554 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
555 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
556 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
560 req->flags = CVAL(req->in.hdr, HDR_FLG);
561 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
562 req->smbpid = SVAL(req->in.hdr,HDR_PID);
564 if (!req_signing_check_incoming(req)) {
565 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
569 switch_message(type, req);
574 we call this when first first part of a possibly chained request has been completed
575 and we need to call the 2nd part, if any
577 void chain_reply(struct smbsrv_request *req)
579 uint16_t chain_cmd, chain_offset;
584 if (req->in.wct < 2 || req->out.wct < 2) {
585 req_reply_dos_error(req, ERRSRV, ERRerror);
589 chain_cmd = CVAL(req->in.vwv, VWV(0));
590 chain_offset = SVAL(req->in.vwv, VWV(1));
592 if (chain_cmd == SMB_CHAIN_NONE) {
594 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
595 SSVAL(req->out.vwv, VWV(1), 0);
600 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
604 wct = CVAL(req->in.hdr, chain_offset);
605 vwv = req->in.hdr + chain_offset + 1;
607 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
611 data_size = SVAL(vwv, VWV(wct));
612 data = vwv + VWV(wct) + 2;
614 if (data + data_size > req->in.buffer + req->in.size) {
618 /* all seems legit */
622 req->in.data_size = data_size;
627 SSVAL(req->out.vwv, VWV(0), chain_cmd);
628 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
630 /* the current request in the chain might have used an async reply,
631 but that doesn't mean the next element needs to */
632 ZERO_STRUCTP(req->async_states);
634 switch_message(chain_cmd, req);
638 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
639 SSVAL(req->out.vwv, VWV(1), 0);
640 req_reply_dos_error(req, ERRSRV, ERRerror);
645 close the socket and shutdown a server_context
647 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
649 server_terminate_connection(smb_conn->connection, reason);
653 called on a fatal error that should cause this server to terminate
655 static void smbsrv_exit(struct server_service *service, const char *reason)
657 DEBUG(1,("smbsrv_exit\n"));
662 add a socket address to the list of events, one event per port
664 static void smb_add_socket(struct server_service *service,
665 const struct model_ops *model_ops,
666 struct socket_context *socket_ctx,
667 struct ipv4_addr *ifip)
669 const char **ports = lp_smb_ports();
671 char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
673 for (i=0;ports[i];i++) {
674 uint16_t port = atoi(ports[i]);
675 if (port == 0) continue;
676 service_setup_socket(service, model_ops, "ipv4", ip_str, &port);
682 /****************************************************************************
683 Open the socket communication.
684 ****************************************************************************/
685 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
687 DEBUG(1,("smbsrv_init\n"));
689 if (lp_interfaces() && lp_bind_interfaces_only()) {
690 int num_interfaces = iface_count();
693 /* We have been given an interfaces line, and been
694 told to only bind to those interfaces. Create a
695 socket per interface and bind to only these.
697 for(i = 0; i < num_interfaces; i++) {
698 struct ipv4_addr *ifip = iface_n_ip(i);
701 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
705 smb_add_socket(service, model_ops, NULL, ifip);
708 struct ipv4_addr ifip;
709 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
710 ifip = interpret_addr2(lp_socket_address());
711 smb_add_socket(service, model_ops, NULL, &ifip);
716 called when a SMB socket becomes readable
718 static void smbsrv_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
720 struct smbsrv_connection *smb_conn = conn->private_data;
723 DEBUG(10,("smbsrv_recv\n"));
725 status = receive_smb_request(smb_conn, t);
726 if (NT_STATUS_IS_ERR(status)) {
727 conn->event.fde->flags = 0;
728 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
732 /* free up temporary memory */
737 called when a SMB socket becomes writable
739 static void smbsrv_send(struct server_connection *conn, struct timeval t, uint16_t flags)
741 struct smbsrv_connection *smb_conn = conn->private_data;
743 while (smb_conn->pending_send) {
744 struct smbsrv_request *req = smb_conn->pending_send;
749 blob.data = req->out.buffer;
750 blob.length = req->out.size;
752 /* send as much of this request as we can */
753 status = socket_send(conn->socket, &blob, &sendlen, 0);
754 if (NT_STATUS_IS_ERR(status)) {
755 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
762 req->out.buffer += sendlen;
763 req->out.size -= sendlen;
765 /* is the whole request gone? */
766 if (req->out.size == 0) {
767 DLIST_REMOVE(smb_conn->pending_send, req);
772 /* if no more requests are pending to be sent then
773 we should stop select for write */
774 if (smb_conn->pending_send == NULL) {
775 conn->event.fde->flags &= ~EVENT_FD_WRITE;
780 called when connection is idle
782 static void smbsrv_idle(struct server_connection *conn, struct timeval t)
784 DEBUG(10,("smbsrv_idle: not implemented!\n"));
785 conn->event.idle->next_event = timeval_add(&t, 5, 0);
789 static void smbsrv_close(struct server_connection *conn, const char *reason)
791 struct smbsrv_connection *smb_conn = conn->private_data;
793 DEBUG(5,("smbsrv_close: %s\n",reason));
795 talloc_free(smb_conn);
801 process a message from an SMB socket while still processing a
802 previous message this is used by backends who need to ensure that
803 new messages from clients are still processed while they are
804 performing long operations
806 void smbd_process_async(struct smbsrv_connection *smb_conn)
810 status = receive_smb_request(smb_conn, timeval_current());
811 if (NT_STATUS_IS_ERR(status)) {
812 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
818 initialise a server_context from a open socket and register a event handler
819 for reading from that socket
821 void smbsrv_accept(struct server_connection *conn)
823 struct smbsrv_connection *smb_conn;
825 DEBUG(5,("smbsrv_accept\n"));
827 smb_conn = talloc_zero_p(conn, struct smbsrv_connection);
828 if (!smb_conn) return;
830 smb_conn->pid = getpid();
832 sub_set_context(&smb_conn->substitute);
834 /* now initialise a few default values associated with this smb socket */
835 smb_conn->negotiate.max_send = 0xFFFF;
837 /* this is the size that w2k uses, and it appears to be important for
839 smb_conn->negotiate.max_recv = lp_max_xmit();
841 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
843 smb_conn->sessions.next_vuid = VUID_OFFSET;
845 srv_init_signing(smb_conn);
847 smbsrv_tcon_init(smb_conn);
849 smb_conn->connection = conn;
851 conn->private_data = smb_conn;
856 static const struct server_service_ops smb_server_ops = {
858 .service_init = smbsrv_init,
859 .accept_connection = smbsrv_accept,
860 .recv_handler = smbsrv_recv,
861 .send_handler = smbsrv_send,
862 .idle_handler = smbsrv_idle,
863 .close_connection = smbsrv_close,
864 .service_exit = smbsrv_exit,
867 const struct server_service_ops *smbsrv_get_ops(void)
869 return &smb_server_ops;
872 NTSTATUS server_service_smb_init(void)