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
, 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();
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 /* 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");
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");
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
);
445 command
= CVAL(req
->in
.hdr
, HDR_COM
);
446 switch_message(command
, req
);
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
)
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
)
474 struct smbsrv_connection
*smb_conn
= req
->smb_conn
;
481 if (smb_messages
[type
].fn
== NULL
) {
482 DEBUG(0,("Unknown message type %d!\n",type
));
483 smbsrv_reply_unknown(req
);
487 flags
= smb_messages
[type
].flags
;
489 req
->tcon
= smbsrv_smb_tcon_find(smb_conn
, SVAL(req
->in
.hdr
,HDR_TID
), req
->request_time
);
492 /* setup the user context for this request if it
493 hasn't already been initialised (to cope with SMB
496 /* In share mode security we must ignore the vuid. */
497 if (smb_conn
->config
.security
== SEC_SHARE
) {
499 req
->session
= req
->tcon
->sec_share
.session
;
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 */
524 if (req
->smb_conn
->config
.nt_status_support
&&
525 req
->smb_conn
->negotiate
.client_caps
& CAP_STATUS32
) {
526 status
= NT_STATUS_INVALID_HANDLE
;
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
)));
542 smbsrv_send_error(req
, status
);
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 */
556 if (req
->smb_conn
->config
.nt_status_support
&&
557 req
->smb_conn
->negotiate
.client_caps
& CAP_STATUS32
) {
558 status
= NT_STATUS_INVALID_HANDLE
;
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
)));
574 smbsrv_send_error(req
, status
);
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
;
592 if (req
->in
.wct
< 2 || req
->out
.wct
< 2) {
593 smbsrv_send_error(req
, NT_STATUS_DOS(ERRSRV
, ERRerror
));
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
) {
602 SSVAL(req
->out
.vwv
, VWV(0), SMB_CHAIN_NONE
);
603 SSVAL(req
->out
.vwv
, VWV(1), 0);
604 smbsrv_send_reply(req
);
608 if (chain_offset
+ req
->in
.hdr
>= req
->in
.buffer
+ req
->in
.size
) {
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
) {
619 data_size
= SVAL(vwv
, VWV(wct
));
620 data
= vwv
+ VWV(wct
) + 2;
622 if (data
+ data_size
> req
->in
.buffer
+ req
->in
.size
) {
626 /* all seems legit */
630 req
->in
.data_size
= data_size
;
633 /* fix the bufinfo */
634 smbsrv_setup_bufinfo(req
);
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
);
644 talloc_free(req
->io_ptr
);
647 switch_message(chain_cmd
, req
);
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
)
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
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
);