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 NTSTATUS smbsrv_send_oplock_break(void *p, uint16_t fnum, uint8_t level)
35 struct smbsrv_tcon *tcon = talloc_get_type(p, struct smbsrv_tcon);
36 struct smbsrv_request *req;
38 req = smbsrv_init_request(tcon->smb_conn);
39 NT_STATUS_HAVE_NO_MEMORY(req);
41 smbsrv_setup_reply(req, 8, 0);
43 SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
44 SSVAL(req->out.hdr,HDR_TID,tcon->tid);
45 SSVAL(req->out.hdr,HDR_PID,0xFFFF);
46 SSVAL(req->out.hdr,HDR_UID,0);
47 SSVAL(req->out.hdr,HDR_MID,0xFFFF);
48 SCVAL(req->out.hdr,HDR_FLG,0);
49 SSVAL(req->out.hdr,HDR_FLG2,0);
51 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
52 SSVAL(req->out.vwv, VWV(1), 0);
53 SSVAL(req->out.vwv, VWV(2), fnum);
54 SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
55 SCVAL(req->out.vwv, VWV(3)+1, level);
56 SIVAL(req->out.vwv, VWV(4), 0);
57 SSVAL(req->out.vwv, VWV(6), 0);
58 SSVAL(req->out.vwv, VWV(7), 0);
60 smbsrv_send_reply(req);
64 static void switch_message(int type, struct smbsrv_request *req);
66 /****************************************************************************
67 receive a SMB request header from the wire, forming a request_context
69 ****************************************************************************/
70 NTSTATUS smbsrv_recv_smb_request(void *private, DATA_BLOB blob)
72 struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
73 struct smbsrv_request *req;
74 struct timeval cur_time = timeval_current();
77 smb_conn->statistics.last_request_time = cur_time;
79 /* see if its a special NBT packet */
80 if (CVAL(blob.data, 0) != 0) {
81 req = smbsrv_init_request(smb_conn);
82 NT_STATUS_HAVE_NO_MEMORY(req);
86 req->in.buffer = talloc_steal(req, blob.data);
87 req->in.size = blob.length;
88 req->request_time = cur_time;
90 smbsrv_reply_special(req);
94 if ((NBT_HDR_SIZE + MIN_SMB_SIZE) > blob.length) {
95 DEBUG(2,("Invalid SMB packet: length %ld\n", (long)blob.length));
96 smbsrv_terminate_connection(smb_conn, "Invalid SMB packet");
100 /* Make sure this is an SMB packet */
101 if (IVAL(blob.data, NBT_HDR_SIZE) != SMB_MAGIC) {
102 DEBUG(2,("Non-SMB packet of length %ld. Terminating connection\n",
104 smbsrv_terminate_connection(smb_conn, "Non-SMB packet");
108 req = smbsrv_init_request(smb_conn);
109 NT_STATUS_HAVE_NO_MEMORY(req);
111 req->in.buffer = talloc_steal(req, blob.data);
112 req->in.size = blob.length;
113 req->request_time = cur_time;
114 req->chained_fnum = -1;
115 req->in.allocated = req->in.size;
116 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
117 req->in.vwv = req->in.hdr + HDR_VWV;
118 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
119 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
120 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
121 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
123 /* the bcc length is only 16 bits, but some packets
124 (such as SMBwriteX) can be much larger than 64k. We
125 detect this by looking for a large non-chained NBT
126 packet (at least 64k bigger than what is
127 specified). If it is detected then the NBT size is
128 used instead of the bcc size */
129 if (req->in.data_size + 0x10000 <=
130 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
131 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
132 /* its an oversized packet! fun for all the family */
133 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
137 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
138 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
139 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
143 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
144 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
145 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
149 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
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 NEED_SESS (1<<0)
165 #define NEED_TCON (1<<1)
166 #define SIGNING_NO_REPLY (1<<2)
169 define a list of possible SMB messages and their corresponding
170 functions. Any message that has a NULL function is unimplemented -
171 please feel free to contribute implementations!
173 static const struct smb_message_struct
176 void (*fn)(struct smbsrv_request *);
179 smb_messages[256] = {
180 /* 0x00 */ { "SMBmkdir", smbsrv_reply_mkdir, NEED_SESS|NEED_TCON },
181 /* 0x01 */ { "SMBrmdir", smbsrv_reply_rmdir, NEED_SESS|NEED_TCON },
182 /* 0x02 */ { "SMBopen", smbsrv_reply_open, NEED_SESS|NEED_TCON },
183 /* 0x03 */ { "SMBcreate", smbsrv_reply_mknew, NEED_SESS|NEED_TCON },
184 /* 0x04 */ { "SMBclose", smbsrv_reply_close, NEED_SESS|NEED_TCON },
185 /* 0x05 */ { "SMBflush", smbsrv_reply_flush, NEED_SESS|NEED_TCON },
186 /* 0x06 */ { "SMBunlink", smbsrv_reply_unlink, NEED_SESS|NEED_TCON },
187 /* 0x07 */ { "SMBmv", smbsrv_reply_mv, NEED_SESS|NEED_TCON },
188 /* 0x08 */ { "SMBgetatr", smbsrv_reply_getatr, NEED_SESS|NEED_TCON },
189 /* 0x09 */ { "SMBsetatr", smbsrv_reply_setatr, NEED_SESS|NEED_TCON },
190 /* 0x0a */ { "SMBread", smbsrv_reply_read, NEED_SESS|NEED_TCON },
191 /* 0x0b */ { "SMBwrite", smbsrv_reply_write, NEED_SESS|NEED_TCON },
192 /* 0x0c */ { "SMBlock", smbsrv_reply_lock, NEED_SESS|NEED_TCON },
193 /* 0x0d */ { "SMBunlock", smbsrv_reply_unlock, NEED_SESS|NEED_TCON },
194 /* 0x0e */ { "SMBctemp", smbsrv_reply_ctemp, NEED_SESS|NEED_TCON },
195 /* 0x0f */ { "SMBmknew", smbsrv_reply_mknew, NEED_SESS|NEED_TCON },
196 /* 0x10 */ { "SMBchkpth", smbsrv_reply_chkpth, NEED_SESS|NEED_TCON },
197 /* 0x11 */ { "SMBexit", smbsrv_reply_exit, NEED_SESS },
198 /* 0x12 */ { "SMBlseek", smbsrv_reply_lseek, NEED_SESS|NEED_TCON },
199 /* 0x13 */ { "SMBlockread", smbsrv_reply_lockread, NEED_SESS|NEED_TCON },
200 /* 0x14 */ { "SMBwriteunlock", smbsrv_reply_writeunlock, NEED_SESS|NEED_TCON },
201 /* 0x15 */ { NULL, NULL, 0 },
202 /* 0x16 */ { NULL, NULL, 0 },
203 /* 0x17 */ { NULL, NULL, 0 },
204 /* 0x18 */ { NULL, NULL, 0 },
205 /* 0x19 */ { NULL, NULL, 0 },
206 /* 0x1a */ { "SMBreadbraw", smbsrv_reply_readbraw, NEED_SESS|NEED_TCON },
207 /* 0x1b */ { "SMBreadBmpx", smbsrv_reply_readbmpx, NEED_SESS|NEED_TCON },
208 /* 0x1c */ { "SMBreadBs", NULL, 0 },
209 /* 0x1d */ { "SMBwritebraw", smbsrv_reply_writebraw, NEED_SESS|NEED_TCON },
210 /* 0x1e */ { "SMBwriteBmpx", smbsrv_reply_writebmpx, NEED_SESS|NEED_TCON },
211 /* 0x1f */ { "SMBwriteBs", smbsrv_reply_writebs, NEED_SESS|NEED_TCON },
212 /* 0x20 */ { "SMBwritec", NULL, 0 },
213 /* 0x21 */ { NULL, NULL, 0 },
214 /* 0x22 */ { "SMBsetattrE", smbsrv_reply_setattrE, NEED_SESS|NEED_TCON },
215 /* 0x23 */ { "SMBgetattrE", smbsrv_reply_getattrE, NEED_SESS|NEED_TCON },
216 /* 0x24 */ { "SMBlockingX", smbsrv_reply_lockingX, NEED_SESS|NEED_TCON },
217 /* 0x25 */ { "SMBtrans", smbsrv_reply_trans, NEED_SESS|NEED_TCON },
218 /* 0x26 */ { "SMBtranss", smbsrv_reply_transs, NEED_SESS|NEED_TCON },
219 /* 0x27 */ { "SMBioctl", smbsrv_reply_ioctl, NEED_SESS|NEED_TCON },
220 /* 0x28 */ { "SMBioctls", NULL, NEED_SESS|NEED_TCON },
221 /* 0x29 */ { "SMBcopy", smbsrv_reply_copy, NEED_SESS|NEED_TCON },
222 /* 0x2a */ { "SMBmove", NULL, NEED_SESS|NEED_TCON },
223 /* 0x2b */ { "SMBecho", smbsrv_reply_echo, 0 },
224 /* 0x2c */ { "SMBwriteclose", smbsrv_reply_writeclose, NEED_SESS|NEED_TCON },
225 /* 0x2d */ { "SMBopenX", smbsrv_reply_open_and_X, NEED_SESS|NEED_TCON },
226 /* 0x2e */ { "SMBreadX", smbsrv_reply_read_and_X, NEED_SESS|NEED_TCON },
227 /* 0x2f */ { "SMBwriteX", smbsrv_reply_write_and_X, NEED_SESS|NEED_TCON},
228 /* 0x30 */ { NULL, NULL, 0 },
229 /* 0x31 */ { NULL, NULL, 0 },
230 /* 0x32 */ { "SMBtrans2", smbsrv_reply_trans2, NEED_SESS|NEED_TCON },
231 /* 0x33 */ { "SMBtranss2", smbsrv_reply_transs2, NEED_SESS|NEED_TCON },
232 /* 0x34 */ { "SMBfindclose", smbsrv_reply_findclose, NEED_SESS|NEED_TCON },
233 /* 0x35 */ { "SMBfindnclose", smbsrv_reply_findnclose, NEED_SESS|NEED_TCON },
234 /* 0x36 */ { NULL, NULL, 0 },
235 /* 0x37 */ { NULL, NULL, 0 },
236 /* 0x38 */ { NULL, NULL, 0 },
237 /* 0x39 */ { NULL, NULL, 0 },
238 /* 0x3a */ { NULL, NULL, 0 },
239 /* 0x3b */ { NULL, NULL, 0 },
240 /* 0x3c */ { NULL, NULL, 0 },
241 /* 0x3d */ { NULL, NULL, 0 },
242 /* 0x3e */ { NULL, NULL, 0 },
243 /* 0x3f */ { NULL, NULL, 0 },
244 /* 0x40 */ { NULL, NULL, 0 },
245 /* 0x41 */ { NULL, NULL, 0 },
246 /* 0x42 */ { NULL, NULL, 0 },
247 /* 0x43 */ { NULL, NULL, 0 },
248 /* 0x44 */ { NULL, NULL, 0 },
249 /* 0x45 */ { NULL, NULL, 0 },
250 /* 0x46 */ { NULL, NULL, 0 },
251 /* 0x47 */ { NULL, NULL, 0 },
252 /* 0x48 */ { NULL, NULL, 0 },
253 /* 0x49 */ { NULL, NULL, 0 },
254 /* 0x4a */ { NULL, NULL, 0 },
255 /* 0x4b */ { NULL, NULL, 0 },
256 /* 0x4c */ { NULL, NULL, 0 },
257 /* 0x4d */ { NULL, NULL, 0 },
258 /* 0x4e */ { NULL, NULL, 0 },
259 /* 0x4f */ { NULL, NULL, 0 },
260 /* 0x50 */ { NULL, NULL, 0 },
261 /* 0x51 */ { NULL, NULL, 0 },
262 /* 0x52 */ { NULL, NULL, 0 },
263 /* 0x53 */ { NULL, NULL, 0 },
264 /* 0x54 */ { NULL, NULL, 0 },
265 /* 0x55 */ { NULL, NULL, 0 },
266 /* 0x56 */ { NULL, NULL, 0 },
267 /* 0x57 */ { NULL, NULL, 0 },
268 /* 0x58 */ { NULL, NULL, 0 },
269 /* 0x59 */ { NULL, NULL, 0 },
270 /* 0x5a */ { NULL, NULL, 0 },
271 /* 0x5b */ { NULL, NULL, 0 },
272 /* 0x5c */ { NULL, NULL, 0 },
273 /* 0x5d */ { NULL, NULL, 0 },
274 /* 0x5e */ { NULL, NULL, 0 },
275 /* 0x5f */ { NULL, NULL, 0 },
276 /* 0x60 */ { NULL, NULL, 0 },
277 /* 0x61 */ { NULL, NULL, 0 },
278 /* 0x62 */ { NULL, NULL, 0 },
279 /* 0x63 */ { NULL, NULL, 0 },
280 /* 0x64 */ { NULL, NULL, 0 },
281 /* 0x65 */ { NULL, NULL, 0 },
282 /* 0x66 */ { NULL, NULL, 0 },
283 /* 0x67 */ { NULL, NULL, 0 },
284 /* 0x68 */ { NULL, NULL, 0 },
285 /* 0x69 */ { NULL, NULL, 0 },
286 /* 0x6a */ { NULL, NULL, 0 },
287 /* 0x6b */ { NULL, NULL, 0 },
288 /* 0x6c */ { NULL, NULL, 0 },
289 /* 0x6d */ { NULL, NULL, 0 },
290 /* 0x6e */ { NULL, NULL, 0 },
291 /* 0x6f */ { NULL, NULL, 0 },
292 /* 0x70 */ { "SMBtcon", smbsrv_reply_tcon, NEED_SESS },
293 /* 0x71 */ { "SMBtdis", smbsrv_reply_tdis, NEED_TCON },
294 /* 0x72 */ { "SMBnegprot", smbsrv_reply_negprot, 0 },
295 /* 0x73 */ { "SMBsesssetupX", smbsrv_reply_sesssetup, 0 },
296 /* 0x74 */ { "SMBulogoffX", smbsrv_reply_ulogoffX, NEED_SESS }, /* ulogoff doesn't give a valid TID */
297 /* 0x75 */ { "SMBtconX", smbsrv_reply_tcon_and_X, NEED_SESS },
298 /* 0x76 */ { NULL, NULL, 0 },
299 /* 0x77 */ { NULL, NULL, 0 },
300 /* 0x78 */ { NULL, NULL, 0 },
301 /* 0x79 */ { NULL, NULL, 0 },
302 /* 0x7a */ { NULL, NULL, 0 },
303 /* 0x7b */ { NULL, NULL, 0 },
304 /* 0x7c */ { NULL, NULL, 0 },
305 /* 0x7d */ { NULL, NULL, 0 },
306 /* 0x7e */ { NULL, NULL, 0 },
307 /* 0x7f */ { NULL, NULL, 0 },
308 /* 0x80 */ { "SMBdskattr", smbsrv_reply_dskattr, NEED_SESS|NEED_TCON },
309 /* 0x81 */ { "SMBsearch", smbsrv_reply_search, NEED_SESS|NEED_TCON },
310 /* 0x82 */ { "SMBffirst", smbsrv_reply_search, NEED_SESS|NEED_TCON },
311 /* 0x83 */ { "SMBfunique", smbsrv_reply_search, NEED_SESS|NEED_TCON },
312 /* 0x84 */ { "SMBfclose", smbsrv_reply_fclose, NEED_SESS|NEED_TCON },
313 /* 0x85 */ { NULL, NULL, 0 },
314 /* 0x86 */ { NULL, NULL, 0 },
315 /* 0x87 */ { NULL, NULL, 0 },
316 /* 0x88 */ { NULL, NULL, 0 },
317 /* 0x89 */ { NULL, NULL, 0 },
318 /* 0x8a */ { NULL, NULL, 0 },
319 /* 0x8b */ { NULL, NULL, 0 },
320 /* 0x8c */ { NULL, NULL, 0 },
321 /* 0x8d */ { NULL, NULL, 0 },
322 /* 0x8e */ { NULL, NULL, 0 },
323 /* 0x8f */ { NULL, NULL, 0 },
324 /* 0x90 */ { NULL, NULL, 0 },
325 /* 0x91 */ { NULL, NULL, 0 },
326 /* 0x92 */ { NULL, NULL, 0 },
327 /* 0x93 */ { NULL, NULL, 0 },
328 /* 0x94 */ { NULL, NULL, 0 },
329 /* 0x95 */ { NULL, NULL, 0 },
330 /* 0x96 */ { NULL, NULL, 0 },
331 /* 0x97 */ { NULL, NULL, 0 },
332 /* 0x98 */ { NULL, NULL, 0 },
333 /* 0x99 */ { NULL, NULL, 0 },
334 /* 0x9a */ { NULL, NULL, 0 },
335 /* 0x9b */ { NULL, NULL, 0 },
336 /* 0x9c */ { NULL, NULL, 0 },
337 /* 0x9d */ { NULL, NULL, 0 },
338 /* 0x9e */ { NULL, NULL, 0 },
339 /* 0x9f */ { NULL, NULL, 0 },
340 /* 0xa0 */ { "SMBnttrans", smbsrv_reply_nttrans, NEED_SESS|NEED_TCON },
341 /* 0xa1 */ { "SMBnttranss", smbsrv_reply_nttranss, NEED_SESS|NEED_TCON },
342 /* 0xa2 */ { "SMBntcreateX", smbsrv_reply_ntcreate_and_X, NEED_SESS|NEED_TCON },
343 /* 0xa3 */ { NULL, NULL, 0 },
344 /* 0xa4 */ { "SMBntcancel", smbsrv_reply_ntcancel, NEED_SESS|NEED_TCON|SIGNING_NO_REPLY },
345 /* 0xa5 */ { "SMBntrename", smbsrv_reply_ntrename, NEED_SESS|NEED_TCON },
346 /* 0xa6 */ { NULL, NULL, 0 },
347 /* 0xa7 */ { NULL, NULL, 0 },
348 /* 0xa8 */ { NULL, NULL, 0 },
349 /* 0xa9 */ { NULL, NULL, 0 },
350 /* 0xaa */ { NULL, NULL, 0 },
351 /* 0xab */ { NULL, NULL, 0 },
352 /* 0xac */ { NULL, NULL, 0 },
353 /* 0xad */ { NULL, NULL, 0 },
354 /* 0xae */ { NULL, NULL, 0 },
355 /* 0xaf */ { NULL, NULL, 0 },
356 /* 0xb0 */ { NULL, NULL, 0 },
357 /* 0xb1 */ { NULL, NULL, 0 },
358 /* 0xb2 */ { NULL, NULL, 0 },
359 /* 0xb3 */ { NULL, NULL, 0 },
360 /* 0xb4 */ { NULL, NULL, 0 },
361 /* 0xb5 */ { NULL, NULL, 0 },
362 /* 0xb6 */ { NULL, NULL, 0 },
363 /* 0xb7 */ { NULL, NULL, 0 },
364 /* 0xb8 */ { NULL, NULL, 0 },
365 /* 0xb9 */ { NULL, NULL, 0 },
366 /* 0xba */ { NULL, NULL, 0 },
367 /* 0xbb */ { NULL, NULL, 0 },
368 /* 0xbc */ { NULL, NULL, 0 },
369 /* 0xbd */ { NULL, NULL, 0 },
370 /* 0xbe */ { NULL, NULL, 0 },
371 /* 0xbf */ { NULL, NULL, 0 },
372 /* 0xc0 */ { "SMBsplopen", smbsrv_reply_printopen, NEED_SESS|NEED_TCON },
373 /* 0xc1 */ { "SMBsplwr", smbsrv_reply_printwrite, NEED_SESS|NEED_TCON },
374 /* 0xc2 */ { "SMBsplclose", smbsrv_reply_printclose, NEED_SESS|NEED_TCON },
375 /* 0xc3 */ { "SMBsplretq", smbsrv_reply_printqueue, NEED_SESS|NEED_TCON },
376 /* 0xc4 */ { NULL, NULL, 0 },
377 /* 0xc5 */ { NULL, NULL, 0 },
378 /* 0xc6 */ { NULL, NULL, 0 },
379 /* 0xc7 */ { NULL, NULL, 0 },
380 /* 0xc8 */ { NULL, NULL, 0 },
381 /* 0xc9 */ { NULL, NULL, 0 },
382 /* 0xca */ { NULL, NULL, 0 },
383 /* 0xcb */ { NULL, NULL, 0 },
384 /* 0xcc */ { NULL, NULL, 0 },
385 /* 0xcd */ { NULL, NULL, 0 },
386 /* 0xce */ { NULL, NULL, 0 },
387 /* 0xcf */ { NULL, NULL, 0 },
388 /* 0xd0 */ { "SMBsends", NULL, 0 },
389 /* 0xd1 */ { "SMBsendb", NULL, 0 },
390 /* 0xd2 */ { "SMBfwdname", NULL, 0 },
391 /* 0xd3 */ { "SMBcancelf", NULL, 0 },
392 /* 0xd4 */ { "SMBgetmac", NULL, 0 },
393 /* 0xd5 */ { "SMBsendstrt", NULL, 0 },
394 /* 0xd6 */ { "SMBsendend", NULL, 0 },
395 /* 0xd7 */ { "SMBsendtxt", NULL, 0 },
396 /* 0xd8 */ { NULL, NULL, 0 },
397 /* 0xd9 */ { NULL, NULL, 0 },
398 /* 0xda */ { NULL, NULL, 0 },
399 /* 0xdb */ { NULL, NULL, 0 },
400 /* 0xdc */ { NULL, NULL, 0 },
401 /* 0xdd */ { NULL, NULL, 0 },
402 /* 0xde */ { NULL, NULL, 0 },
403 /* 0xdf */ { NULL, NULL, 0 },
404 /* 0xe0 */ { NULL, NULL, 0 },
405 /* 0xe1 */ { NULL, NULL, 0 },
406 /* 0xe2 */ { NULL, NULL, 0 },
407 /* 0xe3 */ { NULL, NULL, 0 },
408 /* 0xe4 */ { NULL, NULL, 0 },
409 /* 0xe5 */ { NULL, NULL, 0 },
410 /* 0xe6 */ { NULL, NULL, 0 },
411 /* 0xe7 */ { NULL, NULL, 0 },
412 /* 0xe8 */ { NULL, NULL, 0 },
413 /* 0xe9 */ { NULL, NULL, 0 },
414 /* 0xea */ { NULL, NULL, 0 },
415 /* 0xeb */ { NULL, NULL, 0 },
416 /* 0xec */ { NULL, NULL, 0 },
417 /* 0xed */ { NULL, NULL, 0 },
418 /* 0xee */ { NULL, NULL, 0 },
419 /* 0xef */ { NULL, NULL, 0 },
420 /* 0xf0 */ { NULL, NULL, 0 },
421 /* 0xf1 */ { NULL, NULL, 0 },
422 /* 0xf2 */ { NULL, NULL, 0 },
423 /* 0xf3 */ { NULL, NULL, 0 },
424 /* 0xf4 */ { NULL, NULL, 0 },
425 /* 0xf5 */ { NULL, NULL, 0 },
426 /* 0xf6 */ { NULL, NULL, 0 },
427 /* 0xf7 */ { NULL, NULL, 0 },
428 /* 0xf8 */ { NULL, NULL, 0 },
429 /* 0xf9 */ { NULL, NULL, 0 },
430 /* 0xfa */ { NULL, NULL, 0 },
431 /* 0xfb */ { NULL, NULL, 0 },
432 /* 0xfc */ { NULL, NULL, 0 },
433 /* 0xfd */ { NULL, NULL, 0 },
434 /* 0xfe */ { NULL, NULL, 0 },
435 /* 0xff */ { NULL, NULL, 0 }
438 /****************************************************************************
439 return a string containing the function name of a SMB command
440 ****************************************************************************/
441 static const char *smb_fn_name(uint8_t type)
443 const char *unknown_name = "SMBunknown";
445 if (smb_messages[type].name == NULL)
448 return smb_messages[type].name;
452 /****************************************************************************
453 Do a switch on the message type and call the specific reply function for this
454 message. Unlike earlier versions of Samba the reply functions are responsible
455 for sending the reply themselves, rather than returning a size to this function
456 The reply functions may also choose to delay the processing by pushing the message
457 onto the message queue
458 ****************************************************************************/
459 static void switch_message(int type, struct smbsrv_request *req)
462 struct smbsrv_connection *smb_conn = req->smb_conn;
469 if (smb_messages[type].fn == NULL) {
470 DEBUG(0,("Unknown message type %d!\n",type));
471 smbsrv_reply_unknown(req);
475 flags = smb_messages[type].flags;
477 req->tcon = smbsrv_smb_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID), req->request_time);
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) {
487 req->session = req->tcon->sec_share.session;
490 req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID), req->request_time);
494 DEBUG(5,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id));
496 /* this must be called before we do any reply */
497 if (flags & SIGNING_NO_REPLY) {
498 smbsrv_signing_no_reply(req);
501 /* see if the vuid is valid */
502 if ((flags & NEED_SESS) && !req->session) {
503 /* amazingly, the error code depends on the command */
508 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
511 status = NT_STATUS_INVALID_HANDLE;
516 * don't know how to handle smb signing for this case
517 * so just skip the reply
519 if ((flags & SIGNING_NO_REPLY) &&
520 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
521 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
522 smb_fn_name(type), nt_errstr(status)));
526 smbsrv_send_error(req, status);
530 /* does this protocol need a valid tree connection? */
531 if ((flags & NEED_TCON) && !req->tcon) {
532 /* amazingly, the error code depends on the command */
537 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
540 status = NT_STATUS_INVALID_HANDLE;
545 * don't know how to handle smb signing for this case
546 * so just skip the reply
548 if ((flags & SIGNING_NO_REPLY) &&
549 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
550 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
551 smb_fn_name(type), nt_errstr(status)));
555 smbsrv_send_error(req, status);
559 smb_messages[type].fn(req);
563 we call this when first first part of a possibly chained request has been completed
564 and we need to call the 2nd part, if any
566 void smbsrv_chain_reply(struct smbsrv_request *req)
568 uint16_t chain_cmd, chain_offset;
573 if (req->in.wct < 2 || req->out.wct < 2) {
574 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
578 chain_cmd = CVAL(req->in.vwv, VWV(0));
579 chain_offset = SVAL(req->in.vwv, VWV(1));
581 if (chain_cmd == SMB_CHAIN_NONE) {
583 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
584 SSVAL(req->out.vwv, VWV(1), 0);
585 smbsrv_send_reply(req);
589 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
593 wct = CVAL(req->in.hdr, chain_offset);
594 vwv = req->in.hdr + chain_offset + 1;
596 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
600 data_size = SVAL(vwv, VWV(wct));
601 data = vwv + VWV(wct) + 2;
603 if (data + data_size > req->in.buffer + req->in.size) {
607 /* all seems legit */
611 req->in.data_size = data_size;
616 SSVAL(req->out.vwv, VWV(0), chain_cmd);
617 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
619 /* cleanup somestuff for the next request */
620 talloc_free(req->ntvfs);
622 talloc_free(req->io_ptr);
625 switch_message(chain_cmd, req);
629 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
630 SSVAL(req->out.vwv, VWV(1), 0);
631 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
635 * init the SMB protocol related stuff
637 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn)
641 /* now initialise a few default values associated with this smb socket */
642 smb_conn->negotiate.max_send = 0xFFFF;
644 /* this is the size that w2k uses, and it appears to be important for
646 smb_conn->negotiate.max_recv = lp_max_xmit();
648 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
650 smb_conn->config.security = lp_security();
651 smb_conn->config.nt_status_support = lp_nt_status_support();
653 status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
654 NT_STATUS_NOT_OK_RETURN(status);
656 status = smbsrv_smb_init_tcons(smb_conn);
657 NT_STATUS_NOT_OK_RETURN(status);
659 smbsrv_init_signing(smb_conn);