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