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