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->cnum);
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, char, 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, len);
112 if (req->in.buffer == NULL) {
113 return NT_STATUS_NO_MEMORY;
120 /* read in the main packet */
121 len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
123 status = socket_recv(smb_conn->connection->socket,
124 req->in.buffer + req->in.size,
127 if (NT_STATUS_IS_ERR(status)) {
134 req->in.size += nread;
136 if (req->in.size != len) {
140 /* we have a full packet */
141 req->request_time = t;
142 req->chained_fnum = -1;
143 req->in.allocated = req->in.size;
144 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
145 req->in.vwv = req->in.hdr + HDR_VWV;
146 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
147 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
148 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
149 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
151 /* the bcc length is only 16 bits, but some packets
152 (such as SMBwriteX) can be much larger than 64k. We
153 detect this by looking for a large non-chained NBT
154 packet (at least 64k bigger than what is
155 specified). If it is detected then the NBT size is
156 used instead of the bcc size */
157 if (req->in.data_size + 0x10000 <=
158 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
159 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
160 /* its an oversized packet! fun for all the family */
161 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
165 smb_conn->partial_req = NULL;
167 construct_reply(req);
173 These flags determine some of the permissions required to do an operation
175 #define AS_USER (1<<0)
178 define a list of possible SMB messages and their corresponding
179 functions. Any message that has a NULL function is unimplemented -
180 please feel free to contribute implementations!
182 static const struct smb_message_struct
185 void (*fn)(struct smbsrv_request *);
188 smb_messages[256] = {
189 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER},
190 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER},
191 /* 0x02 */ { "SMBopen",reply_open,AS_USER},
192 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
193 /* 0x04 */ { "SMBclose",reply_close,AS_USER},
194 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
195 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER},
196 /* 0x07 */ { "SMBmv",reply_mv,AS_USER},
197 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
198 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER},
199 /* 0x0a */ { "SMBread",reply_read,AS_USER},
200 /* 0x0b */ { "SMBwrite",reply_write,AS_USER},
201 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
202 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
203 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
204 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
205 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
206 /* 0x11 */ { "SMBexit",reply_exit,0},
207 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
208 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
209 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
210 /* 0x15 */ { NULL, NULL, 0 },
211 /* 0x16 */ { NULL, NULL, 0 },
212 /* 0x17 */ { NULL, NULL, 0 },
213 /* 0x18 */ { NULL, NULL, 0 },
214 /* 0x19 */ { NULL, NULL, 0 },
215 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
216 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
217 /* 0x1c */ { "SMBreadBs",NULL,0 },
218 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
219 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
220 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
221 /* 0x20 */ { "SMBwritec",NULL,0},
222 /* 0x21 */ { NULL, NULL, 0 },
223 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER},
224 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER},
225 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER},
226 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER},
227 /* 0x26 */ { "SMBtranss",NULL,AS_USER},
228 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
229 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
230 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER},
231 /* 0x2a */ { "SMBmove",NULL,AS_USER},
232 /* 0x2b */ { "SMBecho",reply_echo,0},
233 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
234 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER},
235 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER},
236 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER},
237 /* 0x30 */ { NULL, NULL, 0 },
238 /* 0x31 */ { NULL, NULL, 0 },
239 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER},
240 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
241 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
242 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
243 /* 0x36 */ { NULL, NULL, 0 },
244 /* 0x37 */ { NULL, NULL, 0 },
245 /* 0x38 */ { NULL, NULL, 0 },
246 /* 0x39 */ { NULL, NULL, 0 },
247 /* 0x3a */ { NULL, NULL, 0 },
248 /* 0x3b */ { NULL, NULL, 0 },
249 /* 0x3c */ { NULL, NULL, 0 },
250 /* 0x3d */ { NULL, NULL, 0 },
251 /* 0x3e */ { NULL, NULL, 0 },
252 /* 0x3f */ { NULL, NULL, 0 },
253 /* 0x40 */ { NULL, NULL, 0 },
254 /* 0x41 */ { NULL, NULL, 0 },
255 /* 0x42 */ { NULL, NULL, 0 },
256 /* 0x43 */ { NULL, NULL, 0 },
257 /* 0x44 */ { NULL, NULL, 0 },
258 /* 0x45 */ { NULL, NULL, 0 },
259 /* 0x46 */ { NULL, NULL, 0 },
260 /* 0x47 */ { NULL, NULL, 0 },
261 /* 0x48 */ { NULL, NULL, 0 },
262 /* 0x49 */ { NULL, NULL, 0 },
263 /* 0x4a */ { NULL, NULL, 0 },
264 /* 0x4b */ { NULL, NULL, 0 },
265 /* 0x4c */ { NULL, NULL, 0 },
266 /* 0x4d */ { NULL, NULL, 0 },
267 /* 0x4e */ { NULL, NULL, 0 },
268 /* 0x4f */ { NULL, NULL, 0 },
269 /* 0x50 */ { NULL, NULL, 0 },
270 /* 0x51 */ { NULL, NULL, 0 },
271 /* 0x52 */ { NULL, NULL, 0 },
272 /* 0x53 */ { NULL, NULL, 0 },
273 /* 0x54 */ { NULL, NULL, 0 },
274 /* 0x55 */ { NULL, NULL, 0 },
275 /* 0x56 */ { NULL, NULL, 0 },
276 /* 0x57 */ { NULL, NULL, 0 },
277 /* 0x58 */ { NULL, NULL, 0 },
278 /* 0x59 */ { NULL, NULL, 0 },
279 /* 0x5a */ { NULL, NULL, 0 },
280 /* 0x5b */ { NULL, NULL, 0 },
281 /* 0x5c */ { NULL, NULL, 0 },
282 /* 0x5d */ { NULL, NULL, 0 },
283 /* 0x5e */ { NULL, NULL, 0 },
284 /* 0x5f */ { NULL, NULL, 0 },
285 /* 0x60 */ { NULL, NULL, 0 },
286 /* 0x61 */ { NULL, NULL, 0 },
287 /* 0x62 */ { NULL, NULL, 0 },
288 /* 0x63 */ { NULL, NULL, 0 },
289 /* 0x64 */ { NULL, NULL, 0 },
290 /* 0x65 */ { NULL, NULL, 0 },
291 /* 0x66 */ { NULL, NULL, 0 },
292 /* 0x67 */ { NULL, NULL, 0 },
293 /* 0x68 */ { NULL, NULL, 0 },
294 /* 0x69 */ { NULL, NULL, 0 },
295 /* 0x6a */ { NULL, NULL, 0 },
296 /* 0x6b */ { NULL, NULL, 0 },
297 /* 0x6c */ { NULL, NULL, 0 },
298 /* 0x6d */ { NULL, NULL, 0 },
299 /* 0x6e */ { NULL, NULL, 0 },
300 /* 0x6f */ { NULL, NULL, 0 },
301 /* 0x70 */ { "SMBtcon",reply_tcon,0},
302 /* 0x71 */ { "SMBtdis",reply_tdis,0},
303 /* 0x72 */ { "SMBnegprot",reply_negprot,0},
304 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,0},
305 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
306 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
307 /* 0x76 */ { NULL, NULL, 0 },
308 /* 0x77 */ { NULL, NULL, 0 },
309 /* 0x78 */ { NULL, NULL, 0 },
310 /* 0x79 */ { NULL, NULL, 0 },
311 /* 0x7a */ { NULL, NULL, 0 },
312 /* 0x7b */ { NULL, NULL, 0 },
313 /* 0x7c */ { NULL, NULL, 0 },
314 /* 0x7d */ { NULL, NULL, 0 },
315 /* 0x7e */ { NULL, NULL, 0 },
316 /* 0x7f */ { NULL, NULL, 0 },
317 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
318 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
319 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
320 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
321 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
322 /* 0x85 */ { NULL, NULL, 0 },
323 /* 0x86 */ { NULL, NULL, 0 },
324 /* 0x87 */ { NULL, NULL, 0 },
325 /* 0x88 */ { NULL, NULL, 0 },
326 /* 0x89 */ { NULL, NULL, 0 },
327 /* 0x8a */ { NULL, NULL, 0 },
328 /* 0x8b */ { NULL, NULL, 0 },
329 /* 0x8c */ { NULL, NULL, 0 },
330 /* 0x8d */ { NULL, NULL, 0 },
331 /* 0x8e */ { NULL, NULL, 0 },
332 /* 0x8f */ { NULL, NULL, 0 },
333 /* 0x90 */ { NULL, NULL, 0 },
334 /* 0x91 */ { NULL, NULL, 0 },
335 /* 0x92 */ { NULL, NULL, 0 },
336 /* 0x93 */ { NULL, NULL, 0 },
337 /* 0x94 */ { NULL, NULL, 0 },
338 /* 0x95 */ { NULL, NULL, 0 },
339 /* 0x96 */ { NULL, NULL, 0 },
340 /* 0x97 */ { NULL, NULL, 0 },
341 /* 0x98 */ { NULL, NULL, 0 },
342 /* 0x99 */ { NULL, NULL, 0 },
343 /* 0x9a */ { NULL, NULL, 0 },
344 /* 0x9b */ { NULL, NULL, 0 },
345 /* 0x9c */ { NULL, NULL, 0 },
346 /* 0x9d */ { NULL, NULL, 0 },
347 /* 0x9e */ { NULL, NULL, 0 },
348 /* 0x9f */ { NULL, NULL, 0 },
349 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER},
350 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER},
351 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER},
352 /* 0xa3 */ { NULL, NULL, 0 },
353 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
354 /* 0xa5 */ { "SMBntrename", reply_ntrename, 0 },
355 /* 0xa6 */ { NULL, NULL, 0 },
356 /* 0xa7 */ { NULL, NULL, 0 },
357 /* 0xa8 */ { NULL, NULL, 0 },
358 /* 0xa9 */ { NULL, NULL, 0 },
359 /* 0xaa */ { NULL, NULL, 0 },
360 /* 0xab */ { NULL, NULL, 0 },
361 /* 0xac */ { NULL, NULL, 0 },
362 /* 0xad */ { NULL, NULL, 0 },
363 /* 0xae */ { NULL, NULL, 0 },
364 /* 0xaf */ { NULL, NULL, 0 },
365 /* 0xb0 */ { NULL, NULL, 0 },
366 /* 0xb1 */ { NULL, NULL, 0 },
367 /* 0xb2 */ { NULL, NULL, 0 },
368 /* 0xb3 */ { NULL, NULL, 0 },
369 /* 0xb4 */ { NULL, NULL, 0 },
370 /* 0xb5 */ { NULL, NULL, 0 },
371 /* 0xb6 */ { NULL, NULL, 0 },
372 /* 0xb7 */ { NULL, NULL, 0 },
373 /* 0xb8 */ { NULL, NULL, 0 },
374 /* 0xb9 */ { NULL, NULL, 0 },
375 /* 0xba */ { NULL, NULL, 0 },
376 /* 0xbb */ { NULL, NULL, 0 },
377 /* 0xbc */ { NULL, NULL, 0 },
378 /* 0xbd */ { NULL, NULL, 0 },
379 /* 0xbe */ { NULL, NULL, 0 },
380 /* 0xbf */ { NULL, NULL, 0 },
381 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
382 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
383 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
384 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
385 /* 0xc4 */ { NULL, NULL, 0 },
386 /* 0xc5 */ { NULL, NULL, 0 },
387 /* 0xc6 */ { NULL, NULL, 0 },
388 /* 0xc7 */ { NULL, NULL, 0 },
389 /* 0xc8 */ { NULL, NULL, 0 },
390 /* 0xc9 */ { NULL, NULL, 0 },
391 /* 0xca */ { NULL, NULL, 0 },
392 /* 0xcb */ { NULL, NULL, 0 },
393 /* 0xcc */ { NULL, NULL, 0 },
394 /* 0xcd */ { NULL, NULL, 0 },
395 /* 0xce */ { NULL, NULL, 0 },
396 /* 0xcf */ { NULL, NULL, 0 },
397 /* 0xd0 */ { "SMBsends",reply_sends,0},
398 /* 0xd1 */ { "SMBsendb",NULL,0},
399 /* 0xd2 */ { "SMBfwdname",NULL,0},
400 /* 0xd3 */ { "SMBcancelf",NULL,0},
401 /* 0xd4 */ { "SMBgetmac",NULL,0},
402 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,0},
403 /* 0xd6 */ { "SMBsendend",reply_sendend,0},
404 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,0},
405 /* 0xd8 */ { NULL, NULL, 0 },
406 /* 0xd9 */ { NULL, NULL, 0 },
407 /* 0xda */ { NULL, NULL, 0 },
408 /* 0xdb */ { NULL, NULL, 0 },
409 /* 0xdc */ { NULL, NULL, 0 },
410 /* 0xdd */ { NULL, NULL, 0 },
411 /* 0xde */ { NULL, NULL, 0 },
412 /* 0xdf */ { NULL, NULL, 0 },
413 /* 0xe0 */ { NULL, NULL, 0 },
414 /* 0xe1 */ { NULL, NULL, 0 },
415 /* 0xe2 */ { NULL, NULL, 0 },
416 /* 0xe3 */ { NULL, NULL, 0 },
417 /* 0xe4 */ { NULL, NULL, 0 },
418 /* 0xe5 */ { NULL, NULL, 0 },
419 /* 0xe6 */ { NULL, NULL, 0 },
420 /* 0xe7 */ { NULL, NULL, 0 },
421 /* 0xe8 */ { NULL, NULL, 0 },
422 /* 0xe9 */ { NULL, NULL, 0 },
423 /* 0xea */ { NULL, NULL, 0 },
424 /* 0xeb */ { NULL, NULL, 0 },
425 /* 0xec */ { NULL, NULL, 0 },
426 /* 0xed */ { NULL, NULL, 0 },
427 /* 0xee */ { NULL, NULL, 0 },
428 /* 0xef */ { NULL, NULL, 0 },
429 /* 0xf0 */ { NULL, NULL, 0 },
430 /* 0xf1 */ { NULL, NULL, 0 },
431 /* 0xf2 */ { NULL, NULL, 0 },
432 /* 0xf3 */ { NULL, NULL, 0 },
433 /* 0xf4 */ { NULL, NULL, 0 },
434 /* 0xf5 */ { NULL, NULL, 0 },
435 /* 0xf6 */ { NULL, NULL, 0 },
436 /* 0xf7 */ { NULL, NULL, 0 },
437 /* 0xf8 */ { NULL, NULL, 0 },
438 /* 0xf9 */ { NULL, NULL, 0 },
439 /* 0xfa */ { NULL, NULL, 0 },
440 /* 0xfb */ { NULL, NULL, 0 },
441 /* 0xfc */ { NULL, NULL, 0 },
442 /* 0xfd */ { NULL, NULL, 0 },
443 /* 0xfe */ { NULL, NULL, 0 },
444 /* 0xff */ { NULL, NULL, 0 }
447 /****************************************************************************
448 return a string containing the function name of a SMB command
449 ****************************************************************************/
450 static const char *smb_fn_name(uint8_t type)
452 const char *unknown_name = "SMBunknown";
454 if (smb_messages[type].name == NULL)
457 return smb_messages[type].name;
461 /****************************************************************************
462 Do a switch on the message type and call the specific reply function for this
463 message. Unlike earlier versions of Samba the reply functions are responsible
464 for sending the reply themselves, rather than returning a size to this function
465 The reply functions may also choose to delay the processing by pushing the message
466 onto the message queue
467 ****************************************************************************/
468 static void switch_message(int type, struct smbsrv_request *req)
471 struct smbsrv_connection *smb_conn = req->smb_conn;
472 uint16_t session_tag;
478 if (smb_messages[type].fn == NULL) {
479 DEBUG(0,("Unknown message type %d!\n",type));
484 flags = smb_messages[type].flags;
486 req->tcon = conn_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
488 if (req->session == NULL) {
489 /* setup the user context for this request if it
490 hasn't already been initialised (to cope with SMB
493 /* In share mode security we must ignore the vuid. */
494 if (lp_security() == SEC_SHARE) {
495 session_tag = UID_FIELD_INVALID;
497 session_tag = SVAL(req->in.hdr,HDR_UID);
500 req->session = smbsrv_session_find(req->smb_conn, session_tag);
502 req->session->vuid = session_tag;
505 session_tag = req->session->vuid;
508 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb_conn->connection->service->model_ops->get_id(req)));
510 /* does this protocol need a valid tree connection? */
511 if ((flags & AS_USER) && !req->tcon) {
512 req_reply_error(req, NT_STATUS_INVALID_HANDLE);
516 /* see if the vuid is valid */
517 if ((flags & AS_USER) && !req->session) {
518 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
522 smb_messages[type].fn(req);
526 /****************************************************************************
527 Construct a reply to the incoming packet.
528 ****************************************************************************/
529 static void construct_reply(struct smbsrv_request *req)
531 uint8_t type = CVAL(req->in.hdr,HDR_COM);
533 /* see if its a special NBT packet */
534 if (CVAL(req->in.buffer,0) != 0) {
539 /* Make sure this is an SMB packet */
540 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
541 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
543 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
547 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
548 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
549 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
553 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
554 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
555 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
559 req->flags = CVAL(req->in.hdr, HDR_FLG);
560 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
561 req->smbpid = SVAL(req->in.hdr,HDR_PID);
563 if (!req_signing_check_incoming(req)) {
564 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
568 switch_message(type, req);
573 we call this when first first part of a possibly chained request has been completed
574 and we need to call the 2nd part, if any
576 void chain_reply(struct smbsrv_request *req)
578 uint16_t chain_cmd, chain_offset;
583 if (req->in.wct < 2 || req->out.wct < 2) {
584 req_reply_dos_error(req, ERRSRV, ERRerror);
588 chain_cmd = CVAL(req->in.vwv, VWV(0));
589 chain_offset = SVAL(req->in.vwv, VWV(1));
591 if (chain_cmd == SMB_CHAIN_NONE) {
593 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
594 SSVAL(req->out.vwv, VWV(1), 0);
599 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
603 wct = CVAL(req->in.hdr, chain_offset);
604 vwv = req->in.hdr + chain_offset + 1;
606 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
610 data_size = SVAL(vwv, VWV(wct));
611 data = vwv + VWV(wct) + 2;
613 if (data + data_size > req->in.buffer + req->in.size) {
617 /* all seems legit */
621 req->in.data_size = data_size;
626 SSVAL(req->out.vwv, VWV(0), chain_cmd);
627 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
629 /* the current request in the chain might have used an async reply,
630 but that doesn't mean the next element needs to */
631 ZERO_STRUCTP(req->async_states);
633 switch_message(chain_cmd, req);
637 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
638 SSVAL(req->out.vwv, VWV(1), 0);
639 req_reply_dos_error(req, ERRSRV, ERRerror);
644 close the socket and shutdown a server_context
646 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
648 server_terminate_connection(smb_conn->connection, reason);
652 called on a fatal error that should cause this server to terminate
654 static void smbsrv_exit(struct server_service *service, const char *reason)
656 DEBUG(1,("smbsrv_exit\n"));
661 add a socket address to the list of events, one event per port
663 static void add_socket(struct server_service *service,
664 const struct model_ops *model_ops,
665 struct socket_context *socket_ctx,
666 struct ipv4_addr *ifip)
668 const char **ports = lp_smb_ports();
670 char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
672 for (i=0;ports[i];i++) {
673 uint16_t port = atoi(ports[i]);
674 if (port == 0) continue;
675 service_setup_socket(service, model_ops, "ipv4", ip_str, &port);
681 /****************************************************************************
682 Open the socket communication.
683 ****************************************************************************/
684 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
686 DEBUG(1,("smbsrv_init\n"));
688 if (lp_interfaces() && lp_bind_interfaces_only()) {
689 int num_interfaces = iface_count();
692 /* We have been given an interfaces line, and been
693 told to only bind to those interfaces. Create a
694 socket per interface and bind to only these.
696 for(i = 0; i < num_interfaces; i++) {
697 struct ipv4_addr *ifip = iface_n_ip(i);
700 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
704 add_socket(service, model_ops, NULL, ifip);
707 struct ipv4_addr ifip;
708 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
709 ifip = interpret_addr2(lp_socket_address());
710 add_socket(service, model_ops, NULL, &ifip);
715 called when a SMB socket becomes readable
717 static void smbsrv_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
719 struct smbsrv_connection *smb_conn = conn->private_data;
722 DEBUG(10,("smbsrv_recv\n"));
724 status = receive_smb_request(smb_conn, t);
725 if (NT_STATUS_IS_ERR(status)) {
726 conn->event.fde->flags = 0;
727 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
731 /* free up temporary memory */
736 called when a SMB socket becomes writable
738 static void smbsrv_send(struct server_connection *conn, struct timeval t, uint16_t flags)
740 struct smbsrv_connection *smb_conn = conn->private_data;
742 while (smb_conn->pending_send) {
743 struct smbsrv_request *req = smb_conn->pending_send;
748 blob.data = req->out.buffer;
749 blob.length = req->out.size;
751 /* send as much of this request as we can */
752 status = socket_send(conn->socket, &blob, &sendlen, 0);
753 if (NT_STATUS_IS_ERR(status)) {
754 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
761 req->out.buffer += sendlen;
762 req->out.size -= sendlen;
764 /* is the whole request gone? */
765 if (req->out.size == 0) {
766 DLIST_REMOVE(smb_conn->pending_send, req);
771 /* if no more requests are pending to be sent then
772 we should stop select for write */
773 if (smb_conn->pending_send == NULL) {
774 conn->event.fde->flags &= ~EVENT_FD_WRITE;
779 called when connection is idle
781 static void smbsrv_idle(struct server_connection *conn, struct timeval t)
783 DEBUG(10,("smbsrv_idle: not implemented!\n"));
784 conn->event.idle->next_event = timeval_add(&t, 5, 0);
788 static void smbsrv_close(struct server_connection *conn, const char *reason)
790 struct smbsrv_connection *smb_conn = conn->private_data;
792 DEBUG(5,("smbsrv_close: %s\n",reason));
794 conn_close_all(smb_conn);
796 talloc_free(smb_conn);
802 process a message from an SMB socket while still processing a
803 previous message this is used by backends who need to ensure that
804 new messages from clients are still processed while they are
805 performing long operations
807 void smbd_process_async(struct smbsrv_connection *smb_conn)
811 status = receive_smb_request(smb_conn, timeval_current());
812 if (NT_STATUS_IS_ERR(status)) {
813 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
819 initialise a server_context from a open socket and register a event handler
820 for reading from that socket
822 void smbsrv_accept(struct server_connection *conn)
824 struct smbsrv_connection *smb_conn;
827 DEBUG(5,("smbsrv_accept\n"));
829 smb_conn = talloc_zero_p(conn, struct smbsrv_connection);
830 if (!smb_conn) return;
832 smb_conn->pid = getpid();
834 sub_set_context(&smb_conn->substitute);
836 /* now initialise a few default values associated with this smb socket */
837 smb_conn->negotiate.max_send = 0xFFFF;
839 /* this is the size that w2k uses, and it appears to be important for
841 smb_conn->negotiate.max_recv = lp_max_xmit();
843 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
845 smb_conn->sessions.next_vuid = VUID_OFFSET;
847 srv_init_signing(smb_conn);
851 smb_conn->connection = conn;
853 conn->private_data = smb_conn;
855 fd = socket_get_fd(conn->socket);
856 set_blocking(fd, True);
858 /* setup the DCERPC server subsystem */
859 dcesrv_init_context(smb_conn, &smb_conn->dcesrv);
864 static const struct server_service_ops smb_server_ops = {
866 .service_init = smbsrv_init,
867 .accept_connection = smbsrv_accept,
868 .recv_handler = smbsrv_recv,
869 .send_handler = smbsrv_send,
870 .idle_handler = smbsrv_idle,
871 .close_connection = smbsrv_close,
872 .service_exit = smbsrv_exit,
875 const struct server_service_ops *smbsrv_get_ops(void)
877 return &smb_server_ops;
880 NTSTATUS server_service_smb_init(void)