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