idl: rebuild drsuapi.idl
[Samba/aatanasov.git] / source4 / smb_server / smb / receive.c
blob9a039095e67f4777e0e825b744d06f3ccc277f66
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
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/>.
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"
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);
63 return NT_STATUS_OK;
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 */
75 #define AND_X (1<<3)
76 /* The 64Kb question: are requests > 64K valid? */
77 #define LARGE_REQUEST (1<<4)
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!
84 static const struct smb_message_struct
86 const char *name;
87 void (*fn)(struct smbsrv_request *);
88 #define message_flags(type) smb_messages[(type) & 0xff].flags
89 int flags;
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 }
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)
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;
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);
375 return NT_STATUS_OK;
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;
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;
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 /* special handling for oversize calls. Windows seems
411 to take the maximum of the BCC value and the
412 computed buffer size. This handles oversized writeX
413 calls, and possibly oversized SMBtrans calls */
414 if ((message_flags(command) & LARGE_REQUEST) &&
415 ( !(message_flags(command) & AND_X) ||
416 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) &&
417 req->in.data_size < req->in.size - PTR_DIFF(req->in.data,req->in.buffer)) {
418 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
422 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
423 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
424 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
425 return NT_STATUS_OK;
428 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
429 DEBUG(2,("Invalid SMB buffer length count %d\n",
430 (int)req->in.data_size));
431 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
432 return NT_STATUS_OK;
435 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
437 /* fix the bufinfo */
438 smbsrv_setup_bufinfo(req);
440 if (!smbsrv_signing_check_incoming(req)) {
441 smbsrv_send_error(req, NT_STATUS_ACCESS_DENIED);
442 return NT_STATUS_OK;
445 command = CVAL(req->in.hdr, HDR_COM);
446 switch_message(command, req);
447 return NT_STATUS_OK;
450 /****************************************************************************
451 return a string containing the function name of a SMB command
452 ****************************************************************************/
453 static const char *smb_fn_name(uint8_t type)
455 const char *unknown_name = "SMBunknown";
457 if (smb_messages[type].name == NULL)
458 return unknown_name;
460 return smb_messages[type].name;
464 /****************************************************************************
465 Do a switch on the message type and call the specific reply function for this
466 message. Unlike earlier versions of Samba the reply functions are responsible
467 for sending the reply themselves, rather than returning a size to this function
468 The reply functions may also choose to delay the processing by pushing the message
469 onto the message queue
470 ****************************************************************************/
471 static void switch_message(int type, struct smbsrv_request *req)
473 int flags;
474 struct smbsrv_connection *smb_conn = req->smb_conn;
475 NTSTATUS status;
477 type &= 0xff;
479 errno = 0;
481 if (smb_messages[type].fn == NULL) {
482 DEBUG(0,("Unknown message type %d!\n",type));
483 smbsrv_reply_unknown(req);
484 return;
487 flags = smb_messages[type].flags;
489 req->tcon = smbsrv_smb_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID), req->request_time);
491 if (!req->session) {
492 /* setup the user context for this request if it
493 hasn't already been initialised (to cope with SMB
494 chaining) */
496 /* In share mode security we must ignore the vuid. */
497 if (smb_conn->config.security == SEC_SHARE) {
498 if (req->tcon) {
499 req->session = req->tcon->sec_share.session;
501 } else {
502 req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID), req->request_time);
506 DEBUG(5,("switch message %s (task_id %u)\n",
507 smb_fn_name(type), (unsigned)req->smb_conn->connection->server_id.id));
509 /* this must be called before we do any reply */
510 if (flags & SIGNING_NO_REPLY) {
511 smbsrv_signing_no_reply(req);
514 /* see if the vuid is valid */
515 if ((flags & NEED_SESS) && !req->session) {
516 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
517 /* amazingly, the error code depends on the command */
518 switch (type) {
519 case SMBntcreateX:
520 case SMBntcancel:
521 case SMBulogoffX:
522 break;
523 default:
524 if (req->smb_conn->config.nt_status_support &&
525 req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
526 status = NT_STATUS_INVALID_HANDLE;
528 break;
531 * TODO:
532 * don't know how to handle smb signing for this case
533 * so just skip the reply
535 if ((flags & SIGNING_NO_REPLY) &&
536 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
537 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
538 smb_fn_name(type), nt_errstr(status)));
539 talloc_free(req);
540 return;
542 smbsrv_send_error(req, status);
543 return;
546 /* does this protocol need a valid tree connection? */
547 if ((flags & NEED_TCON) && !req->tcon) {
548 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
549 /* amazingly, the error code depends on the command */
550 switch (type) {
551 case SMBntcreateX:
552 case SMBntcancel:
553 case SMBtdis:
554 break;
555 default:
556 if (req->smb_conn->config.nt_status_support &&
557 req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
558 status = NT_STATUS_INVALID_HANDLE;
560 break;
563 * TODO:
564 * don't know how to handle smb signing for this case
565 * so just skip the reply
567 if ((flags & SIGNING_NO_REPLY) &&
568 (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
569 DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
570 smb_fn_name(type), nt_errstr(status)));
571 talloc_free(req);
572 return;
574 smbsrv_send_error(req, status);
575 return;
578 smb_messages[type].fn(req);
582 we call this when first first part of a possibly chained request has been completed
583 and we need to call the 2nd part, if any
585 void smbsrv_chain_reply(struct smbsrv_request *req)
587 uint16_t chain_cmd, chain_offset;
588 uint8_t *vwv, *data;
589 uint16_t wct;
590 uint16_t data_size;
592 if (req->in.wct < 2 || req->out.wct < 2) {
593 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
594 return;
597 chain_cmd = CVAL(req->in.vwv, VWV(0));
598 chain_offset = SVAL(req->in.vwv, VWV(1));
600 if (chain_cmd == SMB_CHAIN_NONE) {
601 /* end of chain */
602 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
603 SSVAL(req->out.vwv, VWV(1), 0);
604 smbsrv_send_reply(req);
605 return;
608 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
609 goto error;
612 wct = CVAL(req->in.hdr, chain_offset);
613 vwv = req->in.hdr + chain_offset + 1;
615 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
616 goto error;
619 data_size = SVAL(vwv, VWV(wct));
620 data = vwv + VWV(wct) + 2;
622 if (data + data_size > req->in.buffer + req->in.size) {
623 goto error;
626 /* all seems legit */
627 req->in.vwv = vwv;
628 req->in.wct = wct;
629 req->in.data = data;
630 req->in.data_size = data_size;
631 req->in.ptr = data;
633 /* fix the bufinfo */
634 smbsrv_setup_bufinfo(req);
636 req->chain_count++;
638 SSVAL(req->out.vwv, VWV(0), chain_cmd);
639 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
641 /* cleanup somestuff for the next request */
642 talloc_free(req->ntvfs);
643 req->ntvfs = NULL;
644 talloc_free(req->io_ptr);
645 req->io_ptr = NULL;
647 switch_message(chain_cmd, req);
648 return;
650 error:
651 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
652 SSVAL(req->out.vwv, VWV(1), 0);
653 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
657 * init the SMB protocol related stuff
659 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn, struct loadparm_context *lp_ctx)
661 NTSTATUS status;
663 /* now initialise a few default values associated with this smb socket */
664 smb_conn->negotiate.max_send = 0xFFFF;
666 /* this is the size that w2k uses, and it appears to be important for
667 good performance */
668 smb_conn->negotiate.max_recv = lp_max_xmit(lp_ctx);
670 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
672 smb_conn->config.security = lp_security(lp_ctx);
673 smb_conn->config.nt_status_support = lp_nt_status_support(lp_ctx);
675 status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
676 NT_STATUS_NOT_OK_RETURN(status);
678 status = smbsrv_smb_init_tcons(smb_conn);
679 NT_STATUS_NOT_OK_RETURN(status);
681 smbsrv_init_signing(smb_conn);
683 return NT_STATUS_OK;