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