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.
27 send an oplock break request to a client
29 BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
31 struct smbsrv_request *req;
33 req = init_smb_request(tcon->smb_conn);
35 req_setup_reply(req, 8, 0);
37 SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
38 SSVAL(req->out.hdr,HDR_TID,tcon->cnum);
39 SSVAL(req->out.hdr,HDR_PID,0xFFFF);
40 SSVAL(req->out.hdr,HDR_UID,0);
41 SSVAL(req->out.hdr,HDR_MID,0xFFFF);
42 SCVAL(req->out.hdr,HDR_FLG,0);
43 SSVAL(req->out.hdr,HDR_FLG2,0);
45 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
46 SSVAL(req->out.vwv, VWV(1), 0);
47 SSVAL(req->out.vwv, VWV(2), fnum);
48 SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
49 SCVAL(req->out.vwv, VWV(3)+1, level);
50 SIVAL(req->out.vwv, VWV(4), 0);
51 SSVAL(req->out.vwv, VWV(6), 0);
52 SSVAL(req->out.vwv, VWV(7), 0);
59 static void construct_reply(struct smbsrv_request *req);
61 /****************************************************************************
62 receive a SMB request header from the wire, forming a request_context
64 ****************************************************************************/
65 static NTSTATUS receive_smb_request(struct smbsrv_connection *smb_conn)
69 struct smbsrv_request *req;
72 /* allocate the request if needed */
73 if (smb_conn->partial_req == NULL) {
74 req = init_smb_request(smb_conn);
76 return NT_STATUS_NO_MEMORY;
79 req->in.buffer = talloc_array_p(req, char, NBT_HDR_SIZE);
80 if (req->in.buffer == NULL) {
82 return NT_STATUS_NO_MEMORY;
85 smb_conn->partial_req = req;
88 req = smb_conn->partial_req;
90 /* read in the header */
91 if (req->in.size < NBT_HDR_SIZE) {
92 status = socket_recv(smb_conn->connection->socket,
93 req->in.buffer + req->in.size,
94 NBT_HDR_SIZE - req->in.size,
96 if (NT_STATUS_IS_ERR(status)) {
102 req->in.size += nread;
104 /* when we have a full NBT header, then allocate the packet */
105 if (req->in.size == NBT_HDR_SIZE) {
106 len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
107 req->in.buffer = talloc_realloc(req, req->in.buffer, len);
108 if (req->in.buffer == NULL) {
109 return NT_STATUS_NO_MEMORY;
116 /* read in the main packet */
117 len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
119 status = socket_recv(smb_conn->connection->socket,
120 req->in.buffer + req->in.size,
123 if (NT_STATUS_IS_ERR(status)) {
130 req->in.size += nread;
132 if (req->in.size != len) {
136 /* we have a full packet */
137 GetTimeOfDay(&req->request_time);
138 req->chained_fnum = -1;
139 req->in.allocated = req->in.size;
140 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
141 req->in.vwv = req->in.hdr + HDR_VWV;
142 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
143 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
144 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
145 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
147 /* the bcc length is only 16 bits, but some packets
148 (such as SMBwriteX) can be much larger than 64k. We
149 detect this by looking for a large non-chained NBT
150 packet (at least 64k bigger than what is
151 specified). If it is detected then the NBT size is
152 used instead of the bcc size */
153 if (req->in.data_size + 0x10000 <=
154 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
155 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
156 /* its an oversized packet! fun for all the family */
157 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
161 smb_conn->partial_req = NULL;
163 construct_reply(req);
169 These flags determine some of the permissions required to do an operation
171 Note that I don't set NEED_WRITE on some write operations because they
172 are used by some brain-dead clients when printing, and I don't want to
173 force write permissions on print services.
175 #define AS_USER (1<<0)
176 #define NEED_WRITE (1<<1)
177 #define TIME_INIT (1<<2)
178 #define CAN_IPC (1<<3)
179 #define AS_GUEST (1<<5)
180 #define USE_MUTEX (1<<7)
183 define a list of possible SMB messages and their corresponding
184 functions. Any message that has a NULL function is unimplemented -
185 please feel free to contribute implementations!
187 static const struct smb_message_struct
190 void (*fn)(struct smbsrv_request *);
193 smb_messages[256] = {
194 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
195 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
196 /* 0x02 */ { "SMBopen",reply_open,AS_USER },
197 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
198 /* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
199 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
200 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
201 /* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
202 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
203 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
204 /* 0x0a */ { "SMBread",reply_read,AS_USER},
205 /* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
206 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
207 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
208 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
209 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
210 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
211 /* 0x11 */ { "SMBexit",reply_exit,0},
212 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
213 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
214 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
215 /* 0x15 */ { NULL, NULL, 0 },
216 /* 0x16 */ { NULL, NULL, 0 },
217 /* 0x17 */ { NULL, NULL, 0 },
218 /* 0x18 */ { NULL, NULL, 0 },
219 /* 0x19 */ { NULL, NULL, 0 },
220 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
221 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
222 /* 0x1c */ { "SMBreadBs",NULL,0 },
223 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
224 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
225 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
226 /* 0x20 */ { "SMBwritec",NULL,0},
227 /* 0x21 */ { NULL, NULL, 0 },
228 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
229 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
230 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
231 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
232 /* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
233 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
234 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
235 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
236 /* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE },
237 /* 0x2b */ { "SMBecho",reply_echo,0},
238 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
239 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
240 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
241 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
242 /* 0x30 */ { NULL, NULL, 0 },
243 /* 0x31 */ { NULL, NULL, 0 },
244 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
245 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
246 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
247 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
248 /* 0x36 */ { NULL, NULL, 0 },
249 /* 0x37 */ { NULL, NULL, 0 },
250 /* 0x38 */ { NULL, NULL, 0 },
251 /* 0x39 */ { NULL, NULL, 0 },
252 /* 0x3a */ { NULL, NULL, 0 },
253 /* 0x3b */ { NULL, NULL, 0 },
254 /* 0x3c */ { NULL, NULL, 0 },
255 /* 0x3d */ { NULL, NULL, 0 },
256 /* 0x3e */ { NULL, NULL, 0 },
257 /* 0x3f */ { NULL, NULL, 0 },
258 /* 0x40 */ { NULL, NULL, 0 },
259 /* 0x41 */ { NULL, NULL, 0 },
260 /* 0x42 */ { NULL, NULL, 0 },
261 /* 0x43 */ { NULL, NULL, 0 },
262 /* 0x44 */ { NULL, NULL, 0 },
263 /* 0x45 */ { NULL, NULL, 0 },
264 /* 0x46 */ { NULL, NULL, 0 },
265 /* 0x47 */ { NULL, NULL, 0 },
266 /* 0x48 */ { NULL, NULL, 0 },
267 /* 0x49 */ { NULL, NULL, 0 },
268 /* 0x4a */ { NULL, NULL, 0 },
269 /* 0x4b */ { NULL, NULL, 0 },
270 /* 0x4c */ { NULL, NULL, 0 },
271 /* 0x4d */ { NULL, NULL, 0 },
272 /* 0x4e */ { NULL, NULL, 0 },
273 /* 0x4f */ { NULL, NULL, 0 },
274 /* 0x50 */ { NULL, NULL, 0 },
275 /* 0x51 */ { NULL, NULL, 0 },
276 /* 0x52 */ { NULL, NULL, 0 },
277 /* 0x53 */ { NULL, NULL, 0 },
278 /* 0x54 */ { NULL, NULL, 0 },
279 /* 0x55 */ { NULL, NULL, 0 },
280 /* 0x56 */ { NULL, NULL, 0 },
281 /* 0x57 */ { NULL, NULL, 0 },
282 /* 0x58 */ { NULL, NULL, 0 },
283 /* 0x59 */ { NULL, NULL, 0 },
284 /* 0x5a */ { NULL, NULL, 0 },
285 /* 0x5b */ { NULL, NULL, 0 },
286 /* 0x5c */ { NULL, NULL, 0 },
287 /* 0x5d */ { NULL, NULL, 0 },
288 /* 0x5e */ { NULL, NULL, 0 },
289 /* 0x5f */ { NULL, NULL, 0 },
290 /* 0x60 */ { NULL, NULL, 0 },
291 /* 0x61 */ { NULL, NULL, 0 },
292 /* 0x62 */ { NULL, NULL, 0 },
293 /* 0x63 */ { NULL, NULL, 0 },
294 /* 0x64 */ { NULL, NULL, 0 },
295 /* 0x65 */ { NULL, NULL, 0 },
296 /* 0x66 */ { NULL, NULL, 0 },
297 /* 0x67 */ { NULL, NULL, 0 },
298 /* 0x68 */ { NULL, NULL, 0 },
299 /* 0x69 */ { NULL, NULL, 0 },
300 /* 0x6a */ { NULL, NULL, 0 },
301 /* 0x6b */ { NULL, NULL, 0 },
302 /* 0x6c */ { NULL, NULL, 0 },
303 /* 0x6d */ { NULL, NULL, 0 },
304 /* 0x6e */ { NULL, NULL, 0 },
305 /* 0x6f */ { NULL, NULL, 0 },
306 /* 0x70 */ { "SMBtcon",reply_tcon,USE_MUTEX},
307 /* 0x71 */ { "SMBtdis",reply_tdis,0},
308 /* 0x72 */ { "SMBnegprot",reply_negprot,USE_MUTEX},
309 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,USE_MUTEX},
310 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
311 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,USE_MUTEX},
312 /* 0x76 */ { NULL, NULL, 0 },
313 /* 0x77 */ { NULL, NULL, 0 },
314 /* 0x78 */ { NULL, NULL, 0 },
315 /* 0x79 */ { NULL, NULL, 0 },
316 /* 0x7a */ { NULL, NULL, 0 },
317 /* 0x7b */ { NULL, NULL, 0 },
318 /* 0x7c */ { NULL, NULL, 0 },
319 /* 0x7d */ { NULL, NULL, 0 },
320 /* 0x7e */ { NULL, NULL, 0 },
321 /* 0x7f */ { NULL, NULL, 0 },
322 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
323 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
324 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
325 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
326 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
327 /* 0x85 */ { NULL, NULL, 0 },
328 /* 0x86 */ { NULL, NULL, 0 },
329 /* 0x87 */ { NULL, NULL, 0 },
330 /* 0x88 */ { NULL, NULL, 0 },
331 /* 0x89 */ { NULL, NULL, 0 },
332 /* 0x8a */ { NULL, NULL, 0 },
333 /* 0x8b */ { NULL, NULL, 0 },
334 /* 0x8c */ { NULL, NULL, 0 },
335 /* 0x8d */ { NULL, NULL, 0 },
336 /* 0x8e */ { NULL, NULL, 0 },
337 /* 0x8f */ { NULL, NULL, 0 },
338 /* 0x90 */ { NULL, NULL, 0 },
339 /* 0x91 */ { NULL, NULL, 0 },
340 /* 0x92 */ { NULL, NULL, 0 },
341 /* 0x93 */ { NULL, NULL, 0 },
342 /* 0x94 */ { NULL, NULL, 0 },
343 /* 0x95 */ { NULL, NULL, 0 },
344 /* 0x96 */ { NULL, NULL, 0 },
345 /* 0x97 */ { NULL, NULL, 0 },
346 /* 0x98 */ { NULL, NULL, 0 },
347 /* 0x99 */ { NULL, NULL, 0 },
348 /* 0x9a */ { NULL, NULL, 0 },
349 /* 0x9b */ { NULL, NULL, 0 },
350 /* 0x9c */ { NULL, NULL, 0 },
351 /* 0x9d */ { NULL, NULL, 0 },
352 /* 0x9e */ { NULL, NULL, 0 },
353 /* 0x9f */ { NULL, NULL, 0 },
354 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
355 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
356 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC },
357 /* 0xa3 */ { NULL, NULL, 0 },
358 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
359 /* 0xa5 */ { "SMBntrename", reply_ntrename, 0 },
360 /* 0xa6 */ { NULL, NULL, 0 },
361 /* 0xa7 */ { NULL, NULL, 0 },
362 /* 0xa8 */ { NULL, NULL, 0 },
363 /* 0xa9 */ { NULL, NULL, 0 },
364 /* 0xaa */ { NULL, NULL, 0 },
365 /* 0xab */ { NULL, NULL, 0 },
366 /* 0xac */ { NULL, NULL, 0 },
367 /* 0xad */ { NULL, NULL, 0 },
368 /* 0xae */ { NULL, NULL, 0 },
369 /* 0xaf */ { NULL, NULL, 0 },
370 /* 0xb0 */ { NULL, NULL, 0 },
371 /* 0xb1 */ { NULL, NULL, 0 },
372 /* 0xb2 */ { NULL, NULL, 0 },
373 /* 0xb3 */ { NULL, NULL, 0 },
374 /* 0xb4 */ { NULL, NULL, 0 },
375 /* 0xb5 */ { NULL, NULL, 0 },
376 /* 0xb6 */ { NULL, NULL, 0 },
377 /* 0xb7 */ { NULL, NULL, 0 },
378 /* 0xb8 */ { NULL, NULL, 0 },
379 /* 0xb9 */ { NULL, NULL, 0 },
380 /* 0xba */ { NULL, NULL, 0 },
381 /* 0xbb */ { NULL, NULL, 0 },
382 /* 0xbc */ { NULL, NULL, 0 },
383 /* 0xbd */ { NULL, NULL, 0 },
384 /* 0xbe */ { NULL, NULL, 0 },
385 /* 0xbf */ { NULL, NULL, 0 },
386 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
387 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
388 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
389 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
390 /* 0xc4 */ { NULL, NULL, 0 },
391 /* 0xc5 */ { NULL, NULL, 0 },
392 /* 0xc6 */ { NULL, NULL, 0 },
393 /* 0xc7 */ { NULL, NULL, 0 },
394 /* 0xc8 */ { NULL, NULL, 0 },
395 /* 0xc9 */ { NULL, NULL, 0 },
396 /* 0xca */ { NULL, NULL, 0 },
397 /* 0xcb */ { NULL, NULL, 0 },
398 /* 0xcc */ { NULL, NULL, 0 },
399 /* 0xcd */ { NULL, NULL, 0 },
400 /* 0xce */ { NULL, NULL, 0 },
401 /* 0xcf */ { NULL, NULL, 0 },
402 /* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
403 /* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
404 /* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
405 /* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
406 /* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
407 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
408 /* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
409 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
410 /* 0xd8 */ { NULL, NULL, 0 },
411 /* 0xd9 */ { NULL, NULL, 0 },
412 /* 0xda */ { NULL, NULL, 0 },
413 /* 0xdb */ { NULL, NULL, 0 },
414 /* 0xdc */ { NULL, NULL, 0 },
415 /* 0xdd */ { NULL, NULL, 0 },
416 /* 0xde */ { NULL, NULL, 0 },
417 /* 0xdf */ { NULL, NULL, 0 },
418 /* 0xe0 */ { NULL, NULL, 0 },
419 /* 0xe1 */ { NULL, NULL, 0 },
420 /* 0xe2 */ { NULL, NULL, 0 },
421 /* 0xe3 */ { NULL, NULL, 0 },
422 /* 0xe4 */ { NULL, NULL, 0 },
423 /* 0xe5 */ { NULL, NULL, 0 },
424 /* 0xe6 */ { NULL, NULL, 0 },
425 /* 0xe7 */ { NULL, NULL, 0 },
426 /* 0xe8 */ { NULL, NULL, 0 },
427 /* 0xe9 */ { NULL, NULL, 0 },
428 /* 0xea */ { NULL, NULL, 0 },
429 /* 0xeb */ { NULL, NULL, 0 },
430 /* 0xec */ { NULL, NULL, 0 },
431 /* 0xed */ { NULL, NULL, 0 },
432 /* 0xee */ { NULL, NULL, 0 },
433 /* 0xef */ { NULL, NULL, 0 },
434 /* 0xf0 */ { NULL, NULL, 0 },
435 /* 0xf1 */ { NULL, NULL, 0 },
436 /* 0xf2 */ { NULL, NULL, 0 },
437 /* 0xf3 */ { NULL, NULL, 0 },
438 /* 0xf4 */ { NULL, NULL, 0 },
439 /* 0xf5 */ { NULL, NULL, 0 },
440 /* 0xf6 */ { NULL, NULL, 0 },
441 /* 0xf7 */ { NULL, NULL, 0 },
442 /* 0xf8 */ { NULL, NULL, 0 },
443 /* 0xf9 */ { NULL, NULL, 0 },
444 /* 0xfa */ { NULL, NULL, 0 },
445 /* 0xfb */ { NULL, NULL, 0 },
446 /* 0xfc */ { NULL, NULL, 0 },
447 /* 0xfd */ { NULL, NULL, 0 },
448 /* 0xfe */ { NULL, NULL, 0 },
449 /* 0xff */ { NULL, NULL, 0 }
452 /****************************************************************************
453 return a string containing the function name of a SMB command
454 ****************************************************************************/
455 static const char *smb_fn_name(uint8_t type)
457 const char *unknown_name = "SMBunknown";
459 if (smb_messages[type].name == NULL)
462 return smb_messages[type].name;
466 /****************************************************************************
467 Do a switch on the message type and call the specific reply function for this
468 message. Unlike earlier versions of Samba the reply functions are responsible
469 for sending the reply themselves, rather than returning a size to this function
470 The reply functions may also choose to delay the processing by pushing the message
471 onto the message queue
472 ****************************************************************************/
473 static void switch_message(int type, struct smbsrv_request *req)
476 struct smbsrv_connection *smb_conn = req->smb_conn;
477 uint16_t session_tag;
483 if (smb_messages[type].fn == NULL) {
484 DEBUG(0,("Unknown message type %d!\n",type));
489 flags = smb_messages[type].flags;
491 req->tcon = conn_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
493 if (req->session == NULL) {
494 /* setup the user context for this request if it
495 hasn't already been initialised (to cope with SMB
498 /* In share mode security we must ignore the vuid. */
499 if (lp_security() == SEC_SHARE) {
500 session_tag = UID_FIELD_INVALID;
502 session_tag = SVAL(req->in.hdr,HDR_UID);
505 req->session = smbsrv_session_find(req->smb_conn, session_tag);
507 req->session->vuid = session_tag;
510 session_tag = req->session->vuid;
513 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb_conn->connection->service->model_ops->get_id(req)));
515 /* does this protocol need to be run as root? */
516 if (!(flags & AS_USER)) {
517 change_to_root_user();
520 /* does this protocol need a valid tree connection? */
521 if ((flags & AS_USER) && !req->tcon) {
522 req_reply_error(req, NT_STATUS_INVALID_HANDLE);
526 /* see if the vuid is valid */
527 if ((flags & AS_USER) && !req->session) {
528 if (!(flags & AS_GUEST)) {
529 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
534 /* does this protocol need to be run as the connected user? */
536 if ((flags & AS_USER) && !change_to_user(req->tcon,session_tag)) {
537 if (!(flags & AS_GUEST)) {
538 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
542 /* we'll run it as guest */
547 /* this code is to work around a bug is MS client 3 without
548 introducing a security hole - it needs to be able to do
549 print queue checks as guest if it isn't logged in properly */
550 if (flags & AS_USER) {
554 /* does it need write permission? */
555 if ((flags & NEED_WRITE) && !CAN_WRITE(req->tcon)) {
556 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
560 /* ipc services are limited */
561 if (req->tcon && req->tcon->ntvfs_ctx->type == NTVFS_IPC && (flags & AS_USER) && !(flags & CAN_IPC)) {
562 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
566 /* load service specific parameters */
567 if (req->tcon && !set_current_service(req->tcon,(flags & AS_USER)?True:False)) {
568 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
572 /* does this protocol need to be run as guest? */
574 if ((flags & AS_GUEST) &&
575 !change_to_guest()) {
576 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
580 /* THREAD TESTING: use mutex to serialize calls to critical functions with global state */
581 if (flags & USE_MUTEX) {
582 MUTEX_LOCK_BY_ID(MUTEX_SMBD);
584 smb_messages[type].fn(req);
585 if (flags & USE_MUTEX) {
586 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
591 /****************************************************************************
592 Construct a reply to the incoming packet.
593 ****************************************************************************/
594 static void construct_reply(struct smbsrv_request *req)
596 uint8_t type = CVAL(req->in.hdr,HDR_COM);
598 /* see if its a special NBT packet */
599 if (CVAL(req->in.buffer,0) != 0) {
604 /* Make sure this is an SMB packet */
605 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
606 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
608 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
612 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
613 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
614 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
618 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
619 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
620 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
624 req->flags = CVAL(req->in.hdr, HDR_FLG);
625 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
626 req->smbpid = SVAL(req->in.hdr,HDR_PID);
627 req->mid = SVAL(req->in.hdr,HDR_MID);
629 if (!req_signing_check_incoming(req)) {
630 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
634 switch_message(type, req);
639 we call this when first first part of a possibly chained request has been completed
640 and we need to call the 2nd part, if any
642 void chain_reply(struct smbsrv_request *req)
644 uint16_t chain_cmd, chain_offset;
649 if (req->in.wct < 2 || req->out.wct < 2) {
650 req_reply_dos_error(req, ERRSRV, ERRerror);
654 chain_cmd = CVAL(req->in.vwv, VWV(0));
655 chain_offset = SVAL(req->in.vwv, VWV(1));
657 if (chain_cmd == SMB_CHAIN_NONE) {
659 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
660 SSVAL(req->out.vwv, VWV(1), 0);
665 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
669 wct = CVAL(req->in.hdr, chain_offset);
670 vwv = req->in.hdr + chain_offset + 1;
672 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
676 data_size = SVAL(vwv, VWV(wct));
677 data = vwv + VWV(wct) + 2;
679 if (data + data_size > req->in.buffer + req->in.size) {
683 /* all seems legit */
687 req->in.data_size = data_size;
692 SSVAL(req->out.vwv, VWV(0), chain_cmd);
693 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
695 /* the current request in the chain might have used an async reply,
696 but that doesn't mean the next element needs to */
697 ZERO_STRUCTP(req->async_states);
699 switch_message(chain_cmd, req);
703 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
704 SSVAL(req->out.vwv, VWV(1), 0);
705 req_reply_dos_error(req, ERRSRV, ERRerror);
710 close the socket and shutdown a server_context
712 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
714 server_terminate_connection(smb_conn->connection, reason);
718 called on a fatal error that should cause this server to terminate
720 static void smbsrv_exit(struct server_service *service, const char *reason)
722 DEBUG(1,("smbsrv_exit\n"));
727 add a socket address to the list of events, one event per port
729 static void add_socket(struct server_service *service,
730 const struct model_ops *model_ops,
731 struct socket_context *socket_ctx,
732 struct in_addr *ifip)
734 const char **ports = lp_smb_ports();
736 char *ip_str = talloc_strdup(service, inet_ntoa(*ifip));
738 for (i=0;ports[i];i++) {
739 uint16_t port = atoi(ports[i]);
740 if (port == 0) continue;
741 service_setup_socket(service, model_ops, "ipv4", ip_str, &port);
747 /****************************************************************************
748 Open the socket communication.
749 ****************************************************************************/
750 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
752 DEBUG(1,("smbsrv_init\n"));
754 if (lp_interfaces() && lp_bind_interfaces_only()) {
755 int num_interfaces = iface_count();
758 /* We have been given an interfaces line, and been
759 told to only bind to those interfaces. Create a
760 socket per interface and bind to only these.
762 for(i = 0; i < num_interfaces; i++) {
763 struct in_addr *ifip = iface_n_ip(i);
766 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
770 add_socket(service, model_ops, NULL, ifip);
774 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
775 ifip = interpret_addr2(lp_socket_address());
776 add_socket(service, model_ops, NULL, &ifip);
781 called when a SMB socket becomes readable
783 static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
785 struct smbsrv_connection *smb_conn = conn->private_data;
788 DEBUG(10,("smbsrv_recv\n"));
790 status = receive_smb_request(smb_conn);
791 if (NT_STATUS_IS_ERR(status)) {
792 conn->event.fde->flags = 0;
793 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
797 /* free up temporary memory */
802 called when a SMB socket becomes writable
804 static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
806 struct smbsrv_connection *smb_conn = conn->private_data;
808 while (smb_conn->pending_send) {
809 struct smbsrv_request *req = smb_conn->pending_send;
814 blob.data = req->out.buffer;
815 blob.length = req->out.size;
817 /* send as much of this request as we can */
818 status = socket_send(conn->socket, &blob, &sendlen, 0);
819 if (NT_STATUS_IS_ERR(status)) {
820 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
827 req->out.buffer += sendlen;
828 req->out.size -= sendlen;
830 /* is the whole request gone? */
831 if (req->out.size == 0) {
832 DLIST_REMOVE(smb_conn->pending_send, req);
837 /* if no more requests are pending to be sent then
838 we should stop select for write */
839 if (smb_conn->pending_send == NULL) {
840 conn->event.fde->flags &= ~EVENT_FD_WRITE;
845 called when connection is idle
847 static void smbsrv_idle(struct server_connection *conn, time_t t)
849 DEBUG(10,("smbsrv_idle: not implemented!\n"));
850 conn->event.idle->next_event = t + 5;
855 static void smbsrv_close(struct server_connection *conn, const char *reason)
857 struct smbsrv_connection *smb_conn = conn->private_data;
859 DEBUG(5,("smbsrv_close: %s\n",reason));
861 conn_close_all(smb_conn);
863 talloc_free(smb_conn);
869 process a message from an SMB socket while still processing a
870 previous message this is used by backends who need to ensure that
871 new messages from clients are still processed while they are
872 performing long operations
874 void smbd_process_async(struct smbsrv_connection *smb_conn)
878 status = receive_smb_request(smb_conn);
879 if (NT_STATUS_IS_ERR(status)) {
880 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
886 initialise a server_context from a open socket and register a event handler
887 for reading from that socket
889 void smbsrv_accept(struct server_connection *conn)
891 struct smbsrv_connection *smb_conn;
894 DEBUG(5,("smbsrv_accept\n"));
896 smb_conn = talloc_zero_p(conn, struct smbsrv_connection);
897 if (!smb_conn) return;
899 smb_conn->pid = getpid();
901 sub_set_context(&smb_conn->substitute);
903 /* now initialise a few default values associated with this smb socket */
904 smb_conn->negotiate.max_send = 0xFFFF;
906 /* this is the size that w2k uses, and it appears to be important for
908 smb_conn->negotiate.max_recv = lp_max_xmit();
910 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
912 smb_conn->sessions.next_vuid = VUID_OFFSET;
914 srv_init_signing(smb_conn);
918 smb_conn->connection = conn;
920 conn->private_data = smb_conn;
922 fd = socket_get_fd(conn->socket);
923 set_blocking(fd, True);
925 /* setup the DCERPC server subsystem */
926 dcesrv_init_context(smb_conn, &smb_conn->dcesrv);
931 static const struct server_service_ops smb_server_ops = {
933 .service_init = smbsrv_init,
934 .accept_connection = smbsrv_accept,
935 .recv_handler = smbsrv_recv,
936 .send_handler = smbsrv_send,
937 .idle_handler = smbsrv_idle,
938 .close_connection = smbsrv_close,
939 .service_exit = smbsrv_exit,
942 const struct server_service_ops *smbsrv_get_ops(void)
944 return &smb_server_ops;
947 NTSTATUS server_service_smb_init(void)