2 Unix SMB/CIFS implementation.
3 process incoming packets - main loop
4 Copyright (C) Andrew Tridgell 1992-2003
5 Copyright (C) James J Myers 2003 <myersjj@samba.org>
6 Copyright (C) Stefan Metzmacher 2004
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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 send an oplock break request to a client
29 BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
31 struct smbsrv_request *req;
33 req = init_smb_request(tcon->smb_conn);
35 req_setup_reply(req, 8, 0);
37 SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
38 SSVAL(req->out.hdr,HDR_TID,tcon->cnum);
39 SSVAL(req->out.hdr,HDR_PID,0xFFFF);
40 SSVAL(req->out.hdr,HDR_UID,0);
41 SSVAL(req->out.hdr,HDR_MID,0xFFFF);
42 SCVAL(req->out.hdr,HDR_FLG,0);
43 SSVAL(req->out.hdr,HDR_FLG2,0);
45 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
46 SSVAL(req->out.vwv, VWV(1), 0);
47 SSVAL(req->out.vwv, VWV(2), fnum);
48 SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
49 SCVAL(req->out.vwv, VWV(3)+1, level);
50 SIVAL(req->out.vwv, VWV(4), 0);
51 SSVAL(req->out.vwv, VWV(6), 0);
52 SSVAL(req->out.vwv, VWV(7), 0);
58 /****************************************************************************
59 receive a SMB request from the wire, forming a request_context from the result
60 ****************************************************************************/
61 static struct smbsrv_request *receive_smb_request(struct smbsrv_connection *smb_conn)
66 struct smbsrv_request *req;
68 status = socket_recv(smb_conn->connection->socket, smb_conn, &tmp_blob, 4, SOCKET_FLAG_BLOCK|SOCKET_FLAG_PEEK);
69 if (!NT_STATUS_IS_OK(status)) {
72 if (tmp_blob.length != 4) {
76 len = smb_len(tmp_blob.data);
77 talloc_free(tmp_blob.data);
79 req = init_smb_request(smb_conn);
81 GetTimeOfDay(&req->request_time);
82 req->chained_fnum = -1;
84 len2 = len + NBT_HDR_SIZE;
86 status = socket_recv(smb_conn->connection->socket, req, &tmp_blob, len2, SOCKET_FLAG_BLOCK);
87 if (!NT_STATUS_IS_OK(status)) {
90 if (tmp_blob.length != len2) {
94 /* fill in the rest of the req->in structure */
95 req->in.buffer = tmp_blob.data;
97 req->in.allocated = req->in.size;
98 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
99 req->in.vwv = req->in.hdr + HDR_VWV;
100 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
101 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
102 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
103 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
105 /* the bcc length is only 16 bits, but some packets
106 (such as SMBwriteX) can be much larger than 64k. We
107 detect this by looking for a large non-chained NBT
108 packet (at least 64k bigger than what is
109 specified). If it is detected then the NBT size is
110 used instead of the bcc size */
111 if (req->in.data_size + 0x10000 <=
112 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
113 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
114 /* its an oversized packet! fun for all the family */
115 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
123 These flags determine some of the permissions required to do an operation
125 Note that I don't set NEED_WRITE on some write operations because they
126 are used by some brain-dead clients when printing, and I don't want to
127 force write permissions on print services.
129 #define AS_USER (1<<0)
130 #define NEED_WRITE (1<<1)
131 #define TIME_INIT (1<<2)
132 #define CAN_IPC (1<<3)
133 #define AS_GUEST (1<<5)
134 #define USE_MUTEX (1<<7)
137 define a list of possible SMB messages and their corresponding
138 functions. Any message that has a NULL function is unimplemented -
139 please feel free to contribute implementations!
141 static const struct smb_message_struct
144 void (*fn)(struct smbsrv_request *);
147 smb_messages[256] = {
148 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
149 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
150 /* 0x02 */ { "SMBopen",reply_open,AS_USER },
151 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
152 /* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
153 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
154 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
155 /* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
156 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
157 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
158 /* 0x0a */ { "SMBread",reply_read,AS_USER},
159 /* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
160 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
161 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
162 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
163 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
164 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
165 /* 0x11 */ { "SMBexit",reply_exit,0},
166 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
167 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
168 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
169 /* 0x15 */ { NULL, NULL, 0 },
170 /* 0x16 */ { NULL, NULL, 0 },
171 /* 0x17 */ { NULL, NULL, 0 },
172 /* 0x18 */ { NULL, NULL, 0 },
173 /* 0x19 */ { NULL, NULL, 0 },
174 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
175 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
176 /* 0x1c */ { "SMBreadBs",NULL,0 },
177 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
178 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
179 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
180 /* 0x20 */ { "SMBwritec",NULL,0},
181 /* 0x21 */ { NULL, NULL, 0 },
182 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
183 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
184 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
185 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
186 /* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
187 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
188 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
189 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
190 /* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE },
191 /* 0x2b */ { "SMBecho",reply_echo,0},
192 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
193 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
194 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
195 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
196 /* 0x30 */ { NULL, NULL, 0 },
197 /* 0x31 */ { NULL, NULL, 0 },
198 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
199 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
200 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
201 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
202 /* 0x36 */ { NULL, NULL, 0 },
203 /* 0x37 */ { NULL, NULL, 0 },
204 /* 0x38 */ { NULL, NULL, 0 },
205 /* 0x39 */ { NULL, NULL, 0 },
206 /* 0x3a */ { NULL, NULL, 0 },
207 /* 0x3b */ { NULL, NULL, 0 },
208 /* 0x3c */ { NULL, NULL, 0 },
209 /* 0x3d */ { NULL, NULL, 0 },
210 /* 0x3e */ { NULL, NULL, 0 },
211 /* 0x3f */ { NULL, NULL, 0 },
212 /* 0x40 */ { NULL, NULL, 0 },
213 /* 0x41 */ { NULL, NULL, 0 },
214 /* 0x42 */ { NULL, NULL, 0 },
215 /* 0x43 */ { NULL, NULL, 0 },
216 /* 0x44 */ { NULL, NULL, 0 },
217 /* 0x45 */ { NULL, NULL, 0 },
218 /* 0x46 */ { NULL, NULL, 0 },
219 /* 0x47 */ { NULL, NULL, 0 },
220 /* 0x48 */ { NULL, NULL, 0 },
221 /* 0x49 */ { NULL, NULL, 0 },
222 /* 0x4a */ { NULL, NULL, 0 },
223 /* 0x4b */ { NULL, NULL, 0 },
224 /* 0x4c */ { NULL, NULL, 0 },
225 /* 0x4d */ { NULL, NULL, 0 },
226 /* 0x4e */ { NULL, NULL, 0 },
227 /* 0x4f */ { NULL, NULL, 0 },
228 /* 0x50 */ { NULL, NULL, 0 },
229 /* 0x51 */ { NULL, NULL, 0 },
230 /* 0x52 */ { NULL, NULL, 0 },
231 /* 0x53 */ { NULL, NULL, 0 },
232 /* 0x54 */ { NULL, NULL, 0 },
233 /* 0x55 */ { NULL, NULL, 0 },
234 /* 0x56 */ { NULL, NULL, 0 },
235 /* 0x57 */ { NULL, NULL, 0 },
236 /* 0x58 */ { NULL, NULL, 0 },
237 /* 0x59 */ { NULL, NULL, 0 },
238 /* 0x5a */ { NULL, NULL, 0 },
239 /* 0x5b */ { NULL, NULL, 0 },
240 /* 0x5c */ { NULL, NULL, 0 },
241 /* 0x5d */ { NULL, NULL, 0 },
242 /* 0x5e */ { NULL, NULL, 0 },
243 /* 0x5f */ { NULL, NULL, 0 },
244 /* 0x60 */ { NULL, NULL, 0 },
245 /* 0x61 */ { NULL, NULL, 0 },
246 /* 0x62 */ { NULL, NULL, 0 },
247 /* 0x63 */ { NULL, NULL, 0 },
248 /* 0x64 */ { NULL, NULL, 0 },
249 /* 0x65 */ { NULL, NULL, 0 },
250 /* 0x66 */ { NULL, NULL, 0 },
251 /* 0x67 */ { NULL, NULL, 0 },
252 /* 0x68 */ { NULL, NULL, 0 },
253 /* 0x69 */ { NULL, NULL, 0 },
254 /* 0x6a */ { NULL, NULL, 0 },
255 /* 0x6b */ { NULL, NULL, 0 },
256 /* 0x6c */ { NULL, NULL, 0 },
257 /* 0x6d */ { NULL, NULL, 0 },
258 /* 0x6e */ { NULL, NULL, 0 },
259 /* 0x6f */ { NULL, NULL, 0 },
260 /* 0x70 */ { "SMBtcon",reply_tcon,USE_MUTEX},
261 /* 0x71 */ { "SMBtdis",reply_tdis,0},
262 /* 0x72 */ { "SMBnegprot",reply_negprot,USE_MUTEX},
263 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,USE_MUTEX},
264 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
265 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,USE_MUTEX},
266 /* 0x76 */ { NULL, NULL, 0 },
267 /* 0x77 */ { NULL, NULL, 0 },
268 /* 0x78 */ { NULL, NULL, 0 },
269 /* 0x79 */ { NULL, NULL, 0 },
270 /* 0x7a */ { NULL, NULL, 0 },
271 /* 0x7b */ { NULL, NULL, 0 },
272 /* 0x7c */ { NULL, NULL, 0 },
273 /* 0x7d */ { NULL, NULL, 0 },
274 /* 0x7e */ { NULL, NULL, 0 },
275 /* 0x7f */ { NULL, NULL, 0 },
276 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
277 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
278 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
279 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
280 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
281 /* 0x85 */ { NULL, NULL, 0 },
282 /* 0x86 */ { NULL, NULL, 0 },
283 /* 0x87 */ { NULL, NULL, 0 },
284 /* 0x88 */ { NULL, NULL, 0 },
285 /* 0x89 */ { NULL, NULL, 0 },
286 /* 0x8a */ { NULL, NULL, 0 },
287 /* 0x8b */ { NULL, NULL, 0 },
288 /* 0x8c */ { NULL, NULL, 0 },
289 /* 0x8d */ { NULL, NULL, 0 },
290 /* 0x8e */ { NULL, NULL, 0 },
291 /* 0x8f */ { NULL, NULL, 0 },
292 /* 0x90 */ { NULL, NULL, 0 },
293 /* 0x91 */ { NULL, NULL, 0 },
294 /* 0x92 */ { NULL, NULL, 0 },
295 /* 0x93 */ { NULL, NULL, 0 },
296 /* 0x94 */ { NULL, NULL, 0 },
297 /* 0x95 */ { NULL, NULL, 0 },
298 /* 0x96 */ { NULL, NULL, 0 },
299 /* 0x97 */ { NULL, NULL, 0 },
300 /* 0x98 */ { NULL, NULL, 0 },
301 /* 0x99 */ { NULL, NULL, 0 },
302 /* 0x9a */ { NULL, NULL, 0 },
303 /* 0x9b */ { NULL, NULL, 0 },
304 /* 0x9c */ { NULL, NULL, 0 },
305 /* 0x9d */ { NULL, NULL, 0 },
306 /* 0x9e */ { NULL, NULL, 0 },
307 /* 0x9f */ { NULL, NULL, 0 },
308 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
309 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
310 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC },
311 /* 0xa3 */ { NULL, NULL, 0 },
312 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
313 /* 0xa5 */ { "SMBntrename", reply_ntrename, 0 },
314 /* 0xa6 */ { NULL, NULL, 0 },
315 /* 0xa7 */ { NULL, NULL, 0 },
316 /* 0xa8 */ { NULL, NULL, 0 },
317 /* 0xa9 */ { NULL, NULL, 0 },
318 /* 0xaa */ { NULL, NULL, 0 },
319 /* 0xab */ { NULL, NULL, 0 },
320 /* 0xac */ { NULL, NULL, 0 },
321 /* 0xad */ { NULL, NULL, 0 },
322 /* 0xae */ { NULL, NULL, 0 },
323 /* 0xaf */ { NULL, NULL, 0 },
324 /* 0xb0 */ { NULL, NULL, 0 },
325 /* 0xb1 */ { NULL, NULL, 0 },
326 /* 0xb2 */ { NULL, NULL, 0 },
327 /* 0xb3 */ { NULL, NULL, 0 },
328 /* 0xb4 */ { NULL, NULL, 0 },
329 /* 0xb5 */ { NULL, NULL, 0 },
330 /* 0xb6 */ { NULL, NULL, 0 },
331 /* 0xb7 */ { NULL, NULL, 0 },
332 /* 0xb8 */ { NULL, NULL, 0 },
333 /* 0xb9 */ { NULL, NULL, 0 },
334 /* 0xba */ { NULL, NULL, 0 },
335 /* 0xbb */ { NULL, NULL, 0 },
336 /* 0xbc */ { NULL, NULL, 0 },
337 /* 0xbd */ { NULL, NULL, 0 },
338 /* 0xbe */ { NULL, NULL, 0 },
339 /* 0xbf */ { NULL, NULL, 0 },
340 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
341 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
342 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
343 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
344 /* 0xc4 */ { NULL, NULL, 0 },
345 /* 0xc5 */ { NULL, NULL, 0 },
346 /* 0xc6 */ { NULL, NULL, 0 },
347 /* 0xc7 */ { NULL, NULL, 0 },
348 /* 0xc8 */ { NULL, NULL, 0 },
349 /* 0xc9 */ { NULL, NULL, 0 },
350 /* 0xca */ { NULL, NULL, 0 },
351 /* 0xcb */ { NULL, NULL, 0 },
352 /* 0xcc */ { NULL, NULL, 0 },
353 /* 0xcd */ { NULL, NULL, 0 },
354 /* 0xce */ { NULL, NULL, 0 },
355 /* 0xcf */ { NULL, NULL, 0 },
356 /* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
357 /* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
358 /* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
359 /* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
360 /* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
361 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
362 /* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
363 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
364 /* 0xd8 */ { NULL, NULL, 0 },
365 /* 0xd9 */ { NULL, NULL, 0 },
366 /* 0xda */ { NULL, NULL, 0 },
367 /* 0xdb */ { NULL, NULL, 0 },
368 /* 0xdc */ { NULL, NULL, 0 },
369 /* 0xdd */ { NULL, NULL, 0 },
370 /* 0xde */ { NULL, NULL, 0 },
371 /* 0xdf */ { NULL, NULL, 0 },
372 /* 0xe0 */ { NULL, NULL, 0 },
373 /* 0xe1 */ { NULL, NULL, 0 },
374 /* 0xe2 */ { NULL, NULL, 0 },
375 /* 0xe3 */ { NULL, NULL, 0 },
376 /* 0xe4 */ { NULL, NULL, 0 },
377 /* 0xe5 */ { NULL, NULL, 0 },
378 /* 0xe6 */ { NULL, NULL, 0 },
379 /* 0xe7 */ { NULL, NULL, 0 },
380 /* 0xe8 */ { NULL, NULL, 0 },
381 /* 0xe9 */ { NULL, NULL, 0 },
382 /* 0xea */ { NULL, NULL, 0 },
383 /* 0xeb */ { NULL, NULL, 0 },
384 /* 0xec */ { NULL, NULL, 0 },
385 /* 0xed */ { NULL, NULL, 0 },
386 /* 0xee */ { NULL, NULL, 0 },
387 /* 0xef */ { NULL, NULL, 0 },
388 /* 0xf0 */ { NULL, NULL, 0 },
389 /* 0xf1 */ { NULL, NULL, 0 },
390 /* 0xf2 */ { NULL, NULL, 0 },
391 /* 0xf3 */ { NULL, NULL, 0 },
392 /* 0xf4 */ { NULL, NULL, 0 },
393 /* 0xf5 */ { NULL, NULL, 0 },
394 /* 0xf6 */ { NULL, NULL, 0 },
395 /* 0xf7 */ { NULL, NULL, 0 },
396 /* 0xf8 */ { NULL, NULL, 0 },
397 /* 0xf9 */ { NULL, NULL, 0 },
398 /* 0xfa */ { NULL, NULL, 0 },
399 /* 0xfb */ { NULL, NULL, 0 },
400 /* 0xfc */ { NULL, NULL, 0 },
401 /* 0xfd */ { NULL, NULL, 0 },
402 /* 0xfe */ { NULL, NULL, 0 },
403 /* 0xff */ { NULL, NULL, 0 }
406 /****************************************************************************
407 return a string containing the function name of a SMB command
408 ****************************************************************************/
409 static const char *smb_fn_name(uint8_t type)
411 const char *unknown_name = "SMBunknown";
413 if (smb_messages[type].name == NULL)
416 return smb_messages[type].name;
420 /****************************************************************************
421 Do a switch on the message type and call the specific reply function for this
422 message. Unlike earlier versions of Samba the reply functions are responsible
423 for sending the reply themselves, rather than returning a size to this function
424 The reply functions may also choose to delay the processing by pushing the message
425 onto the message queue
426 ****************************************************************************/
427 static void switch_message(int type, struct smbsrv_request *req)
430 struct smbsrv_connection *smb_conn = req->smb_conn;
431 uint16_t session_tag;
437 if (smb_messages[type].fn == NULL) {
438 DEBUG(0,("Unknown message type %d!\n",type));
443 flags = smb_messages[type].flags;
445 req->tcon = conn_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
447 if (req->session == NULL) {
448 /* setup the user context for this request if it
449 hasn't already been initialised (to cope with SMB
452 /* In share mode security we must ignore the vuid. */
453 if (lp_security() == SEC_SHARE) {
454 session_tag = UID_FIELD_INVALID;
456 session_tag = SVAL(req->in.hdr,HDR_UID);
459 req->session = smbsrv_session_find(req->smb_conn, session_tag);
461 req->session->vuid = session_tag;
464 session_tag = req->session->vuid;
467 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb_conn->connection->service->model_ops->get_id(req)));
469 /* does this protocol need to be run as root? */
470 if (!(flags & AS_USER)) {
471 change_to_root_user();
474 /* does this protocol need a valid tree connection? */
475 if ((flags & AS_USER) && !req->tcon) {
476 req_reply_error(req, NT_STATUS_INVALID_HANDLE);
480 /* see if the vuid is valid */
481 if ((flags & AS_USER) && !req->session) {
482 if (!(flags & AS_GUEST)) {
483 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
488 /* does this protocol need to be run as the connected user? */
490 if ((flags & AS_USER) && !change_to_user(req->tcon,session_tag)) {
491 if (!(flags & AS_GUEST)) {
492 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
496 /* we'll run it as guest */
501 /* this code is to work around a bug is MS client 3 without
502 introducing a security hole - it needs to be able to do
503 print queue checks as guest if it isn't logged in properly */
504 if (flags & AS_USER) {
508 /* does it need write permission? */
509 if ((flags & NEED_WRITE) && !CAN_WRITE(req->tcon)) {
510 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
514 /* ipc services are limited */
515 if (req->tcon && req->tcon->ntvfs_ctx->type == NTVFS_IPC && (flags & AS_USER) && !(flags & CAN_IPC)) {
516 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
520 /* load service specific parameters */
521 if (req->tcon && !set_current_service(req->tcon,(flags & AS_USER)?True:False)) {
522 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
526 /* does this protocol need to be run as guest? */
528 if ((flags & AS_GUEST) &&
529 !change_to_guest()) {
530 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
534 /* THREAD TESTING: use mutex to serialize calls to critical functions with global state */
535 if (flags & USE_MUTEX) {
536 MUTEX_LOCK_BY_ID(MUTEX_SMBD);
538 smb_messages[type].fn(req);
539 if (flags & USE_MUTEX) {
540 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
545 /****************************************************************************
546 Construct a reply to the incoming packet.
547 ****************************************************************************/
548 static void construct_reply(struct smbsrv_request *req)
550 uint8_t type = CVAL(req->in.hdr,HDR_COM);
552 /* see if its a special NBT packet */
553 if (CVAL(req->in.buffer,0) != 0) {
558 /* Make sure this is an SMB packet */
559 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
560 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
562 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
566 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
567 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
568 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
572 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
573 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
574 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
579 req->smbpid = SVAL(req->in.hdr,HDR_PID);
580 req->flags = CVAL(req->in.hdr, HDR_FLG);
581 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
583 if (!req_signing_check_incoming(req)) {
584 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
588 switch_message(type, req);
593 we call this when first first part of a possibly chained request has been completed
594 and we need to call the 2nd part, if any
596 void chain_reply(struct smbsrv_request *req)
598 uint16_t chain_cmd, chain_offset;
603 if (req->in.wct < 2 || req->out.wct < 2) {
604 req_reply_dos_error(req, ERRSRV, ERRerror);
608 chain_cmd = CVAL(req->in.vwv, VWV(0));
609 chain_offset = SVAL(req->in.vwv, VWV(1));
611 if (chain_cmd == SMB_CHAIN_NONE) {
613 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
614 SSVAL(req->out.vwv, VWV(1), 0);
619 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
623 wct = CVAL(req->in.hdr, chain_offset);
624 vwv = req->in.hdr + chain_offset + 1;
626 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
630 data_size = SVAL(vwv, VWV(wct));
631 data = vwv + VWV(wct) + 2;
633 if (data + data_size > req->in.buffer + req->in.size) {
637 /* all seems legit */
641 req->in.data_size = data_size;
646 SSVAL(req->out.vwv, VWV(0), chain_cmd);
647 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
649 /* the current request in the chain might have used an async reply,
650 but that doesn't mean the next element needs to */
651 ZERO_STRUCT(req->async);
652 req->control_flags &= ~REQ_CONTROL_ASYNC;
654 switch_message(chain_cmd, req);
658 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
659 SSVAL(req->out.vwv, VWV(1), 0);
660 req_reply_dos_error(req, ERRSRV, ERRerror);
665 close the socket and shutdown a server_context
667 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
669 server_terminate_connection(smb_conn->connection, reason);
673 called on a fatal error that should cause this server to terminate
675 static void smbsrv_exit(struct server_service *service, const char *reason)
677 DEBUG(1,("smbsrv_exit\n"));
682 add a socket address to the list of events, one event per port
684 static void add_socket(struct server_service *service,
685 const struct model_ops *model_ops,
686 struct socket_context *socket_ctx,
687 struct in_addr *ifip)
689 const char **ports = lp_smb_ports();
691 char *ip_str = talloc_strdup(service, inet_ntoa(*ifip));
693 for (i=0;ports[i];i++) {
694 uint16_t port = atoi(ports[i]);
695 if (port == 0) continue;
696 service_setup_socket(service, model_ops, "ipv4", ip_str, &port);
702 /****************************************************************************
703 Open the socket communication.
704 ****************************************************************************/
705 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
707 DEBUG(1,("smbsrv_init\n"));
709 if (lp_interfaces() && lp_bind_interfaces_only()) {
710 int num_interfaces = iface_count();
713 /* We have been given an interfaces line, and been
714 told to only bind to those interfaces. Create a
715 socket per interface and bind to only these.
717 for(i = 0; i < num_interfaces; i++) {
718 struct in_addr *ifip = iface_n_ip(i);
721 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
725 add_socket(service, model_ops, NULL, ifip);
729 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
730 ifip = interpret_addr2(lp_socket_address());
731 add_socket(service, model_ops, NULL, &ifip);
736 called when a SMB socket becomes readable
738 static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
740 struct smbsrv_request *req;
741 struct smbsrv_connection *smb_conn = conn->private_data;
743 DEBUG(10,("smbsrv_recv\n"));
745 req = receive_smb_request(smb_conn);
747 conn->event.fde->flags = 0;
748 smbsrv_terminate_connection(smb_conn, "receive error");
752 construct_reply(req);
754 /* free up temporary memory */
760 called when a SMB socket becomes writable
762 static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
764 DEBUG(10,("smbsrv_send\n"));
769 called when connection is idle
771 static void smbsrv_idle(struct server_connection *conn, time_t t)
773 DEBUG(10,("smbsrv_idle: not implemented!\n"));
774 conn->event.idle->next_event = t + 5;
779 static void smbsrv_close(struct server_connection *conn, const char *reason)
781 struct smbsrv_connection *smb_conn = conn->private_data;
783 DEBUG(5,("smbsrv_close: %s\n",reason));
785 conn_close_all(smb_conn);
787 talloc_free(smb_conn);
793 process a message from an SMB socket while still processing a
794 previous message this is used by backends who need to ensure that
795 new messages from clients are still processed while they are
796 performing long operations
798 void smbd_process_async(struct smbsrv_connection *smb_conn)
800 struct smbsrv_request *req;
802 req = receive_smb_request(smb_conn);
804 smbsrv_terminate_connection(smb_conn, "receive error");
808 construct_reply(req);
813 initialise a server_context from a open socket and register a event handler
814 for reading from that socket
816 void smbsrv_accept(struct server_connection *conn)
818 struct smbsrv_connection *smb_conn;
821 DEBUG(5,("smbsrv_accept\n"));
823 smb_conn = talloc_p(conn, struct smbsrv_connection);
824 if (!smb_conn) return;
826 ZERO_STRUCTP(smb_conn);
828 smb_conn->pid = getpid();
830 sub_set_context(&smb_conn->substitute);
832 /* now initialise a few default values associated with this smb socket */
833 smb_conn->negotiate.max_send = 0xFFFF;
835 /* this is the size that w2k uses, and it appears to be important for
837 smb_conn->negotiate.max_recv = lp_max_xmit();
839 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
841 smb_conn->sessions.next_vuid = VUID_OFFSET;
843 srv_init_signing(smb_conn);
847 smb_conn->connection = conn;
849 conn->private_data = smb_conn;
851 fd = socket_get_fd(conn->socket);
852 set_blocking(fd, True);
854 /* setup the DCERPC server subsystem */
855 dcesrv_init_context(smb_conn, &smb_conn->dcesrv);
860 static const struct server_service_ops smb_server_ops = {
862 .service_init = smbsrv_init,
863 .accept_connection = smbsrv_accept,
864 .recv_handler = smbsrv_recv,
865 .send_handler = smbsrv_send,
866 .idle_handler = smbsrv_idle,
867 .close_connection = smbsrv_close,
868 .service_exit = smbsrv_exit,
871 const struct server_service_ops *smbsrv_get_ops(void)
873 return &smb_server_ops;
876 NTSTATUS server_service_smb_init(void)