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