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