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.
24 #include "lib/events/events.h"
25 #include "system/time.h"
26 #include "dlinklist.h"
27 #include "smbd/service_stream.h"
28 #include "smb_server/smb_server.h"
29 #include "lib/messaging/irpc.h"
30 #include "lib/stream/packet.h"
34 send an oplock break request to a client
36 BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
38 struct smbsrv_request *req;
40 req = init_smb_request(tcon->smb_conn);
42 req_setup_reply(req, 8, 0);
44 SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
45 SSVAL(req->out.hdr,HDR_TID,tcon->tid);
46 SSVAL(req->out.hdr,HDR_PID,0xFFFF);
47 SSVAL(req->out.hdr,HDR_UID,0);
48 SSVAL(req->out.hdr,HDR_MID,0xFFFF);
49 SCVAL(req->out.hdr,HDR_FLG,0);
50 SSVAL(req->out.hdr,HDR_FLG2,0);
52 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
53 SSVAL(req->out.vwv, VWV(1), 0);
54 SSVAL(req->out.vwv, VWV(2), fnum);
55 SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
56 SCVAL(req->out.vwv, VWV(3)+1, level);
57 SIVAL(req->out.vwv, VWV(4), 0);
58 SSVAL(req->out.vwv, VWV(6), 0);
59 SSVAL(req->out.vwv, VWV(7), 0);
65 static void switch_message(int type, struct smbsrv_request *req);
67 /****************************************************************************
68 receive a SMB request header from the wire, forming a request_context
70 ****************************************************************************/
71 static NTSTATUS receive_smb_request(void *private, DATA_BLOB blob)
73 struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
74 struct smbsrv_request *req;
77 /* see if its a special NBT packet */
78 if (CVAL(blob.data, 0) != 0) {
79 req = init_smb_request(smb_conn);
80 NT_STATUS_HAVE_NO_MEMORY(req);
84 req->in.buffer = talloc_steal(req, blob.data);
85 req->in.size = blob.length;
86 req->request_time = timeval_current();
92 if ((NBT_HDR_SIZE + MIN_SMB_SIZE) > blob.length) {
93 DEBUG(2,("Invalid SMB packet: length %d\n", blob.length));
94 smbsrv_terminate_connection(smb_conn, "Invalid SMB packet");
98 /* Make sure this is an SMB packet */
99 if (IVAL(blob.data, NBT_HDR_SIZE) != SMB_MAGIC) {
100 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
102 smbsrv_terminate_connection(smb_conn, "Non-SMB packet");
106 req = init_smb_request(smb_conn);
107 NT_STATUS_HAVE_NO_MEMORY(req);
109 req->in.buffer = talloc_steal(req, blob.data);
110 req->in.size = blob.length;
111 req->request_time = timeval_current();
112 req->chained_fnum = -1;
113 req->in.allocated = req->in.size;
114 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
115 req->in.vwv = req->in.hdr + HDR_VWV;
116 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
117 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
118 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
119 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
121 /* the bcc length is only 16 bits, but some packets
122 (such as SMBwriteX) can be much larger than 64k. We
123 detect this by looking for a large non-chained NBT
124 packet (at least 64k bigger than what is
125 specified). If it is detected then the NBT size is
126 used instead of the bcc size */
127 if (req->in.data_size + 0x10000 <=
128 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
129 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
130 /* its an oversized packet! fun for all the family */
131 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
135 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
136 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
137 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
141 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
142 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
143 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
147 req->flags = CVAL(req->in.hdr, HDR_FLG);
148 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
149 req->smbpid = SVAL(req->in.hdr, HDR_PID);
151 if (!req_signing_check_incoming(req)) {
152 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
156 command = CVAL(req->in.hdr, HDR_COM);
157 switch_message(command, req);
162 These flags determine some of the permissions required to do an operation
164 #define AS_USER (1<<0)
165 #define SIGNING_NO_REPLY (1<<1)
168 define a list of possible SMB messages and their corresponding
169 functions. Any message that has a NULL function is unimplemented -
170 please feel free to contribute implementations!
172 static const struct smb_message_struct
175 void (*fn)(struct smbsrv_request *);
178 smb_messages[256] = {
179 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER},
180 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER},
181 /* 0x02 */ { "SMBopen",reply_open,AS_USER},
182 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
183 /* 0x04 */ { "SMBclose",reply_close,AS_USER},
184 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
185 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER},
186 /* 0x07 */ { "SMBmv",reply_mv,AS_USER},
187 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
188 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER},
189 /* 0x0a */ { "SMBread",reply_read,AS_USER},
190 /* 0x0b */ { "SMBwrite",reply_write,AS_USER},
191 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
192 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
193 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
194 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
195 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
196 /* 0x11 */ { "SMBexit",reply_exit,0},
197 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
198 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
199 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
200 /* 0x15 */ { NULL, NULL, 0 },
201 /* 0x16 */ { NULL, NULL, 0 },
202 /* 0x17 */ { NULL, NULL, 0 },
203 /* 0x18 */ { NULL, NULL, 0 },
204 /* 0x19 */ { NULL, NULL, 0 },
205 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
206 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
207 /* 0x1c */ { "SMBreadBs",NULL,0 },
208 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
209 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
210 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
211 /* 0x20 */ { "SMBwritec",NULL,0},
212 /* 0x21 */ { NULL, NULL, 0 },
213 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER},
214 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER},
215 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER},
216 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER},
217 /* 0x26 */ { "SMBtranss",reply_transs,AS_USER},
218 /* 0x27 */ { "SMBioctl",reply_ioctl,AS_USER},
219 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
220 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER},
221 /* 0x2a */ { "SMBmove",NULL,AS_USER},
222 /* 0x2b */ { "SMBecho",reply_echo,0},
223 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
224 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER},
225 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER},
226 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER},
227 /* 0x30 */ { NULL, NULL, 0 },
228 /* 0x31 */ { NULL, NULL, 0 },
229 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER},
230 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
231 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
232 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
233 /* 0x36 */ { NULL, NULL, 0 },
234 /* 0x37 */ { NULL, NULL, 0 },
235 /* 0x38 */ { NULL, NULL, 0 },
236 /* 0x39 */ { NULL, NULL, 0 },
237 /* 0x3a */ { NULL, NULL, 0 },
238 /* 0x3b */ { NULL, NULL, 0 },
239 /* 0x3c */ { NULL, NULL, 0 },
240 /* 0x3d */ { NULL, NULL, 0 },
241 /* 0x3e */ { NULL, NULL, 0 },
242 /* 0x3f */ { NULL, NULL, 0 },
243 /* 0x40 */ { NULL, NULL, 0 },
244 /* 0x41 */ { NULL, NULL, 0 },
245 /* 0x42 */ { NULL, NULL, 0 },
246 /* 0x43 */ { NULL, NULL, 0 },
247 /* 0x44 */ { NULL, NULL, 0 },
248 /* 0x45 */ { NULL, NULL, 0 },
249 /* 0x46 */ { NULL, NULL, 0 },
250 /* 0x47 */ { NULL, NULL, 0 },
251 /* 0x48 */ { NULL, NULL, 0 },
252 /* 0x49 */ { NULL, NULL, 0 },
253 /* 0x4a */ { NULL, NULL, 0 },
254 /* 0x4b */ { NULL, NULL, 0 },
255 /* 0x4c */ { NULL, NULL, 0 },
256 /* 0x4d */ { NULL, NULL, 0 },
257 /* 0x4e */ { NULL, NULL, 0 },
258 /* 0x4f */ { NULL, NULL, 0 },
259 /* 0x50 */ { NULL, NULL, 0 },
260 /* 0x51 */ { NULL, NULL, 0 },
261 /* 0x52 */ { NULL, NULL, 0 },
262 /* 0x53 */ { NULL, NULL, 0 },
263 /* 0x54 */ { NULL, NULL, 0 },
264 /* 0x55 */ { NULL, NULL, 0 },
265 /* 0x56 */ { NULL, NULL, 0 },
266 /* 0x57 */ { NULL, NULL, 0 },
267 /* 0x58 */ { NULL, NULL, 0 },
268 /* 0x59 */ { NULL, NULL, 0 },
269 /* 0x5a */ { NULL, NULL, 0 },
270 /* 0x5b */ { NULL, NULL, 0 },
271 /* 0x5c */ { NULL, NULL, 0 },
272 /* 0x5d */ { NULL, NULL, 0 },
273 /* 0x5e */ { NULL, NULL, 0 },
274 /* 0x5f */ { NULL, NULL, 0 },
275 /* 0x60 */ { NULL, NULL, 0 },
276 /* 0x61 */ { NULL, NULL, 0 },
277 /* 0x62 */ { NULL, NULL, 0 },
278 /* 0x63 */ { NULL, NULL, 0 },
279 /* 0x64 */ { NULL, NULL, 0 },
280 /* 0x65 */ { NULL, NULL, 0 },
281 /* 0x66 */ { NULL, NULL, 0 },
282 /* 0x67 */ { NULL, NULL, 0 },
283 /* 0x68 */ { NULL, NULL, 0 },
284 /* 0x69 */ { NULL, NULL, 0 },
285 /* 0x6a */ { NULL, NULL, 0 },
286 /* 0x6b */ { NULL, NULL, 0 },
287 /* 0x6c */ { NULL, NULL, 0 },
288 /* 0x6d */ { NULL, NULL, 0 },
289 /* 0x6e */ { NULL, NULL, 0 },
290 /* 0x6f */ { NULL, NULL, 0 },
291 /* 0x70 */ { "SMBtcon",reply_tcon,0},
292 /* 0x71 */ { "SMBtdis",reply_tdis,0},
293 /* 0x72 */ { "SMBnegprot",reply_negprot,0},
294 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,0},
295 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
296 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
297 /* 0x76 */ { NULL, NULL, 0 },
298 /* 0x77 */ { NULL, NULL, 0 },
299 /* 0x78 */ { NULL, NULL, 0 },
300 /* 0x79 */ { NULL, NULL, 0 },
301 /* 0x7a */ { NULL, NULL, 0 },
302 /* 0x7b */ { NULL, NULL, 0 },
303 /* 0x7c */ { NULL, NULL, 0 },
304 /* 0x7d */ { NULL, NULL, 0 },
305 /* 0x7e */ { NULL, NULL, 0 },
306 /* 0x7f */ { NULL, NULL, 0 },
307 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
308 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
309 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
310 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
311 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
312 /* 0x85 */ { NULL, NULL, 0 },
313 /* 0x86 */ { NULL, NULL, 0 },
314 /* 0x87 */ { NULL, NULL, 0 },
315 /* 0x88 */ { NULL, NULL, 0 },
316 /* 0x89 */ { NULL, NULL, 0 },
317 /* 0x8a */ { NULL, NULL, 0 },
318 /* 0x8b */ { NULL, NULL, 0 },
319 /* 0x8c */ { NULL, NULL, 0 },
320 /* 0x8d */ { NULL, NULL, 0 },
321 /* 0x8e */ { NULL, NULL, 0 },
322 /* 0x8f */ { NULL, NULL, 0 },
323 /* 0x90 */ { NULL, NULL, 0 },
324 /* 0x91 */ { NULL, NULL, 0 },
325 /* 0x92 */ { NULL, NULL, 0 },
326 /* 0x93 */ { NULL, NULL, 0 },
327 /* 0x94 */ { NULL, NULL, 0 },
328 /* 0x95 */ { NULL, NULL, 0 },
329 /* 0x96 */ { NULL, NULL, 0 },
330 /* 0x97 */ { NULL, NULL, 0 },
331 /* 0x98 */ { NULL, NULL, 0 },
332 /* 0x99 */ { NULL, NULL, 0 },
333 /* 0x9a */ { NULL, NULL, 0 },
334 /* 0x9b */ { NULL, NULL, 0 },
335 /* 0x9c */ { NULL, NULL, 0 },
336 /* 0x9d */ { NULL, NULL, 0 },
337 /* 0x9e */ { NULL, NULL, 0 },
338 /* 0x9f */ { NULL, NULL, 0 },
339 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER},
340 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER},
341 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER},
342 /* 0xa3 */ { NULL, NULL, 0 },
343 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, AS_USER|SIGNING_NO_REPLY},
344 /* 0xa5 */ { "SMBntrename", reply_ntrename, AS_USER},
345 /* 0xa6 */ { NULL, NULL, 0 },
346 /* 0xa7 */ { NULL, NULL, 0 },
347 /* 0xa8 */ { NULL, NULL, 0 },
348 /* 0xa9 */ { NULL, NULL, 0 },
349 /* 0xaa */ { NULL, NULL, 0 },
350 /* 0xab */ { NULL, NULL, 0 },
351 /* 0xac */ { NULL, NULL, 0 },
352 /* 0xad */ { NULL, NULL, 0 },
353 /* 0xae */ { NULL, NULL, 0 },
354 /* 0xaf */ { NULL, NULL, 0 },
355 /* 0xb0 */ { NULL, NULL, 0 },
356 /* 0xb1 */ { NULL, NULL, 0 },
357 /* 0xb2 */ { NULL, NULL, 0 },
358 /* 0xb3 */ { NULL, NULL, 0 },
359 /* 0xb4 */ { NULL, NULL, 0 },
360 /* 0xb5 */ { NULL, NULL, 0 },
361 /* 0xb6 */ { NULL, NULL, 0 },
362 /* 0xb7 */ { NULL, NULL, 0 },
363 /* 0xb8 */ { NULL, NULL, 0 },
364 /* 0xb9 */ { NULL, NULL, 0 },
365 /* 0xba */ { NULL, NULL, 0 },
366 /* 0xbb */ { NULL, NULL, 0 },
367 /* 0xbc */ { NULL, NULL, 0 },
368 /* 0xbd */ { NULL, NULL, 0 },
369 /* 0xbe */ { NULL, NULL, 0 },
370 /* 0xbf */ { NULL, NULL, 0 },
371 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
372 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
373 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
374 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
375 /* 0xc4 */ { NULL, NULL, 0 },
376 /* 0xc5 */ { NULL, NULL, 0 },
377 /* 0xc6 */ { NULL, NULL, 0 },
378 /* 0xc7 */ { NULL, NULL, 0 },
379 /* 0xc8 */ { NULL, NULL, 0 },
380 /* 0xc9 */ { NULL, NULL, 0 },
381 /* 0xca */ { NULL, NULL, 0 },
382 /* 0xcb */ { NULL, NULL, 0 },
383 /* 0xcc */ { NULL, NULL, 0 },
384 /* 0xcd */ { NULL, NULL, 0 },
385 /* 0xce */ { NULL, NULL, 0 },
386 /* 0xcf */ { NULL, NULL, 0 },
387 /* 0xd0 */ { "SMBsends",reply_sends,0},
388 /* 0xd1 */ { "SMBsendb",NULL,0},
389 /* 0xd2 */ { "SMBfwdname",NULL,0},
390 /* 0xd3 */ { "SMBcancelf",NULL,0},
391 /* 0xd4 */ { "SMBgetmac",NULL,0},
392 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,0},
393 /* 0xd6 */ { "SMBsendend",reply_sendend,0},
394 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,0},
395 /* 0xd8 */ { NULL, NULL, 0 },
396 /* 0xd9 */ { NULL, NULL, 0 },
397 /* 0xda */ { NULL, NULL, 0 },
398 /* 0xdb */ { NULL, NULL, 0 },
399 /* 0xdc */ { NULL, NULL, 0 },
400 /* 0xdd */ { NULL, NULL, 0 },
401 /* 0xde */ { NULL, NULL, 0 },
402 /* 0xdf */ { NULL, NULL, 0 },
403 /* 0xe0 */ { NULL, NULL, 0 },
404 /* 0xe1 */ { NULL, NULL, 0 },
405 /* 0xe2 */ { NULL, NULL, 0 },
406 /* 0xe3 */ { NULL, NULL, 0 },
407 /* 0xe4 */ { NULL, NULL, 0 },
408 /* 0xe5 */ { NULL, NULL, 0 },
409 /* 0xe6 */ { NULL, NULL, 0 },
410 /* 0xe7 */ { NULL, NULL, 0 },
411 /* 0xe8 */ { NULL, NULL, 0 },
412 /* 0xe9 */ { NULL, NULL, 0 },
413 /* 0xea */ { NULL, NULL, 0 },
414 /* 0xeb */ { NULL, NULL, 0 },
415 /* 0xec */ { NULL, NULL, 0 },
416 /* 0xed */ { NULL, NULL, 0 },
417 /* 0xee */ { NULL, NULL, 0 },
418 /* 0xef */ { NULL, NULL, 0 },
419 /* 0xf0 */ { NULL, NULL, 0 },
420 /* 0xf1 */ { NULL, NULL, 0 },
421 /* 0xf2 */ { NULL, NULL, 0 },
422 /* 0xf3 */ { NULL, NULL, 0 },
423 /* 0xf4 */ { NULL, NULL, 0 },
424 /* 0xf5 */ { NULL, NULL, 0 },
425 /* 0xf6 */ { NULL, NULL, 0 },
426 /* 0xf7 */ { NULL, NULL, 0 },
427 /* 0xf8 */ { NULL, NULL, 0 },
428 /* 0xf9 */ { NULL, NULL, 0 },
429 /* 0xfa */ { NULL, NULL, 0 },
430 /* 0xfb */ { NULL, NULL, 0 },
431 /* 0xfc */ { NULL, NULL, 0 },
432 /* 0xfd */ { NULL, NULL, 0 },
433 /* 0xfe */ { NULL, NULL, 0 },
434 /* 0xff */ { NULL, NULL, 0 }
437 /****************************************************************************
438 return a string containing the function name of a SMB command
439 ****************************************************************************/
440 static const char *smb_fn_name(uint8_t type)
442 const char *unknown_name = "SMBunknown";
444 if (smb_messages[type].name == NULL)
447 return smb_messages[type].name;
451 /****************************************************************************
452 Do a switch on the message type and call the specific reply function for this
453 message. Unlike earlier versions of Samba the reply functions are responsible
454 for sending the reply themselves, rather than returning a size to this function
455 The reply functions may also choose to delay the processing by pushing the message
456 onto the message queue
457 ****************************************************************************/
458 static void switch_message(int type, struct smbsrv_request *req)
461 struct smbsrv_connection *smb_conn = req->smb_conn;
462 uint16_t session_tag;
469 if (smb_messages[type].fn == NULL) {
470 DEBUG(0,("Unknown message type %d!\n",type));
475 flags = smb_messages[type].flags;
477 req->tcon = smbsrv_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
479 if (req->session == NULL) {
480 /* setup the user context for this request if it
481 hasn't already been initialised (to cope with SMB
484 /* In share mode security we must ignore the vuid. */
485 if (smb_conn->config.security == SEC_SHARE) {
486 session_tag = UID_FIELD_INVALID;
488 session_tag = SVAL(req->in.hdr,HDR_UID);
491 req->session = smbsrv_session_find(req->smb_conn, session_tag);
493 req->session->vuid = session_tag;
496 session_tag = req->session->vuid;
499 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id));
501 /* this must be called before we do any reply */
502 if (flags & SIGNING_NO_REPLY) {
503 req_signing_no_reply(req);
506 /* see if the vuid is valid */
507 if ((flags & AS_USER) && (!req->session || !req->session->finished_sesssetup)) {
508 /* amazingly, the error code depends on the command */
512 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
515 status = NT_STATUS_INVALID_HANDLE;
520 * don't know how to handle smb signing for this case
521 * so just skip the reply
523 if ((flags & SIGNING_NO_REPLY) &&
524 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
525 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
526 smb_fn_name(type), nt_errstr(status)));
530 req_reply_error(req, status);
534 /* does this protocol need a valid tree connection? */
535 if ((flags & AS_USER) && !req->tcon) {
536 /* amazingly, the error code depends on the command */
540 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
543 status = NT_STATUS_INVALID_HANDLE;
548 * don't know how to handle smb signing for this case
549 * so just skip the reply
551 if ((flags & SIGNING_NO_REPLY) &&
552 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
553 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
554 smb_fn_name(type), nt_errstr(status)));
558 req_reply_error(req, status);
562 smb_messages[type].fn(req);
566 we call this when first first part of a possibly chained request has been completed
567 and we need to call the 2nd part, if any
569 void chain_reply(struct smbsrv_request *req)
571 uint16_t chain_cmd, chain_offset;
576 if (req->in.wct < 2 || req->out.wct < 2) {
577 req_reply_dos_error(req, ERRSRV, ERRerror);
581 chain_cmd = CVAL(req->in.vwv, VWV(0));
582 chain_offset = SVAL(req->in.vwv, VWV(1));
584 if (chain_cmd == SMB_CHAIN_NONE) {
586 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
587 SSVAL(req->out.vwv, VWV(1), 0);
592 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
596 wct = CVAL(req->in.hdr, chain_offset);
597 vwv = req->in.hdr + chain_offset + 1;
599 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
603 data_size = SVAL(vwv, VWV(wct));
604 data = vwv + VWV(wct) + 2;
606 if (data + data_size > req->in.buffer + req->in.size) {
610 /* all seems legit */
614 req->in.data_size = data_size;
619 SSVAL(req->out.vwv, VWV(0), chain_cmd);
620 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
622 /* the current request in the chain might have used an async reply,
623 but that doesn't mean the next element needs to */
624 ZERO_STRUCTP(req->async_states);
626 switch_message(chain_cmd, req);
630 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
631 SSVAL(req->out.vwv, VWV(1), 0);
632 req_reply_dos_error(req, ERRSRV, ERRerror);
637 close the socket and shutdown a server_context
639 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
641 smb_conn->terminate = reason;
645 called when a SMB socket becomes readable
647 static void smbsrv_recv(struct stream_connection *conn, uint16_t flags)
649 struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
651 DEBUG(10,("smbsrv_recv\n"));
653 packet_recv(smb_conn->packet);
654 if (smb_conn->terminate) {
655 talloc_free(conn->event.fde);
656 conn->event.fde = NULL;
657 stream_terminate_connection(smb_conn->connection, smb_conn->terminate);
661 /* free up temporary memory */
666 called when a SMB socket becomes writable
668 static void smbsrv_send(struct stream_connection *conn, uint16_t flags)
670 struct smbsrv_connection *smb_conn = talloc_get_type(conn->private,
671 struct smbsrv_connection);
672 packet_queue_run(smb_conn->packet);
677 handle socket recv errors
679 static void smbsrv_recv_error(void *private, NTSTATUS status)
681 struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
683 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
687 initialise a server_context from a open socket and register a event handler
688 for reading from that socket
690 static void smbsrv_accept(struct stream_connection *conn)
692 struct smbsrv_connection *smb_conn;
694 DEBUG(5,("smbsrv_accept\n"));
696 smb_conn = talloc_zero(conn, struct smbsrv_connection);
697 if (!smb_conn) return;
699 /* now initialise a few default values associated with this smb socket */
700 smb_conn->negotiate.max_send = 0xFFFF;
702 /* this is the size that w2k uses, and it appears to be important for
704 smb_conn->negotiate.max_recv = lp_max_xmit();
706 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
708 smb_conn->negotiate.called_name = NULL;
709 smb_conn->negotiate.calling_name = NULL;
711 smb_conn->packet = packet_init(smb_conn);
712 if (smb_conn->packet == NULL) {
713 stream_terminate_connection(conn, "out of memory");
716 packet_set_private(smb_conn->packet, smb_conn);
717 packet_set_socket(smb_conn->packet, conn->socket);
718 packet_set_callback(smb_conn->packet, receive_smb_request);
719 packet_set_full_request(smb_conn->packet, packet_full_request_nbt);
720 packet_set_error_handler(smb_conn->packet, smbsrv_recv_error);
721 packet_set_event_context(smb_conn->packet, conn->event.ctx);
722 packet_set_fde(smb_conn->packet, conn->event.fde);
723 packet_set_serialise(smb_conn->packet);
725 smbsrv_vuid_init(smb_conn);
727 srv_init_signing(smb_conn);
729 smbsrv_tcon_init(smb_conn);
731 smb_conn->connection = conn;
732 smb_conn->config.security = lp_security();
733 smb_conn->config.nt_status_support = lp_nt_status_support();
735 conn->private = smb_conn;
737 irpc_add_name(conn->msg_ctx, "smb_server");
739 smbsrv_management_init(smb_conn);
743 static const struct stream_server_ops smb_stream_ops = {
745 .accept_connection = smbsrv_accept,
746 .recv_handler = smbsrv_recv,
747 .send_handler = smbsrv_send,
751 setup a listening socket on all the SMB ports for a particular address
753 static NTSTATUS smb_add_socket(struct event_context *event_context,
754 const struct model_ops *model_ops,
757 const char **ports = lp_smb_ports();
761 for (i=0;ports[i];i++) {
762 uint16_t port = atoi(ports[i]);
763 if (port == 0) continue;
764 status = stream_setup_socket(event_context, model_ops, &smb_stream_ops,
765 "ipv4", address, &port, NULL);
766 NT_STATUS_NOT_OK_RETURN(status);
773 called on startup of the smb server service It's job is to start
774 listening on all configured SMB server sockets
776 static NTSTATUS smbsrv_init(struct event_context *event_context, const struct model_ops *model_ops)
780 if (lp_interfaces() && lp_bind_interfaces_only()) {
781 int num_interfaces = iface_count();
784 /* We have been given an interfaces line, and been
785 told to only bind to those interfaces. Create a
786 socket per interface and bind to only these.
788 for(i = 0; i < num_interfaces; i++) {
789 const char *address = iface_n_ip(i);
790 status = smb_add_socket(event_context, model_ops, address);
791 NT_STATUS_NOT_OK_RETURN(status);
794 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
795 status = smb_add_socket(event_context, model_ops, lp_socket_address());
796 NT_STATUS_NOT_OK_RETURN(status);
802 /* called at smbd startup - register ourselves as a server service */
803 NTSTATUS server_service_smb_init(void)
805 return register_server_service("smb", smbsrv_init);