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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "system/time.h"
24 #include "smbd/service_stream.h"
25 #include "smb_server/smb_server.h"
26 #include "smb_server/service_smb_proto.h"
27 #include "ntvfs/ntvfs.h"
28 #include "system/filesys.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",
146 (int)req->in.data_size));
147 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
151 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
153 if (!smbsrv_signing_check_incoming(req)) {
154 smbsrv_send_error(req, NT_STATUS_ACCESS_DENIED);
158 command = CVAL(req->in.hdr, HDR_COM);
159 switch_message(command, req);
164 These flags determine some of the permissions required to do an operation
166 #define NEED_SESS (1<<0)
167 #define NEED_TCON (1<<1)
168 #define SIGNING_NO_REPLY (1<<2)
171 define a list of possible SMB messages and their corresponding
172 functions. Any message that has a NULL function is unimplemented -
173 please feel free to contribute implementations!
175 static const struct smb_message_struct
178 void (*fn)(struct smbsrv_request *);
181 smb_messages[256] = {
182 /* 0x00 */ { "SMBmkdir", smbsrv_reply_mkdir, NEED_SESS|NEED_TCON },
183 /* 0x01 */ { "SMBrmdir", smbsrv_reply_rmdir, NEED_SESS|NEED_TCON },
184 /* 0x02 */ { "SMBopen", smbsrv_reply_open, NEED_SESS|NEED_TCON },
185 /* 0x03 */ { "SMBcreate", smbsrv_reply_mknew, NEED_SESS|NEED_TCON },
186 /* 0x04 */ { "SMBclose", smbsrv_reply_close, NEED_SESS|NEED_TCON },
187 /* 0x05 */ { "SMBflush", smbsrv_reply_flush, NEED_SESS|NEED_TCON },
188 /* 0x06 */ { "SMBunlink", smbsrv_reply_unlink, NEED_SESS|NEED_TCON },
189 /* 0x07 */ { "SMBmv", smbsrv_reply_mv, NEED_SESS|NEED_TCON },
190 /* 0x08 */ { "SMBgetatr", smbsrv_reply_getatr, NEED_SESS|NEED_TCON },
191 /* 0x09 */ { "SMBsetatr", smbsrv_reply_setatr, NEED_SESS|NEED_TCON },
192 /* 0x0a */ { "SMBread", smbsrv_reply_read, NEED_SESS|NEED_TCON },
193 /* 0x0b */ { "SMBwrite", smbsrv_reply_write, NEED_SESS|NEED_TCON },
194 /* 0x0c */ { "SMBlock", smbsrv_reply_lock, NEED_SESS|NEED_TCON },
195 /* 0x0d */ { "SMBunlock", smbsrv_reply_unlock, NEED_SESS|NEED_TCON },
196 /* 0x0e */ { "SMBctemp", smbsrv_reply_ctemp, NEED_SESS|NEED_TCON },
197 /* 0x0f */ { "SMBmknew", smbsrv_reply_mknew, NEED_SESS|NEED_TCON },
198 /* 0x10 */ { "SMBchkpth", smbsrv_reply_chkpth, NEED_SESS|NEED_TCON },
199 /* 0x11 */ { "SMBexit", smbsrv_reply_exit, NEED_SESS },
200 /* 0x12 */ { "SMBlseek", smbsrv_reply_lseek, NEED_SESS|NEED_TCON },
201 /* 0x13 */ { "SMBlockread", smbsrv_reply_lockread, NEED_SESS|NEED_TCON },
202 /* 0x14 */ { "SMBwriteunlock", smbsrv_reply_writeunlock, NEED_SESS|NEED_TCON },
203 /* 0x15 */ { NULL, NULL, 0 },
204 /* 0x16 */ { NULL, NULL, 0 },
205 /* 0x17 */ { NULL, NULL, 0 },
206 /* 0x18 */ { NULL, NULL, 0 },
207 /* 0x19 */ { NULL, NULL, 0 },
208 /* 0x1a */ { "SMBreadbraw", smbsrv_reply_readbraw, NEED_SESS|NEED_TCON },
209 /* 0x1b */ { "SMBreadBmpx", smbsrv_reply_readbmpx, NEED_SESS|NEED_TCON },
210 /* 0x1c */ { "SMBreadBs", NULL, 0 },
211 /* 0x1d */ { "SMBwritebraw", smbsrv_reply_writebraw, NEED_SESS|NEED_TCON },
212 /* 0x1e */ { "SMBwriteBmpx", smbsrv_reply_writebmpx, NEED_SESS|NEED_TCON },
213 /* 0x1f */ { "SMBwriteBs", smbsrv_reply_writebs, NEED_SESS|NEED_TCON },
214 /* 0x20 */ { "SMBwritec", NULL, 0 },
215 /* 0x21 */ { NULL, NULL, 0 },
216 /* 0x22 */ { "SMBsetattrE", smbsrv_reply_setattrE, NEED_SESS|NEED_TCON },
217 /* 0x23 */ { "SMBgetattrE", smbsrv_reply_getattrE, NEED_SESS|NEED_TCON },
218 /* 0x24 */ { "SMBlockingX", smbsrv_reply_lockingX, NEED_SESS|NEED_TCON },
219 /* 0x25 */ { "SMBtrans", smbsrv_reply_trans, NEED_SESS|NEED_TCON },
220 /* 0x26 */ { "SMBtranss", smbsrv_reply_transs, NEED_SESS|NEED_TCON },
221 /* 0x27 */ { "SMBioctl", smbsrv_reply_ioctl, NEED_SESS|NEED_TCON },
222 /* 0x28 */ { "SMBioctls", NULL, NEED_SESS|NEED_TCON },
223 /* 0x29 */ { "SMBcopy", smbsrv_reply_copy, NEED_SESS|NEED_TCON },
224 /* 0x2a */ { "SMBmove", NULL, NEED_SESS|NEED_TCON },
225 /* 0x2b */ { "SMBecho", smbsrv_reply_echo, 0 },
226 /* 0x2c */ { "SMBwriteclose", smbsrv_reply_writeclose, NEED_SESS|NEED_TCON },
227 /* 0x2d */ { "SMBopenX", smbsrv_reply_open_and_X, NEED_SESS|NEED_TCON },
228 /* 0x2e */ { "SMBreadX", smbsrv_reply_read_and_X, NEED_SESS|NEED_TCON },
229 /* 0x2f */ { "SMBwriteX", smbsrv_reply_write_and_X, NEED_SESS|NEED_TCON},
230 /* 0x30 */ { NULL, NULL, 0 },
231 /* 0x31 */ { NULL, NULL, 0 },
232 /* 0x32 */ { "SMBtrans2", smbsrv_reply_trans2, NEED_SESS|NEED_TCON },
233 /* 0x33 */ { "SMBtranss2", smbsrv_reply_transs2, NEED_SESS|NEED_TCON },
234 /* 0x34 */ { "SMBfindclose", smbsrv_reply_findclose, NEED_SESS|NEED_TCON },
235 /* 0x35 */ { "SMBfindnclose", smbsrv_reply_findnclose, NEED_SESS|NEED_TCON },
236 /* 0x36 */ { NULL, NULL, 0 },
237 /* 0x37 */ { NULL, NULL, 0 },
238 /* 0x38 */ { NULL, NULL, 0 },
239 /* 0x39 */ { NULL, NULL, 0 },
240 /* 0x3a */ { NULL, NULL, 0 },
241 /* 0x3b */ { NULL, NULL, 0 },
242 /* 0x3c */ { NULL, NULL, 0 },
243 /* 0x3d */ { NULL, NULL, 0 },
244 /* 0x3e */ { NULL, NULL, 0 },
245 /* 0x3f */ { NULL, NULL, 0 },
246 /* 0x40 */ { NULL, NULL, 0 },
247 /* 0x41 */ { NULL, NULL, 0 },
248 /* 0x42 */ { NULL, NULL, 0 },
249 /* 0x43 */ { NULL, NULL, 0 },
250 /* 0x44 */ { NULL, NULL, 0 },
251 /* 0x45 */ { NULL, NULL, 0 },
252 /* 0x46 */ { NULL, NULL, 0 },
253 /* 0x47 */ { NULL, NULL, 0 },
254 /* 0x48 */ { NULL, NULL, 0 },
255 /* 0x49 */ { NULL, NULL, 0 },
256 /* 0x4a */ { NULL, NULL, 0 },
257 /* 0x4b */ { NULL, NULL, 0 },
258 /* 0x4c */ { NULL, NULL, 0 },
259 /* 0x4d */ { NULL, NULL, 0 },
260 /* 0x4e */ { NULL, NULL, 0 },
261 /* 0x4f */ { NULL, NULL, 0 },
262 /* 0x50 */ { NULL, NULL, 0 },
263 /* 0x51 */ { NULL, NULL, 0 },
264 /* 0x52 */ { NULL, NULL, 0 },
265 /* 0x53 */ { NULL, NULL, 0 },
266 /* 0x54 */ { NULL, NULL, 0 },
267 /* 0x55 */ { NULL, NULL, 0 },
268 /* 0x56 */ { NULL, NULL, 0 },
269 /* 0x57 */ { NULL, NULL, 0 },
270 /* 0x58 */ { NULL, NULL, 0 },
271 /* 0x59 */ { NULL, NULL, 0 },
272 /* 0x5a */ { NULL, NULL, 0 },
273 /* 0x5b */ { NULL, NULL, 0 },
274 /* 0x5c */ { NULL, NULL, 0 },
275 /* 0x5d */ { NULL, NULL, 0 },
276 /* 0x5e */ { NULL, NULL, 0 },
277 /* 0x5f */ { NULL, NULL, 0 },
278 /* 0x60 */ { NULL, NULL, 0 },
279 /* 0x61 */ { NULL, NULL, 0 },
280 /* 0x62 */ { NULL, NULL, 0 },
281 /* 0x63 */ { NULL, NULL, 0 },
282 /* 0x64 */ { NULL, NULL, 0 },
283 /* 0x65 */ { NULL, NULL, 0 },
284 /* 0x66 */ { NULL, NULL, 0 },
285 /* 0x67 */ { NULL, NULL, 0 },
286 /* 0x68 */ { NULL, NULL, 0 },
287 /* 0x69 */ { NULL, NULL, 0 },
288 /* 0x6a */ { NULL, NULL, 0 },
289 /* 0x6b */ { NULL, NULL, 0 },
290 /* 0x6c */ { NULL, NULL, 0 },
291 /* 0x6d */ { NULL, NULL, 0 },
292 /* 0x6e */ { NULL, NULL, 0 },
293 /* 0x6f */ { NULL, NULL, 0 },
294 /* 0x70 */ { "SMBtcon", smbsrv_reply_tcon, NEED_SESS },
295 /* 0x71 */ { "SMBtdis", smbsrv_reply_tdis, NEED_TCON },
296 /* 0x72 */ { "SMBnegprot", smbsrv_reply_negprot, 0 },
297 /* 0x73 */ { "SMBsesssetupX", smbsrv_reply_sesssetup, 0 },
298 /* 0x74 */ { "SMBulogoffX", smbsrv_reply_ulogoffX, NEED_SESS }, /* ulogoff doesn't give a valid TID */
299 /* 0x75 */ { "SMBtconX", smbsrv_reply_tcon_and_X, NEED_SESS },
300 /* 0x76 */ { NULL, NULL, 0 },
301 /* 0x77 */ { NULL, NULL, 0 },
302 /* 0x78 */ { NULL, NULL, 0 },
303 /* 0x79 */ { NULL, NULL, 0 },
304 /* 0x7a */ { NULL, NULL, 0 },
305 /* 0x7b */ { NULL, NULL, 0 },
306 /* 0x7c */ { NULL, NULL, 0 },
307 /* 0x7d */ { NULL, NULL, 0 },
308 /* 0x7e */ { NULL, NULL, 0 },
309 /* 0x7f */ { NULL, NULL, 0 },
310 /* 0x80 */ { "SMBdskattr", smbsrv_reply_dskattr, NEED_SESS|NEED_TCON },
311 /* 0x81 */ { "SMBsearch", smbsrv_reply_search, NEED_SESS|NEED_TCON },
312 /* 0x82 */ { "SMBffirst", smbsrv_reply_search, NEED_SESS|NEED_TCON },
313 /* 0x83 */ { "SMBfunique", smbsrv_reply_search, NEED_SESS|NEED_TCON },
314 /* 0x84 */ { "SMBfclose", smbsrv_reply_fclose, NEED_SESS|NEED_TCON },
315 /* 0x85 */ { NULL, NULL, 0 },
316 /* 0x86 */ { NULL, NULL, 0 },
317 /* 0x87 */ { NULL, NULL, 0 },
318 /* 0x88 */ { NULL, NULL, 0 },
319 /* 0x89 */ { NULL, NULL, 0 },
320 /* 0x8a */ { NULL, NULL, 0 },
321 /* 0x8b */ { NULL, NULL, 0 },
322 /* 0x8c */ { NULL, NULL, 0 },
323 /* 0x8d */ { NULL, NULL, 0 },
324 /* 0x8e */ { NULL, NULL, 0 },
325 /* 0x8f */ { NULL, NULL, 0 },
326 /* 0x90 */ { NULL, NULL, 0 },
327 /* 0x91 */ { NULL, NULL, 0 },
328 /* 0x92 */ { NULL, NULL, 0 },
329 /* 0x93 */ { NULL, NULL, 0 },
330 /* 0x94 */ { NULL, NULL, 0 },
331 /* 0x95 */ { NULL, NULL, 0 },
332 /* 0x96 */ { NULL, NULL, 0 },
333 /* 0x97 */ { NULL, NULL, 0 },
334 /* 0x98 */ { NULL, NULL, 0 },
335 /* 0x99 */ { NULL, NULL, 0 },
336 /* 0x9a */ { NULL, NULL, 0 },
337 /* 0x9b */ { NULL, NULL, 0 },
338 /* 0x9c */ { NULL, NULL, 0 },
339 /* 0x9d */ { NULL, NULL, 0 },
340 /* 0x9e */ { NULL, NULL, 0 },
341 /* 0x9f */ { NULL, NULL, 0 },
342 /* 0xa0 */ { "SMBnttrans", smbsrv_reply_nttrans, NEED_SESS|NEED_TCON },
343 /* 0xa1 */ { "SMBnttranss", smbsrv_reply_nttranss, NEED_SESS|NEED_TCON },
344 /* 0xa2 */ { "SMBntcreateX", smbsrv_reply_ntcreate_and_X, NEED_SESS|NEED_TCON },
345 /* 0xa3 */ { NULL, NULL, 0 },
346 /* 0xa4 */ { "SMBntcancel", smbsrv_reply_ntcancel, NEED_SESS|NEED_TCON|SIGNING_NO_REPLY },
347 /* 0xa5 */ { "SMBntrename", smbsrv_reply_ntrename, NEED_SESS|NEED_TCON },
348 /* 0xa6 */ { NULL, NULL, 0 },
349 /* 0xa7 */ { NULL, NULL, 0 },
350 /* 0xa8 */ { NULL, NULL, 0 },
351 /* 0xa9 */ { NULL, NULL, 0 },
352 /* 0xaa */ { NULL, NULL, 0 },
353 /* 0xab */ { NULL, NULL, 0 },
354 /* 0xac */ { NULL, NULL, 0 },
355 /* 0xad */ { NULL, NULL, 0 },
356 /* 0xae */ { NULL, NULL, 0 },
357 /* 0xaf */ { NULL, NULL, 0 },
358 /* 0xb0 */ { NULL, NULL, 0 },
359 /* 0xb1 */ { NULL, NULL, 0 },
360 /* 0xb2 */ { NULL, NULL, 0 },
361 /* 0xb3 */ { NULL, NULL, 0 },
362 /* 0xb4 */ { NULL, NULL, 0 },
363 /* 0xb5 */ { NULL, NULL, 0 },
364 /* 0xb6 */ { NULL, NULL, 0 },
365 /* 0xb7 */ { NULL, NULL, 0 },
366 /* 0xb8 */ { NULL, NULL, 0 },
367 /* 0xb9 */ { NULL, NULL, 0 },
368 /* 0xba */ { NULL, NULL, 0 },
369 /* 0xbb */ { NULL, NULL, 0 },
370 /* 0xbc */ { NULL, NULL, 0 },
371 /* 0xbd */ { NULL, NULL, 0 },
372 /* 0xbe */ { NULL, NULL, 0 },
373 /* 0xbf */ { NULL, NULL, 0 },
374 /* 0xc0 */ { "SMBsplopen", smbsrv_reply_printopen, NEED_SESS|NEED_TCON },
375 /* 0xc1 */ { "SMBsplwr", smbsrv_reply_printwrite, NEED_SESS|NEED_TCON },
376 /* 0xc2 */ { "SMBsplclose", smbsrv_reply_printclose, NEED_SESS|NEED_TCON },
377 /* 0xc3 */ { "SMBsplretq", smbsrv_reply_printqueue, NEED_SESS|NEED_TCON },
378 /* 0xc4 */ { NULL, NULL, 0 },
379 /* 0xc5 */ { NULL, NULL, 0 },
380 /* 0xc6 */ { NULL, NULL, 0 },
381 /* 0xc7 */ { NULL, NULL, 0 },
382 /* 0xc8 */ { NULL, NULL, 0 },
383 /* 0xc9 */ { NULL, NULL, 0 },
384 /* 0xca */ { NULL, NULL, 0 },
385 /* 0xcb */ { NULL, NULL, 0 },
386 /* 0xcc */ { NULL, NULL, 0 },
387 /* 0xcd */ { NULL, NULL, 0 },
388 /* 0xce */ { NULL, NULL, 0 },
389 /* 0xcf */ { NULL, NULL, 0 },
390 /* 0xd0 */ { "SMBsends", NULL, 0 },
391 /* 0xd1 */ { "SMBsendb", NULL, 0 },
392 /* 0xd2 */ { "SMBfwdname", NULL, 0 },
393 /* 0xd3 */ { "SMBcancelf", NULL, 0 },
394 /* 0xd4 */ { "SMBgetmac", NULL, 0 },
395 /* 0xd5 */ { "SMBsendstrt", NULL, 0 },
396 /* 0xd6 */ { "SMBsendend", NULL, 0 },
397 /* 0xd7 */ { "SMBsendtxt", NULL, 0 },
398 /* 0xd8 */ { NULL, NULL, 0 },
399 /* 0xd9 */ { NULL, NULL, 0 },
400 /* 0xda */ { NULL, NULL, 0 },
401 /* 0xdb */ { NULL, NULL, 0 },
402 /* 0xdc */ { NULL, NULL, 0 },
403 /* 0xdd */ { NULL, NULL, 0 },
404 /* 0xde */ { NULL, NULL, 0 },
405 /* 0xdf */ { NULL, NULL, 0 },
406 /* 0xe0 */ { NULL, NULL, 0 },
407 /* 0xe1 */ { NULL, NULL, 0 },
408 /* 0xe2 */ { NULL, NULL, 0 },
409 /* 0xe3 */ { NULL, NULL, 0 },
410 /* 0xe4 */ { NULL, NULL, 0 },
411 /* 0xe5 */ { NULL, NULL, 0 },
412 /* 0xe6 */ { NULL, NULL, 0 },
413 /* 0xe7 */ { NULL, NULL, 0 },
414 /* 0xe8 */ { NULL, NULL, 0 },
415 /* 0xe9 */ { NULL, NULL, 0 },
416 /* 0xea */ { NULL, NULL, 0 },
417 /* 0xeb */ { NULL, NULL, 0 },
418 /* 0xec */ { NULL, NULL, 0 },
419 /* 0xed */ { NULL, NULL, 0 },
420 /* 0xee */ { NULL, NULL, 0 },
421 /* 0xef */ { NULL, NULL, 0 },
422 /* 0xf0 */ { NULL, NULL, 0 },
423 /* 0xf1 */ { NULL, NULL, 0 },
424 /* 0xf2 */ { NULL, NULL, 0 },
425 /* 0xf3 */ { NULL, NULL, 0 },
426 /* 0xf4 */ { NULL, NULL, 0 },
427 /* 0xf5 */ { NULL, NULL, 0 },
428 /* 0xf6 */ { NULL, NULL, 0 },
429 /* 0xf7 */ { NULL, NULL, 0 },
430 /* 0xf8 */ { NULL, NULL, 0 },
431 /* 0xf9 */ { NULL, NULL, 0 },
432 /* 0xfa */ { NULL, NULL, 0 },
433 /* 0xfb */ { NULL, NULL, 0 },
434 /* 0xfc */ { NULL, NULL, 0 },
435 /* 0xfd */ { NULL, NULL, 0 },
436 /* 0xfe */ { NULL, NULL, 0 },
437 /* 0xff */ { NULL, NULL, 0 }
440 /****************************************************************************
441 return a string containing the function name of a SMB command
442 ****************************************************************************/
443 static const char *smb_fn_name(uint8_t type)
445 const char *unknown_name = "SMBunknown";
447 if (smb_messages[type].name == NULL)
450 return smb_messages[type].name;
454 /****************************************************************************
455 Do a switch on the message type and call the specific reply function for this
456 message. Unlike earlier versions of Samba the reply functions are responsible
457 for sending the reply themselves, rather than returning a size to this function
458 The reply functions may also choose to delay the processing by pushing the message
459 onto the message queue
460 ****************************************************************************/
461 static void switch_message(int type, struct smbsrv_request *req)
464 struct smbsrv_connection *smb_conn = req->smb_conn;
471 if (smb_messages[type].fn == NULL) {
472 DEBUG(0,("Unknown message type %d!\n",type));
473 smbsrv_reply_unknown(req);
477 flags = smb_messages[type].flags;
479 req->tcon = smbsrv_smb_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID), req->request_time);
482 /* setup the user context for this request if it
483 hasn't already been initialised (to cope with SMB
486 /* In share mode security we must ignore the vuid. */
487 if (smb_conn->config.security == SEC_SHARE) {
489 req->session = req->tcon->sec_share.session;
492 req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID), req->request_time);
496 DEBUG(5,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id.id));
498 /* this must be called before we do any reply */
499 if (flags & SIGNING_NO_REPLY) {
500 smbsrv_signing_no_reply(req);
503 /* see if the vuid is valid */
504 if ((flags & NEED_SESS) && !req->session) {
505 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
506 /* amazingly, the error code depends on the command */
513 if (req->smb_conn->config.nt_status_support &&
514 req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
515 status = NT_STATUS_INVALID_HANDLE;
521 * don't know how to handle smb signing for this case
522 * so just skip the reply
524 if ((flags & SIGNING_NO_REPLY) &&
525 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
526 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
527 smb_fn_name(type), nt_errstr(status)));
531 smbsrv_send_error(req, status);
535 /* does this protocol need a valid tree connection? */
536 if ((flags & NEED_TCON) && !req->tcon) {
537 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
538 /* amazingly, the error code depends on the command */
545 if (req->smb_conn->config.nt_status_support &&
546 req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
547 status = NT_STATUS_INVALID_HANDLE;
553 * don't know how to handle smb signing for this case
554 * so just skip the reply
556 if ((flags & SIGNING_NO_REPLY) &&
557 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
558 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
559 smb_fn_name(type), nt_errstr(status)));
563 smbsrv_send_error(req, status);
567 smb_messages[type].fn(req);
571 we call this when first first part of a possibly chained request has been completed
572 and we need to call the 2nd part, if any
574 void smbsrv_chain_reply(struct smbsrv_request *req)
576 uint16_t chain_cmd, chain_offset;
581 if (req->in.wct < 2 || req->out.wct < 2) {
582 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
586 chain_cmd = CVAL(req->in.vwv, VWV(0));
587 chain_offset = SVAL(req->in.vwv, VWV(1));
589 if (chain_cmd == SMB_CHAIN_NONE) {
591 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
592 SSVAL(req->out.vwv, VWV(1), 0);
593 smbsrv_send_reply(req);
597 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
601 wct = CVAL(req->in.hdr, chain_offset);
602 vwv = req->in.hdr + chain_offset + 1;
604 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
608 data_size = SVAL(vwv, VWV(wct));
609 data = vwv + VWV(wct) + 2;
611 if (data + data_size > req->in.buffer + req->in.size) {
615 /* all seems legit */
619 req->in.data_size = data_size;
624 SSVAL(req->out.vwv, VWV(0), chain_cmd);
625 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
627 /* cleanup somestuff for the next request */
628 talloc_free(req->ntvfs);
630 talloc_free(req->io_ptr);
633 switch_message(chain_cmd, req);
637 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
638 SSVAL(req->out.vwv, VWV(1), 0);
639 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
643 * init the SMB protocol related stuff
645 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn)
649 /* now initialise a few default values associated with this smb socket */
650 smb_conn->negotiate.max_send = 0xFFFF;
652 /* this is the size that w2k uses, and it appears to be important for
654 smb_conn->negotiate.max_recv = lp_max_xmit();
656 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
658 smb_conn->config.security = lp_security();
659 smb_conn->config.nt_status_support = lp_nt_status_support();
661 status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
662 NT_STATUS_NOT_OK_RETURN(status);
664 status = smbsrv_smb_init_tcons(smb_conn);
665 NT_STATUS_NOT_OK_RETURN(status);
667 smbsrv_init_signing(smb_conn);