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