changed BCC handling for SMBwriteX to handle broken MacOSX client
[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, DATA_BLOB blob)
355 {
356         struct smbsrv_connection *smb_conn = talloc_get_type(private_data, 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                 /* special handling for oversize calls. Windows seems
411                    to take the maximum of the BCC value and the
412                    computed buffer size. This handles oversized writeX
413                    calls, and possibly oversized SMBtrans calls */
414                 if ((message_flags(command) & LARGE_REQUEST) &&
415                     ( !(message_flags(command) & AND_X) ||
416                       (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) &&
417                     req->in.data_size < req->in.size - PTR_DIFF(req->in.data,req->in.buffer)) {
418                         req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
419                 }
420         }
421
422         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
423                 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
424                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
425                 return NT_STATUS_OK;
426         }
427  
428         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
429                 DEBUG(2,("Invalid SMB buffer length count %d\n", 
430                          (int)req->in.data_size));
431                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
432                 return NT_STATUS_OK;
433         }
434
435         req->flags2     = SVAL(req->in.hdr, HDR_FLG2);
436
437         /* fix the bufinfo */
438         smbsrv_setup_bufinfo(req);
439
440         if (!smbsrv_signing_check_incoming(req)) {
441                 smbsrv_send_error(req, NT_STATUS_ACCESS_DENIED);
442                 return NT_STATUS_OK;
443         }
444
445         command = CVAL(req->in.hdr, HDR_COM);
446         switch_message(command, req);
447         return NT_STATUS_OK;
448 }
449
450 /****************************************************************************
451 return a string containing the function name of a SMB command
452 ****************************************************************************/
453 static const char *smb_fn_name(uint8_t type)
454 {
455         const char *unknown_name = "SMBunknown";
456
457         if (smb_messages[type].name == NULL)
458                 return unknown_name;
459
460         return smb_messages[type].name;
461 }
462
463
464 /****************************************************************************
465  Do a switch on the message type and call the specific reply function for this 
466 message. Unlike earlier versions of Samba the reply functions are responsible
467 for sending the reply themselves, rather than returning a size to this function
468 The reply functions may also choose to delay the processing by pushing the message
469 onto the message queue
470 ****************************************************************************/
471 static void switch_message(int type, struct smbsrv_request *req)
472 {
473         int flags;
474         struct smbsrv_connection *smb_conn = req->smb_conn;
475         NTSTATUS status;
476
477         type &= 0xff;
478
479         errno = 0;
480
481         if (smb_messages[type].fn == NULL) {
482                 DEBUG(0,("Unknown message type %d!\n",type));
483                 smbsrv_reply_unknown(req);
484                 return;
485         }
486
487         flags = smb_messages[type].flags;
488
489         req->tcon = smbsrv_smb_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID), req->request_time);
490
491         if (!req->session) {
492                 /* setup the user context for this request if it
493                    hasn't already been initialised (to cope with SMB
494                    chaining) */
495
496                 /* In share mode security we must ignore the vuid. */
497                 if (smb_conn->config.security == SEC_SHARE) {
498                         if (req->tcon) {
499                                 req->session = req->tcon->sec_share.session;
500                         }
501                 } else {
502                         req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID), req->request_time);
503                 }
504         }
505
506         DEBUG(5,("switch message %s (task_id %u)\n",
507                  smb_fn_name(type), (unsigned)req->smb_conn->connection->server_id.id));
508
509         /* this must be called before we do any reply */
510         if (flags & SIGNING_NO_REPLY) {
511                 smbsrv_signing_no_reply(req);
512         }
513
514         /* see if the vuid is valid */
515         if ((flags & NEED_SESS) && !req->session) {
516                 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
517                 /* amazingly, the error code depends on the command */
518                 switch (type) {
519                 case SMBntcreateX:
520                 case SMBntcancel:
521                 case SMBulogoffX:
522                         break;
523                 default:
524                         if (req->smb_conn->config.nt_status_support &&
525                             req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
526                                 status = NT_STATUS_INVALID_HANDLE;
527                         }
528                         break;
529                 }
530                 /* 
531                  * TODO:
532                  * don't know how to handle smb signing for this case 
533                  * so just skip the reply
534                  */
535                 if ((flags & SIGNING_NO_REPLY) &&
536                     (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
537                         DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
538                                 smb_fn_name(type), nt_errstr(status)));
539                         talloc_free(req);
540                         return;
541                 }
542                 smbsrv_send_error(req, status);
543                 return;
544         }
545
546         /* does this protocol need a valid tree connection? */
547         if ((flags & NEED_TCON) && !req->tcon) {
548                 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
549                 /* amazingly, the error code depends on the command */
550                 switch (type) {
551                 case SMBntcreateX:
552                 case SMBntcancel:
553                 case SMBtdis:
554                         break;
555                 default:
556                         if (req->smb_conn->config.nt_status_support &&
557                             req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
558                                 status = NT_STATUS_INVALID_HANDLE;
559                         }
560                         break;
561                 }
562                 /* 
563                  * TODO:
564                  * don't know how to handle smb signing for this case 
565                  * so just skip the reply
566                  */
567                 if ((flags & SIGNING_NO_REPLY) &&
568                     (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
569                         DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
570                                 smb_fn_name(type), nt_errstr(status)));
571                         talloc_free(req);
572                         return;
573                 }
574                 smbsrv_send_error(req, status);
575                 return;
576         }
577
578         smb_messages[type].fn(req);
579 }
580
581 /*
582   we call this when first first part of a possibly chained request has been completed
583   and we need to call the 2nd part, if any
584 */
585 void smbsrv_chain_reply(struct smbsrv_request *req)
586 {
587         uint16_t chain_cmd, chain_offset;
588         uint8_t *vwv, *data;
589         uint16_t wct;
590         uint16_t data_size;
591
592         if (req->in.wct < 2 || req->out.wct < 2) {
593                 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
594                 return;
595         }
596
597         chain_cmd    = CVAL(req->in.vwv, VWV(0));
598         chain_offset = SVAL(req->in.vwv, VWV(1));
599
600         if (chain_cmd == SMB_CHAIN_NONE) {
601                 /* end of chain */
602                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
603                 SSVAL(req->out.vwv, VWV(1), 0);
604                 smbsrv_send_reply(req);
605                 return;
606         }
607
608         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
609                 goto error;
610         }
611
612         wct = CVAL(req->in.hdr, chain_offset);
613         vwv = req->in.hdr + chain_offset + 1;
614
615         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
616                 goto error;
617         }
618
619         data_size = SVAL(vwv, VWV(wct));
620         data = vwv + VWV(wct) + 2;
621
622         if (data + data_size > req->in.buffer + req->in.size) {
623                 goto error;
624         }
625
626         /* all seems legit */
627         req->in.vwv = vwv;
628         req->in.wct = wct;
629         req->in.data = data;
630         req->in.data_size = data_size;
631         req->in.ptr = data;
632
633         /* fix the bufinfo */
634         smbsrv_setup_bufinfo(req);
635
636         req->chain_count++;
637
638         SSVAL(req->out.vwv, VWV(0), chain_cmd);
639         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
640
641         /* cleanup somestuff for the next request */
642         talloc_free(req->ntvfs);
643         req->ntvfs = NULL;
644         talloc_free(req->io_ptr);
645         req->io_ptr = NULL;
646
647         switch_message(chain_cmd, req);
648         return;
649
650 error:
651         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
652         SSVAL(req->out.vwv, VWV(1), 0);
653         smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
654 }
655
656 /*
657  * init the SMB protocol related stuff
658  */
659 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn, struct loadparm_context *lp_ctx)
660 {
661         NTSTATUS status;
662
663         /* now initialise a few default values associated with this smb socket */
664         smb_conn->negotiate.max_send = 0xFFFF;
665
666         /* this is the size that w2k uses, and it appears to be important for
667            good performance */
668         smb_conn->negotiate.max_recv = lp_max_xmit(lp_ctx);
669
670         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
671
672         smb_conn->config.security = lp_security(lp_ctx);
673         smb_conn->config.nt_status_support = lp_nt_status_support(lp_ctx);
674
675         status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
676         NT_STATUS_NOT_OK_RETURN(status);
677
678         status = smbsrv_smb_init_tcons(smb_conn);
679         NT_STATUS_NOT_OK_RETURN(status);
680
681         smbsrv_init_signing(smb_conn);
682
683         return NT_STATUS_OK;
684 }