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