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