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(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), req->smb_conn->connection->connection.id));
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);
652 static const struct server_stream_ops *smbsrv_stream_ops(void);
655 add a socket address to the list of events, one event per port
657 static void smb_add_socket(struct server_service *service,
658 struct ipv4_addr *ifip)
660 const char **ports = lp_smb_ports();
662 char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
664 for (i=0;ports[i];i++) {
665 uint16_t port = atoi(ports[i]);
666 if (port == 0) continue;
667 service_setup_stream_socket(service, smbsrv_stream_ops(), "ipv4", ip_str, &port);
673 /****************************************************************************
674 Open the socket communication.
675 ****************************************************************************/
676 static void smbsrv_init(struct server_service *service)
678 DEBUG(1,("smbsrv_init\n"));
680 if (lp_interfaces() && lp_bind_interfaces_only()) {
681 int num_interfaces = iface_count();
684 /* We have been given an interfaces line, and been
685 told to only bind to those interfaces. Create a
686 socket per interface and bind to only these.
688 for(i = 0; i < num_interfaces; i++) {
689 struct ipv4_addr *ifip = iface_n_ip(i);
692 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
696 smb_add_socket(service, ifip);
699 struct ipv4_addr ifip;
700 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
701 ifip = interpret_addr2(lp_socket_address());
702 smb_add_socket(service, &ifip);
707 called when a SMB socket becomes readable
709 static void smbsrv_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
711 struct smbsrv_connection *smb_conn = conn->connection.private_data;
714 DEBUG(10,("smbsrv_recv\n"));
716 status = receive_smb_request(smb_conn, t);
717 if (NT_STATUS_IS_ERR(status)) {
718 conn->event.fde->flags = 0;
719 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
723 /* free up temporary memory */
728 called when a SMB socket becomes writable
730 static void smbsrv_send(struct server_connection *conn, struct timeval t, uint16_t flags)
732 struct smbsrv_connection *smb_conn = conn->connection.private_data;
734 while (smb_conn->pending_send) {
735 struct smbsrv_request *req = smb_conn->pending_send;
740 blob.data = req->out.buffer;
741 blob.length = req->out.size;
743 /* send as much of this request as we can */
744 status = socket_send(conn->socket, &blob, &sendlen, 0);
745 if (NT_STATUS_IS_ERR(status)) {
746 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
753 req->out.buffer += sendlen;
754 req->out.size -= sendlen;
756 /* is the whole request gone? */
757 if (req->out.size == 0) {
758 DLIST_REMOVE(smb_conn->pending_send, req);
763 /* if no more requests are pending to be sent then
764 we should stop select for write */
765 if (smb_conn->pending_send == NULL) {
766 conn->event.fde->flags &= ~EVENT_FD_WRITE;
770 static void smbsrv_close(struct server_connection *conn, const char *reason)
772 struct smbsrv_connection *smb_conn = conn->connection.private_data;
774 DEBUG(5,("smbsrv_close: %s\n",reason));
776 talloc_free(smb_conn);
782 process a message from an SMB socket while still processing a
783 previous message this is used by backends who need to ensure that
784 new messages from clients are still processed while they are
785 performing long operations
787 void smbd_process_async(struct smbsrv_connection *smb_conn)
791 status = receive_smb_request(smb_conn, timeval_current());
792 if (NT_STATUS_IS_ERR(status)) {
793 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
799 initialise a server_context from a open socket and register a event handler
800 for reading from that socket
802 static void smbsrv_accept(struct server_connection *conn)
804 struct smbsrv_connection *smb_conn;
806 DEBUG(5,("smbsrv_accept\n"));
808 smb_conn = talloc_zero(conn, struct smbsrv_connection);
809 if (!smb_conn) return;
811 /* now initialise a few default values associated with this smb socket */
812 smb_conn->negotiate.max_send = 0xFFFF;
814 /* this is the size that w2k uses, and it appears to be important for
816 smb_conn->negotiate.max_recv = lp_max_xmit();
818 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
820 smb_conn->sessions.next_vuid = VUID_OFFSET;
822 srv_init_signing(smb_conn);
824 smbsrv_tcon_init(smb_conn);
826 smb_conn->connection = conn;
828 conn->connection.private_data = smb_conn;
833 static const struct server_stream_ops smb_stream_ops = {
836 .accept_connection = smbsrv_accept,
837 .recv_handler = smbsrv_recv,
838 .send_handler = smbsrv_send,
839 .idle_handler = NULL,
840 .close_connection = smbsrv_close
843 static const struct server_stream_ops *smbsrv_stream_ops(void)
845 return &smb_stream_ops;
848 static const struct server_service_ops smb_server_ops = {
850 .service_init = smbsrv_init,
853 const struct server_service_ops *smbsrv_get_ops(void)
855 return &smb_server_ops;
858 NTSTATUS server_service_smb_init(void)