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
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.
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.
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/>.
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"
33 send an oplock break request to a client
35 NTSTATUS smbsrv_send_oplock_break(void *p, struct ntvfs_handle *ntvfs, uint8_t level)
37 struct smbsrv_tcon *tcon = talloc_get_type(p, struct smbsrv_tcon);
38 struct smbsrv_request *req;
40 req = smbsrv_init_request(tcon->smb_conn);
41 NT_STATUS_HAVE_NO_MEMORY(req);
43 smbsrv_setup_reply(req, 8, 0);
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);
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);
62 smbsrv_send_reply(req);
66 static void switch_message(int type, struct smbsrv_request *req);
69 These flags determine some of the permissions required to do an operation
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 */
76 /* The 64Kb question: are requests > 64K valid? */
77 #define LARGE_REQUEST (1<<4)
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!
84 static const struct smb_message_struct
87 void (*fn)(struct smbsrv_request *);
88 #define message_flags(type) smb_messages[(type) & 0xff].flags
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 }
350 /****************************************************************************
351 receive a SMB request header from the wire, forming a request_context
353 ****************************************************************************/
354 NTSTATUS smbsrv_recv_smb_request(void *private, DATA_BLOB blob)
356 struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
357 struct smbsrv_request *req;
358 struct timeval cur_time = timeval_current();
361 smb_conn->statistics.last_request_time = cur_time;
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);
368 ZERO_STRUCT(req->in);
370 req->in.buffer = talloc_steal(req, blob.data);
371 req->in.size = blob.length;
372 req->request_time = cur_time;
374 smbsrv_reply_special(req);
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");
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",
388 smbsrv_terminate_connection(smb_conn, "Non-SMB packet");
392 req = smbsrv_init_request(smb_conn);
393 NT_STATUS_HAVE_NO_MEMORY(req);
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);
404 command = CVAL(req->in.hdr, HDR_COM);
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));
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) )
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);
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");
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");
440 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
442 /* fix the bufinfo */
443 smbsrv_setup_bufinfo(req);
445 if (!smbsrv_signing_check_incoming(req)) {
446 smbsrv_send_error(req, NT_STATUS_ACCESS_DENIED);
450 command = CVAL(req->in.hdr, HDR_COM);
451 switch_message(command, req);
455 /****************************************************************************
456 return a string containing the function name of a SMB command
457 ****************************************************************************/
458 static const char *smb_fn_name(uint8_t type)
460 const char *unknown_name = "SMBunknown";
462 if (smb_messages[type].name == NULL)
465 return smb_messages[type].name;
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)
479 struct smbsrv_connection *smb_conn = req->smb_conn;
486 if (smb_messages[type].fn == NULL) {
487 DEBUG(0,("Unknown message type %d!\n",type));
488 smbsrv_reply_unknown(req);
492 flags = smb_messages[type].flags;
494 req->tcon = smbsrv_smb_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID), req->request_time);
497 /* setup the user context for this request if it
498 hasn't already been initialised (to cope with SMB
501 /* In share mode security we must ignore the vuid. */
502 if (smb_conn->config.security == SEC_SHARE) {
504 req->session = req->tcon->sec_share.session;
507 req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID), req->request_time);
511 DEBUG(5,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id.id));
513 /* this must be called before we do any reply */
514 if (flags & SIGNING_NO_REPLY) {
515 smbsrv_signing_no_reply(req);
518 /* see if the vuid is valid */
519 if ((flags & NEED_SESS) && !req->session) {
520 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
521 /* amazingly, the error code depends on the command */
528 if (req->smb_conn->config.nt_status_support &&
529 req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
530 status = NT_STATUS_INVALID_HANDLE;
536 * don't know how to handle smb signing for this case
537 * so just skip the reply
539 if ((flags & SIGNING_NO_REPLY) &&
540 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
541 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
542 smb_fn_name(type), nt_errstr(status)));
546 smbsrv_send_error(req, status);
550 /* does this protocol need a valid tree connection? */
551 if ((flags & NEED_TCON) && !req->tcon) {
552 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
553 /* amazingly, the error code depends on the command */
560 if (req->smb_conn->config.nt_status_support &&
561 req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
562 status = NT_STATUS_INVALID_HANDLE;
568 * don't know how to handle smb signing for this case
569 * so just skip the reply
571 if ((flags & SIGNING_NO_REPLY) &&
572 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
573 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
574 smb_fn_name(type), nt_errstr(status)));
578 smbsrv_send_error(req, status);
582 smb_messages[type].fn(req);
586 we call this when first first part of a possibly chained request has been completed
587 and we need to call the 2nd part, if any
589 void smbsrv_chain_reply(struct smbsrv_request *req)
591 uint16_t chain_cmd, chain_offset;
596 if (req->in.wct < 2 || req->out.wct < 2) {
597 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
601 chain_cmd = CVAL(req->in.vwv, VWV(0));
602 chain_offset = SVAL(req->in.vwv, VWV(1));
604 if (chain_cmd == SMB_CHAIN_NONE) {
606 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
607 SSVAL(req->out.vwv, VWV(1), 0);
608 smbsrv_send_reply(req);
612 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
616 wct = CVAL(req->in.hdr, chain_offset);
617 vwv = req->in.hdr + chain_offset + 1;
619 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
623 data_size = SVAL(vwv, VWV(wct));
624 data = vwv + VWV(wct) + 2;
626 if (data + data_size > req->in.buffer + req->in.size) {
630 /* all seems legit */
634 req->in.data_size = data_size;
637 /* fix the bufinfo */
638 smbsrv_setup_bufinfo(req);
642 SSVAL(req->out.vwv, VWV(0), chain_cmd);
643 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
645 /* cleanup somestuff for the next request */
646 talloc_free(req->ntvfs);
648 talloc_free(req->io_ptr);
651 switch_message(chain_cmd, req);
655 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
656 SSVAL(req->out.vwv, VWV(1), 0);
657 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
661 * init the SMB protocol related stuff
663 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn, struct loadparm_context *lp_ctx)
667 /* now initialise a few default values associated with this smb socket */
668 smb_conn->negotiate.max_send = 0xFFFF;
670 /* this is the size that w2k uses, and it appears to be important for
672 smb_conn->negotiate.max_recv = lp_max_xmit(lp_ctx);
674 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
676 smb_conn->config.security = lp_security(lp_ctx);
677 smb_conn->config.nt_status_support = lp_nt_status_support(lp_ctx);
679 status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
680 NT_STATUS_NOT_OK_RETURN(status);
682 status = smbsrv_smb_init_tcons(smb_conn);
683 NT_STATUS_NOT_OK_RETURN(status);
685 smbsrv_init_signing(smb_conn);