/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- smbsrv_send_oplock_break
- smbsrv_recv_smb_request
- smb_fn_name
- switch_message
- smbsrv_chain_reply
- smbsrv_init_smb_connection
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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 /* 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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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)
/* [<][>][^][v][top][bottom][index][help] */
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 }