2 Unix SMB/CIFS implementation.
3 process incoming packets - main loop
4 Copyright (C) Andrew Tridgell 1992-2005
5 Copyright (C) James J Myers 2003 <myersjj@samba.org>
6 Copyright (C) Stefan Metzmacher 2004-2005
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 "system/time.h"
25 #include "smbd/service_stream.h"
26 #include "smb_server/smb_server.h"
27 #include "ntvfs/ntvfs.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 = smbsrv_init_request(tcon->smb_conn);
42 smbsrv_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);
61 smbsrv_send_reply(req);
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 NTSTATUS smbsrv_recv_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 = smbsrv_init_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();
88 smbsrv_reply_special(req);
92 if ((NBT_HDR_SIZE + MIN_SMB_SIZE) > blob.length) {
93 DEBUG(2,("Invalid SMB packet: length %ld\n", (long)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 %ld. Terminating connection\n",
102 smbsrv_terminate_connection(smb_conn, "Non-SMB packet");
106 req = smbsrv_init_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 (!smbsrv_signing_check_incoming(req)) {
152 smbsrv_send_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", smbsrv_reply_mkdir, AS_USER },
180 /* 0x01 */ { "SMBrmdir", smbsrv_reply_rmdir, AS_USER },
181 /* 0x02 */ { "SMBopen", smbsrv_reply_open, AS_USER },
182 /* 0x03 */ { "SMBcreate", smbsrv_reply_mknew, AS_USER },
183 /* 0x04 */ { "SMBclose", smbsrv_reply_close, AS_USER },
184 /* 0x05 */ { "SMBflush", smbsrv_reply_flush, AS_USER },
185 /* 0x06 */ { "SMBunlink", smbsrv_reply_unlink, AS_USER },
186 /* 0x07 */ { "SMBmv", smbsrv_reply_mv, AS_USER },
187 /* 0x08 */ { "SMBgetatr", smbsrv_reply_getatr, AS_USER },
188 /* 0x09 */ { "SMBsetatr", smbsrv_reply_setatr, AS_USER },
189 /* 0x0a */ { "SMBread", smbsrv_reply_read, AS_USER },
190 /* 0x0b */ { "SMBwrite", smbsrv_reply_write, AS_USER },
191 /* 0x0c */ { "SMBlock", smbsrv_reply_lock, AS_USER },
192 /* 0x0d */ { "SMBunlock", smbsrv_reply_unlock, AS_USER },
193 /* 0x0e */ { "SMBctemp", smbsrv_reply_ctemp, AS_USER },
194 /* 0x0f */ { "SMBmknew", smbsrv_reply_mknew, AS_USER },
195 /* 0x10 */ { "SMBchkpth", smbsrv_reply_chkpth, AS_USER },
196 /* 0x11 */ { "SMBexit", smbsrv_reply_exit, 0 },
197 /* 0x12 */ { "SMBlseek", smbsrv_reply_lseek, AS_USER },
198 /* 0x13 */ { "SMBlockread", smbsrv_reply_lockread, AS_USER },
199 /* 0x14 */ { "SMBwriteunlock", smbsrv_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", smbsrv_reply_readbraw, AS_USER },
206 /* 0x1b */ { "SMBreadBmpx", smbsrv_reply_readbmpx, AS_USER },
207 /* 0x1c */ { "SMBreadBs", NULL, 0 },
208 /* 0x1d */ { "SMBwritebraw", smbsrv_reply_writebraw, AS_USER },
209 /* 0x1e */ { "SMBwriteBmpx", smbsrv_reply_writebmpx, AS_USER },
210 /* 0x1f */ { "SMBwriteBs", smbsrv_reply_writebs, AS_USER },
211 /* 0x20 */ { "SMBwritec", NULL, 0 },
212 /* 0x21 */ { NULL, NULL, 0 },
213 /* 0x22 */ { "SMBsetattrE", smbsrv_reply_setattrE, AS_USER },
214 /* 0x23 */ { "SMBgetattrE", smbsrv_reply_getattrE, AS_USER },
215 /* 0x24 */ { "SMBlockingX", smbsrv_reply_lockingX, AS_USER },
216 /* 0x25 */ { "SMBtrans", smbsrv_reply_trans, AS_USER },
217 /* 0x26 */ { "SMBtranss", smbsrv_reply_transs, AS_USER },
218 /* 0x27 */ { "SMBioctl", smbsrv_reply_ioctl, AS_USER },
219 /* 0x28 */ { "SMBioctls", NULL, AS_USER },
220 /* 0x29 */ { "SMBcopy", smbsrv_reply_copy, AS_USER },
221 /* 0x2a */ { "SMBmove", NULL, AS_USER },
222 /* 0x2b */ { "SMBecho", smbsrv_reply_echo, 0 },
223 /* 0x2c */ { "SMBwriteclose", smbsrv_reply_writeclose,AS_USER },
224 /* 0x2d */ { "SMBopenX", smbsrv_reply_open_and_X,AS_USER },
225 /* 0x2e */ { "SMBreadX", smbsrv_reply_read_and_X,AS_USER },
226 /* 0x2f */ { "SMBwriteX", smbsrv_reply_write_and_X,AS_USER},
227 /* 0x30 */ { NULL, NULL, 0 },
228 /* 0x31 */ { NULL, NULL, 0 },
229 /* 0x32 */ { "SMBtrans2", smbsrv_reply_trans2, AS_USER },
230 /* 0x33 */ { "SMBtranss2", smbsrv_reply_transs2, AS_USER },
231 /* 0x34 */ { "SMBfindclose", smbsrv_reply_findclose, AS_USER },
232 /* 0x35 */ { "SMBfindnclose", smbsrv_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", smbsrv_reply_tcon, 0 },
292 /* 0x71 */ { "SMBtdis", smbsrv_reply_tdis, 0 },
293 /* 0x72 */ { "SMBnegprot", smbsrv_reply_negprot, 0 },
294 /* 0x73 */ { "SMBsesssetupX", smbsrv_reply_sesssetup, 0 },
295 /* 0x74 */ { "SMBulogoffX", smbsrv_reply_ulogoffX, 0 }, /* ulogoff doesn't give a valid TID */
296 /* 0x75 */ { "SMBtconX", smbsrv_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", smbsrv_reply_dskattr, AS_USER },
308 /* 0x81 */ { "SMBsearch", smbsrv_reply_search, AS_USER },
309 /* 0x82 */ { "SMBffirst", smbsrv_reply_search, AS_USER },
310 /* 0x83 */ { "SMBfunique", smbsrv_reply_search, AS_USER },
311 /* 0x84 */ { "SMBfclose", smbsrv_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", smbsrv_reply_nttrans, AS_USER },
340 /* 0xa1 */ { "SMBnttranss", smbsrv_reply_nttranss, AS_USER},
341 /* 0xa2 */ { "SMBntcreateX", smbsrv_reply_ntcreate_and_X, AS_USER },
342 /* 0xa3 */ { NULL, NULL, 0 },
343 /* 0xa4 */ { "SMBntcancel", smbsrv_reply_ntcancel, AS_USER | SIGNING_NO_REPLY },
344 /* 0xa5 */ { "SMBntrename", smbsrv_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", smbsrv_reply_printopen, AS_USER },
372 /* 0xc1 */ { "SMBsplwr", smbsrv_reply_printwrite, AS_USER },
373 /* 0xc2 */ { "SMBsplclose", smbsrv_reply_printclose, AS_USER },
374 /* 0xc3 */ { "SMBsplretq", smbsrv_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", smbsrv_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", smbsrv_reply_sendstrt, 0 },
393 /* 0xd6 */ { "SMBsendend", smbsrv_reply_sendend, 0 },
394 /* 0xd7 */ { "SMBsendtxt", smbsrv_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;
468 if (smb_messages[type].fn == NULL) {
469 DEBUG(0,("Unknown message type %d!\n",type));
470 smbsrv_reply_unknown(req);
474 flags = smb_messages[type].flags;
476 req->tcon = smbsrv_smb_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
479 /* setup the user context for this request if it
480 hasn't already been initialised (to cope with SMB
483 /* In share mode security we must ignore the vuid. */
484 if (smb_conn->config.security == SEC_SHARE) {
486 req->session = req->tcon->sec_share.session;
489 req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID));
493 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id));
495 /* this must be called before we do any reply */
496 if (flags & SIGNING_NO_REPLY) {
497 smbsrv_signing_no_reply(req);
500 /* see if the vuid is valid */
501 if ((flags & AS_USER) && !req->session) {
502 /* amazingly, the error code depends on the command */
506 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
509 status = NT_STATUS_INVALID_HANDLE;
514 * don't know how to handle smb signing for this case
515 * so just skip the reply
517 if ((flags & SIGNING_NO_REPLY) &&
518 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
519 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
520 smb_fn_name(type), nt_errstr(status)));
524 smbsrv_send_error(req, status);
528 /* does this protocol need a valid tree connection? */
529 if ((flags & AS_USER) && !req->tcon) {
530 /* amazingly, the error code depends on the command */
534 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
537 status = NT_STATUS_INVALID_HANDLE;
542 * don't know how to handle smb signing for this case
543 * so just skip the reply
545 if ((flags & SIGNING_NO_REPLY) &&
546 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
547 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
548 smb_fn_name(type), nt_errstr(status)));
552 smbsrv_send_error(req, status);
556 smb_messages[type].fn(req);
560 we call this when first first part of a possibly chained request has been completed
561 and we need to call the 2nd part, if any
563 void smbsrv_chain_reply(struct smbsrv_request *req)
565 uint16_t chain_cmd, chain_offset;
570 if (req->in.wct < 2 || req->out.wct < 2) {
571 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
575 chain_cmd = CVAL(req->in.vwv, VWV(0));
576 chain_offset = SVAL(req->in.vwv, VWV(1));
578 if (chain_cmd == SMB_CHAIN_NONE) {
580 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
581 SSVAL(req->out.vwv, VWV(1), 0);
582 smbsrv_send_reply(req);
586 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
590 wct = CVAL(req->in.hdr, chain_offset);
591 vwv = req->in.hdr + chain_offset + 1;
593 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
597 data_size = SVAL(vwv, VWV(wct));
598 data = vwv + VWV(wct) + 2;
600 if (data + data_size > req->in.buffer + req->in.size) {
604 /* all seems legit */
608 req->in.data_size = data_size;
613 SSVAL(req->out.vwv, VWV(0), chain_cmd);
614 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
616 /* the current request in the chain might have used an async reply,
617 but that doesn't mean the next element needs to */
618 ZERO_STRUCTP(req->async_states);
620 switch_message(chain_cmd, req);
624 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
625 SSVAL(req->out.vwv, VWV(1), 0);
626 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
630 * init the SMB protocol related stuff
632 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn)
636 /* now initialise a few default values associated with this smb socket */
637 smb_conn->negotiate.max_send = 0xFFFF;
639 /* this is the size that w2k uses, and it appears to be important for
641 smb_conn->negotiate.max_recv = lp_max_xmit();
643 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
645 smb_conn->config.security = lp_security();
646 smb_conn->config.nt_status_support = lp_nt_status_support();
648 status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
649 NT_STATUS_NOT_OK_RETURN(status);
651 status = smbsrv_smb_init_tcons(smb_conn);
652 NT_STATUS_NOT_OK_RETURN(status);
654 smbsrv_init_signing(smb_conn);