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);
628 if (!req_signing_check_incoming(req)) {
629 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
633 switch_message(type, req);
638 we call this when first first part of a possibly chained request has been completed
639 and we need to call the 2nd part, if any
641 void chain_reply(struct smbsrv_request *req)
643 uint16_t chain_cmd, chain_offset;
648 if (req->in.wct < 2 || req->out.wct < 2) {
649 req_reply_dos_error(req, ERRSRV, ERRerror);
653 chain_cmd = CVAL(req->in.vwv, VWV(0));
654 chain_offset = SVAL(req->in.vwv, VWV(1));
656 if (chain_cmd == SMB_CHAIN_NONE) {
658 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
659 SSVAL(req->out.vwv, VWV(1), 0);
664 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
668 wct = CVAL(req->in.hdr, chain_offset);
669 vwv = req->in.hdr + chain_offset + 1;
671 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
675 data_size = SVAL(vwv, VWV(wct));
676 data = vwv + VWV(wct) + 2;
678 if (data + data_size > req->in.buffer + req->in.size) {
682 /* all seems legit */
686 req->in.data_size = data_size;
691 SSVAL(req->out.vwv, VWV(0), chain_cmd);
692 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
694 /* the current request in the chain might have used an async reply,
695 but that doesn't mean the next element needs to */
696 ZERO_STRUCTP(req->async_states);
698 switch_message(chain_cmd, req);
702 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
703 SSVAL(req->out.vwv, VWV(1), 0);
704 req_reply_dos_error(req, ERRSRV, ERRerror);
709 close the socket and shutdown a server_context
711 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
713 server_terminate_connection(smb_conn->connection, reason);
717 called on a fatal error that should cause this server to terminate
719 static void smbsrv_exit(struct server_service *service, const char *reason)
721 DEBUG(1,("smbsrv_exit\n"));
726 add a socket address to the list of events, one event per port
728 static void add_socket(struct server_service *service,
729 const struct model_ops *model_ops,
730 struct socket_context *socket_ctx,
731 struct ipv4_addr *ifip)
733 const char **ports = lp_smb_ports();
735 char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
737 for (i=0;ports[i];i++) {
738 uint16_t port = atoi(ports[i]);
739 if (port == 0) continue;
740 service_setup_socket(service, model_ops, "ipv4", ip_str, &port);
746 /****************************************************************************
747 Open the socket communication.
748 ****************************************************************************/
749 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
751 DEBUG(1,("smbsrv_init\n"));
753 if (lp_interfaces() && lp_bind_interfaces_only()) {
754 int num_interfaces = iface_count();
757 /* We have been given an interfaces line, and been
758 told to only bind to those interfaces. Create a
759 socket per interface and bind to only these.
761 for(i = 0; i < num_interfaces; i++) {
762 struct ipv4_addr *ifip = iface_n_ip(i);
765 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
769 add_socket(service, model_ops, NULL, ifip);
772 struct ipv4_addr ifip;
773 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
774 ifip = interpret_addr2(lp_socket_address());
775 add_socket(service, model_ops, NULL, &ifip);
780 called when a SMB socket becomes readable
782 static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
784 struct smbsrv_connection *smb_conn = conn->private_data;
787 DEBUG(10,("smbsrv_recv\n"));
789 status = receive_smb_request(smb_conn);
790 if (NT_STATUS_IS_ERR(status)) {
791 conn->event.fde->flags = 0;
792 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
796 /* free up temporary memory */
801 called when a SMB socket becomes writable
803 static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
805 struct smbsrv_connection *smb_conn = conn->private_data;
807 while (smb_conn->pending_send) {
808 struct smbsrv_request *req = smb_conn->pending_send;
813 blob.data = req->out.buffer;
814 blob.length = req->out.size;
816 /* send as much of this request as we can */
817 status = socket_send(conn->socket, &blob, &sendlen, 0);
818 if (NT_STATUS_IS_ERR(status)) {
819 smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
826 req->out.buffer += sendlen;
827 req->out.size -= sendlen;
829 /* is the whole request gone? */
830 if (req->out.size == 0) {
831 DLIST_REMOVE(smb_conn->pending_send, req);
836 /* if no more requests are pending to be sent then
837 we should stop select for write */
838 if (smb_conn->pending_send == NULL) {
839 conn->event.fde->flags &= ~EVENT_FD_WRITE;
844 called when connection is idle
846 static void smbsrv_idle(struct server_connection *conn, time_t t)
848 DEBUG(10,("smbsrv_idle: not implemented!\n"));
849 conn->event.idle->next_event = t + 5;
854 static void smbsrv_close(struct server_connection *conn, const char *reason)
856 struct smbsrv_connection *smb_conn = conn->private_data;
858 DEBUG(5,("smbsrv_close: %s\n",reason));
860 conn_close_all(smb_conn);
862 talloc_free(smb_conn);
868 process a message from an SMB socket while still processing a
869 previous message this is used by backends who need to ensure that
870 new messages from clients are still processed while they are
871 performing long operations
873 void smbd_process_async(struct smbsrv_connection *smb_conn)
877 status = receive_smb_request(smb_conn);
878 if (NT_STATUS_IS_ERR(status)) {
879 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
885 initialise a server_context from a open socket and register a event handler
886 for reading from that socket
888 void smbsrv_accept(struct server_connection *conn)
890 struct smbsrv_connection *smb_conn;
893 DEBUG(5,("smbsrv_accept\n"));
895 smb_conn = talloc_zero_p(conn, struct smbsrv_connection);
896 if (!smb_conn) return;
898 smb_conn->pid = getpid();
900 sub_set_context(&smb_conn->substitute);
902 /* now initialise a few default values associated with this smb socket */
903 smb_conn->negotiate.max_send = 0xFFFF;
905 /* this is the size that w2k uses, and it appears to be important for
907 smb_conn->negotiate.max_recv = lp_max_xmit();
909 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
911 smb_conn->sessions.next_vuid = VUID_OFFSET;
913 srv_init_signing(smb_conn);
917 smb_conn->connection = conn;
919 conn->private_data = smb_conn;
921 fd = socket_get_fd(conn->socket);
922 set_blocking(fd, True);
924 /* setup the DCERPC server subsystem */
925 dcesrv_init_context(smb_conn, &smb_conn->dcesrv);
930 static const struct server_service_ops smb_server_ops = {
932 .service_init = smbsrv_init,
933 .accept_connection = smbsrv_accept,
934 .recv_handler = smbsrv_recv,
935 .send_handler = smbsrv_send,
936 .idle_handler = smbsrv_idle,
937 .close_connection = smbsrv_close,
938 .service_exit = smbsrv_exit,
941 const struct server_service_ops *smbsrv_get_ops(void)
943 return &smb_server_ops;
946 NTSTATUS server_service_smb_init(void)