Merge commit 'release-4-0-0alpha1' into v4-0-test
[ira/wip.git] / source / 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 3 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, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
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"
30
31
32 /*
33   send an oplock break request to a client
34 */
35 NTSTATUS smbsrv_send_oplock_break(void *p, struct ntvfs_handle *ntvfs, uint8_t level)
36 {
37         struct smbsrv_tcon *tcon = talloc_get_type(p, struct smbsrv_tcon);
38         struct smbsrv_request *req;
39
40         req = smbsrv_init_request(tcon->smb_conn);
41         NT_STATUS_HAVE_NO_MEMORY(req);
42
43         smbsrv_setup_reply(req, 8, 0);
44
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);
52
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);
61
62         smbsrv_send_reply(req);
63         return NT_STATUS_OK;
64 }
65
66 static void switch_message(int type, struct smbsrv_request *req);
67
68 /****************************************************************************
69 receive a SMB request header from the wire, forming a request_context
70 from the result
71 ****************************************************************************/
72 NTSTATUS smbsrv_recv_smb_request(void *private, DATA_BLOB blob)
73 {
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();
77         uint8_t command;
78
79         smb_conn->statistics.last_request_time = cur_time;
80
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);
85
86                 ZERO_STRUCT(req->in);
87
88                 req->in.buffer = talloc_steal(req, blob.data);
89                 req->in.size = blob.length;
90                 req->request_time = cur_time;
91
92                 smbsrv_reply_special(req);
93                 return NT_STATUS_OK;
94         }
95
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");
99                 return NT_STATUS_OK;
100         }
101
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",
105                          (long)blob.length));
106                 smbsrv_terminate_connection(smb_conn, "Non-SMB packet");
107                 return NT_STATUS_OK;
108         }
109
110         req = smbsrv_init_request(smb_conn);
111         NT_STATUS_HAVE_NO_MEMORY(req);
112
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));
124
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);
136                 }
137         }
138
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");
142                 return NT_STATUS_OK;
143         }
144  
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");
149                 return NT_STATUS_OK;
150         }
151
152         req->flags2     = SVAL(req->in.hdr, HDR_FLG2);
153
154         if (!smbsrv_signing_check_incoming(req)) {
155                 smbsrv_send_error(req, NT_STATUS_ACCESS_DENIED);
156                 return NT_STATUS_OK;
157         }
158
159         command = CVAL(req->in.hdr, HDR_COM);
160         switch_message(command, req);
161         return NT_STATUS_OK;
162 }
163
164 /*
165   These flags determine some of the permissions required to do an operation 
166 */
167 #define NEED_SESS               (1<<0)
168 #define NEED_TCON               (1<<1)
169 #define SIGNING_NO_REPLY        (1<<2)
170
171 /* 
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!
175 */
176 static const struct smb_message_struct
177 {
178         const char *name;
179         void (*fn)(struct smbsrv_request *);
180         int flags;
181 }
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 }
439 };
440
441 /****************************************************************************
442 return a string containing the function name of a SMB command
443 ****************************************************************************/
444 static const char *smb_fn_name(uint8_t type)
445 {
446         const char *unknown_name = "SMBunknown";
447
448         if (smb_messages[type].name == NULL)
449                 return unknown_name;
450
451         return smb_messages[type].name;
452 }
453
454
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)
463 {
464         int flags;
465         struct smbsrv_connection *smb_conn = req->smb_conn;
466         NTSTATUS status;
467
468         type &= 0xff;
469
470         errno = 0;
471
472         if (smb_messages[type].fn == NULL) {
473                 DEBUG(0,("Unknown message type %d!\n",type));
474                 smbsrv_reply_unknown(req);
475                 return;
476         }
477
478         flags = smb_messages[type].flags;
479
480         req->tcon = smbsrv_smb_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID), req->request_time);
481
482         if (!req->session) {
483                 /* setup the user context for this request if it
484                    hasn't already been initialised (to cope with SMB
485                    chaining) */
486
487                 /* In share mode security we must ignore the vuid. */
488                 if (smb_conn->config.security == SEC_SHARE) {
489                         if (req->tcon) {
490                                 req->session = req->tcon->sec_share.session;
491                         }
492                 } else {
493                         req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID), req->request_time);
494                 }
495         }
496
497         DEBUG(5,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id.id));
498
499         /* this must be called before we do any reply */
500         if (flags & SIGNING_NO_REPLY) {
501                 smbsrv_signing_no_reply(req);
502         }
503
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 */
508                 switch (type) {
509                 case SMBntcreateX:
510                 case SMBntcancel:
511                 case SMBulogoffX:
512                         break;
513                 default:
514                         if (req->smb_conn->config.nt_status_support &&
515                             req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
516                                 status = NT_STATUS_INVALID_HANDLE;
517                         }
518                         break;
519                 }
520                 /* 
521                  * TODO:
522                  * don't know how to handle smb signing for this case 
523                  * so just skip the reply
524                  */
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)));
529                         talloc_free(req);
530                         return;
531                 }
532                 smbsrv_send_error(req, status);
533                 return;
534         }
535
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 */
540                 switch (type) {
541                 case SMBntcreateX:
542                 case SMBntcancel:
543                 case SMBtdis:
544                         break;
545                 default:
546                         if (req->smb_conn->config.nt_status_support &&
547                             req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
548                                 status = NT_STATUS_INVALID_HANDLE;
549                         }
550                         break;
551                 }
552                 /* 
553                  * TODO:
554                  * don't know how to handle smb signing for this case 
555                  * so just skip the reply
556                  */
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)));
561                         talloc_free(req);
562                         return;
563                 }
564                 smbsrv_send_error(req, status);
565                 return;
566         }
567
568         smb_messages[type].fn(req);
569 }
570
571 /*
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
574 */
575 void smbsrv_chain_reply(struct smbsrv_request *req)
576 {
577         uint16_t chain_cmd, chain_offset;
578         uint8_t *vwv, *data;
579         uint16_t wct;
580         uint16_t data_size;
581
582         if (req->in.wct < 2 || req->out.wct < 2) {
583                 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
584                 return;
585         }
586
587         chain_cmd    = CVAL(req->in.vwv, VWV(0));
588         chain_offset = SVAL(req->in.vwv, VWV(1));
589
590         if (chain_cmd == SMB_CHAIN_NONE) {
591                 /* end of chain */
592                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
593                 SSVAL(req->out.vwv, VWV(1), 0);
594                 smbsrv_send_reply(req);
595                 return;
596         }
597
598         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
599                 goto error;
600         }
601
602         wct = CVAL(req->in.hdr, chain_offset);
603         vwv = req->in.hdr + chain_offset + 1;
604
605         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
606                 goto error;
607         }
608
609         data_size = SVAL(vwv, VWV(wct));
610         data = vwv + VWV(wct) + 2;
611
612         if (data + data_size > req->in.buffer + req->in.size) {
613                 goto error;
614         }
615
616         /* all seems legit */
617         req->in.vwv = vwv;
618         req->in.wct = wct;
619         req->in.data = data;
620         req->in.data_size = data_size;
621         req->in.ptr = data;
622
623         req->chain_count++;
624
625         SSVAL(req->out.vwv, VWV(0), chain_cmd);
626         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
627
628         /* cleanup somestuff for the next request */
629         talloc_free(req->ntvfs);
630         req->ntvfs = NULL;
631         talloc_free(req->io_ptr);
632         req->io_ptr = NULL;
633
634         switch_message(chain_cmd, req);
635         return;
636
637 error:
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));
641 }
642
643 /*
644  * init the SMB protocol related stuff
645  */
646 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn)
647 {
648         NTSTATUS status;
649
650         /* now initialise a few default values associated with this smb socket */
651         smb_conn->negotiate.max_send = 0xFFFF;
652
653         /* this is the size that w2k uses, and it appears to be important for
654            good performance */
655         smb_conn->negotiate.max_recv = lp_max_xmit(global_loadparm);
656
657         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
658
659         smb_conn->config.security = lp_security(global_loadparm);
660         smb_conn->config.nt_status_support = lp_nt_status_support(global_loadparm);
661
662         status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
663         NT_STATUS_NOT_OK_RETURN(status);
664
665         status = smbsrv_smb_init_tcons(smb_conn);
666         NT_STATUS_NOT_OK_RETURN(status);
667
668         smbsrv_init_signing(smb_conn);
669
670         return NT_STATUS_OK;
671 }