Merge branch 'v4-0-test' of ssh://git.samba.org/data/git/samba into 4-0-abartlet
[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   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 %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id.id));
512
513         /* this must be called before we do any reply */
514         if (flags & SIGNING_NO_REPLY) {
515                 smbsrv_signing_no_reply(req);
516         }
517
518         /* see if the vuid is valid */
519         if ((flags & NEED_SESS) && !req->session) {
520                 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
521                 /* amazingly, the error code depends on the command */
522                 switch (type) {
523                 case SMBntcreateX:
524                 case SMBntcancel:
525                 case SMBulogoffX:
526                         break;
527                 default:
528                         if (req->smb_conn->config.nt_status_support &&
529                             req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
530                                 status = NT_STATUS_INVALID_HANDLE;
531                         }
532                         break;
533                 }
534                 /* 
535                  * TODO:
536                  * don't know how to handle smb signing for this case 
537                  * so just skip the reply
538                  */
539                 if ((flags & SIGNING_NO_REPLY) &&
540                     (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
541                         DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
542                                 smb_fn_name(type), nt_errstr(status)));
543                         talloc_free(req);
544                         return;
545                 }
546                 smbsrv_send_error(req, status);
547                 return;
548         }
549
550         /* does this protocol need a valid tree connection? */
551         if ((flags & NEED_TCON) && !req->tcon) {
552                 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
553                 /* amazingly, the error code depends on the command */
554                 switch (type) {
555                 case SMBntcreateX:
556                 case SMBntcancel:
557                 case SMBtdis:
558                         break;
559                 default:
560                         if (req->smb_conn->config.nt_status_support &&
561                             req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
562                                 status = NT_STATUS_INVALID_HANDLE;
563                         }
564                         break;
565                 }
566                 /* 
567                  * TODO:
568                  * don't know how to handle smb signing for this case 
569                  * so just skip the reply
570                  */
571                 if ((flags & SIGNING_NO_REPLY) &&
572                     (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
573                         DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
574                                 smb_fn_name(type), nt_errstr(status)));
575                         talloc_free(req);
576                         return;
577                 }
578                 smbsrv_send_error(req, status);
579                 return;
580         }
581
582         smb_messages[type].fn(req);
583 }
584
585 /*
586   we call this when first first part of a possibly chained request has been completed
587   and we need to call the 2nd part, if any
588 */
589 void smbsrv_chain_reply(struct smbsrv_request *req)
590 {
591         uint16_t chain_cmd, chain_offset;
592         uint8_t *vwv, *data;
593         uint16_t wct;
594         uint16_t data_size;
595
596         if (req->in.wct < 2 || req->out.wct < 2) {
597                 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
598                 return;
599         }
600
601         chain_cmd    = CVAL(req->in.vwv, VWV(0));
602         chain_offset = SVAL(req->in.vwv, VWV(1));
603
604         if (chain_cmd == SMB_CHAIN_NONE) {
605                 /* end of chain */
606                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
607                 SSVAL(req->out.vwv, VWV(1), 0);
608                 smbsrv_send_reply(req);
609                 return;
610         }
611
612         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
613                 goto error;
614         }
615
616         wct = CVAL(req->in.hdr, chain_offset);
617         vwv = req->in.hdr + chain_offset + 1;
618
619         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
620                 goto error;
621         }
622
623         data_size = SVAL(vwv, VWV(wct));
624         data = vwv + VWV(wct) + 2;
625
626         if (data + data_size > req->in.buffer + req->in.size) {
627                 goto error;
628         }
629
630         /* all seems legit */
631         req->in.vwv = vwv;
632         req->in.wct = wct;
633         req->in.data = data;
634         req->in.data_size = data_size;
635         req->in.ptr = data;
636
637         /* fix the bufinfo */
638         smbsrv_setup_bufinfo(req);
639
640         req->chain_count++;
641
642         SSVAL(req->out.vwv, VWV(0), chain_cmd);
643         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
644
645         /* cleanup somestuff for the next request */
646         talloc_free(req->ntvfs);
647         req->ntvfs = NULL;
648         talloc_free(req->io_ptr);
649         req->io_ptr = NULL;
650
651         switch_message(chain_cmd, req);
652         return;
653
654 error:
655         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
656         SSVAL(req->out.vwv, VWV(1), 0);
657         smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
658 }
659
660 /*
661  * init the SMB protocol related stuff
662  */
663 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn, struct loadparm_context *lp_ctx)
664 {
665         NTSTATUS status;
666
667         /* now initialise a few default values associated with this smb socket */
668         smb_conn->negotiate.max_send = 0xFFFF;
669
670         /* this is the size that w2k uses, and it appears to be important for
671            good performance */
672         smb_conn->negotiate.max_recv = lp_max_xmit(lp_ctx);
673
674         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
675
676         smb_conn->config.security = lp_security(lp_ctx);
677         smb_conn->config.nt_status_support = lp_nt_status_support(lp_ctx);
678
679         status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
680         NT_STATUS_NOT_OK_RETURN(status);
681
682         status = smbsrv_smb_init_tcons(smb_conn);
683         NT_STATUS_NOT_OK_RETURN(status);
684
685         smbsrv_init_signing(smb_conn);
686
687         return NT_STATUS_OK;
688 }