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