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