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