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