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)
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 GetTimeOfDay(&req->request_time);
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)
176 #define USE_MUTEX (1<<1)
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",NULL,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,USE_MUTEX},
303 /* 0x71 */ { "SMBtdis",reply_tdis,0},
304 /* 0x72 */ { "SMBnegprot",reply_negprot,USE_MUTEX},
305 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,USE_MUTEX},
306 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
307 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,USE_MUTEX},
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 = conn_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 /* THREAD TESTING: use mutex to serialize calls to critical
524 functions with global state */
525 if (flags & USE_MUTEX) {
526 MUTEX_LOCK_BY_ID(MUTEX_SMBD);
528 smb_messages[type].fn(req);
529 if (flags & USE_MUTEX) {
530 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
535 /****************************************************************************
536 Construct a reply to the incoming packet.
537 ****************************************************************************/
538 static void construct_reply(struct smbsrv_request *req)
540 uint8_t type = CVAL(req->in.hdr,HDR_COM);
542 /* see if its a special NBT packet */
543 if (CVAL(req->in.buffer,0) != 0) {
548 /* Make sure this is an SMB packet */
549 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
550 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
552 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
556 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
557 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
558 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
562 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
563 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
564 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
568 req->flags = CVAL(req->in.hdr, HDR_FLG);
569 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
570 req->smbpid = SVAL(req->in.hdr,HDR_PID);
572 if (!req_signing_check_incoming(req)) {
573 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
577 switch_message(type, req);
582 we call this when first first part of a possibly chained request has been completed
583 and we need to call the 2nd part, if any
585 void chain_reply(struct smbsrv_request *req)
587 uint16_t chain_cmd, chain_offset;
592 if (req->in.wct < 2 || req->out.wct < 2) {
593 req_reply_dos_error(req, ERRSRV, ERRerror);
597 chain_cmd = CVAL(req->in.vwv, VWV(0));
598 chain_offset = SVAL(req->in.vwv, VWV(1));
600 if (chain_cmd == SMB_CHAIN_NONE) {
602 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
603 SSVAL(req->out.vwv, VWV(1), 0);
608 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
612 wct = CVAL(req->in.hdr, chain_offset);
613 vwv = req->in.hdr + chain_offset + 1;
615 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
619 data_size = SVAL(vwv, VWV(wct));
620 data = vwv + VWV(wct) + 2;
622 if (data + data_size > req->in.buffer + req->in.size) {
626 /* all seems legit */
630 req->in.data_size = data_size;
635 SSVAL(req->out.vwv, VWV(0), chain_cmd);
636 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
638 /* the current request in the chain might have used an async reply,
639 but that doesn't mean the next element needs to */
640 ZERO_STRUCTP(req->async_states);
642 switch_message(chain_cmd, req);
646 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
647 SSVAL(req->out.vwv, VWV(1), 0);
648 req_reply_dos_error(req, ERRSRV, ERRerror);
653 close the socket and shutdown a server_context
655 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
657 server_terminate_connection(smb_conn->connection, reason);
661 called on a fatal error that should cause this server to terminate
663 static void smbsrv_exit(struct server_service *service, const char *reason)
665 DEBUG(1,("smbsrv_exit\n"));
670 add a socket address to the list of events, one event per port
672 static void add_socket(struct server_service *service,
673 const struct model_ops *model_ops,
674 struct socket_context *socket_ctx,
675 struct ipv4_addr *ifip)
677 const char **ports = lp_smb_ports();
679 char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
681 for (i=0;ports[i];i++) {
682 uint16_t port = atoi(ports[i]);
683 if (port == 0) continue;
684 service_setup_socket(service, model_ops, "ipv4", ip_str, &port);
690 /****************************************************************************
691 Open the socket communication.
692 ****************************************************************************/
693 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
695 DEBUG(1,("smbsrv_init\n"));
697 if (lp_interfaces() && lp_bind_interfaces_only()) {
698 int num_interfaces = iface_count();
701 /* We have been given an interfaces line, and been
702 told to only bind to those interfaces. Create a
703 socket per interface and bind to only these.
705 for(i = 0; i < num_interfaces; i++) {
706 struct ipv4_addr *ifip = iface_n_ip(i);
709 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
713 add_socket(service, model_ops, NULL, ifip);
716 struct ipv4_addr ifip;
717 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
718 ifip = interpret_addr2(lp_socket_address());
719 add_socket(service, model_ops, NULL, &ifip);
724 called when a SMB socket becomes readable
726 static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
728 struct smbsrv_connection *smb_conn = conn->private_data;
731 DEBUG(10,("smbsrv_recv\n"));
733 status = receive_smb_request(smb_conn);
734 if (NT_STATUS_IS_ERR(status)) {
735 conn->event.fde->flags = 0;
736 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
740 /* free up temporary memory */
745 called when a SMB socket becomes writable
747 static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
749 struct smbsrv_connection *smb_conn = conn->private_data;
751 while (smb_conn->pending_send) {
752 struct smbsrv_request *req = smb_conn->pending_send;
757 blob.data = req->out.buffer;
758 blob.length = req->out.size;
760 /* send as much of this request as we can */
761 status = socket_send(conn->socket, &blob, &sendlen, 0);
762 if (NT_STATUS_IS_ERR(status)) {
763 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
770 req->out.buffer += sendlen;
771 req->out.size -= sendlen;
773 /* is the whole request gone? */
774 if (req->out.size == 0) {
775 DLIST_REMOVE(smb_conn->pending_send, req);
780 /* if no more requests are pending to be sent then
781 we should stop select for write */
782 if (smb_conn->pending_send == NULL) {
783 conn->event.fde->flags &= ~EVENT_FD_WRITE;
788 called when connection is idle
790 static void smbsrv_idle(struct server_connection *conn, time_t t)
792 DEBUG(10,("smbsrv_idle: not implemented!\n"));
793 conn->event.idle->next_event = t + 5;
798 static void smbsrv_close(struct server_connection *conn, const char *reason)
800 struct smbsrv_connection *smb_conn = conn->private_data;
802 DEBUG(5,("smbsrv_close: %s\n",reason));
804 conn_close_all(smb_conn);
806 talloc_free(smb_conn);
812 process a message from an SMB socket while still processing a
813 previous message this is used by backends who need to ensure that
814 new messages from clients are still processed while they are
815 performing long operations
817 void smbd_process_async(struct smbsrv_connection *smb_conn)
821 status = receive_smb_request(smb_conn);
822 if (NT_STATUS_IS_ERR(status)) {
823 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
829 initialise a server_context from a open socket and register a event handler
830 for reading from that socket
832 void smbsrv_accept(struct server_connection *conn)
834 struct smbsrv_connection *smb_conn;
837 DEBUG(5,("smbsrv_accept\n"));
839 smb_conn = talloc_zero_p(conn, struct smbsrv_connection);
840 if (!smb_conn) return;
842 smb_conn->pid = getpid();
844 sub_set_context(&smb_conn->substitute);
846 /* now initialise a few default values associated with this smb socket */
847 smb_conn->negotiate.max_send = 0xFFFF;
849 /* this is the size that w2k uses, and it appears to be important for
851 smb_conn->negotiate.max_recv = lp_max_xmit();
853 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
855 smb_conn->sessions.next_vuid = VUID_OFFSET;
857 srv_init_signing(smb_conn);
861 smb_conn->connection = conn;
863 conn->private_data = smb_conn;
865 fd = socket_get_fd(conn->socket);
866 set_blocking(fd, True);
868 /* setup the DCERPC server subsystem */
869 dcesrv_init_context(smb_conn, &smb_conn->dcesrv);
874 static const struct server_service_ops smb_server_ops = {
876 .service_init = smbsrv_init,
877 .accept_connection = smbsrv_accept,
878 .recv_handler = smbsrv_recv,
879 .send_handler = smbsrv_send,
880 .idle_handler = smbsrv_idle,
881 .close_connection = smbsrv_close,
882 .service_exit = smbsrv_exit,
885 const struct server_service_ops *smbsrv_get_ops(void)
887 return &smb_server_ops;
890 NTSTATUS server_service_smb_init(void)