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>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 send an oplock break request to a client
28 BOOL req_send_oplock_break(struct tcon_context *conn, uint16 fnum, uint8 level)
30 struct request_context *req;
32 req = init_smb_request(conn->smb);
34 req_setup_reply(req, 8, 0);
36 SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
37 SSVAL(req->out.hdr,HDR_TID,conn->cnum);
38 SSVAL(req->out.hdr,HDR_PID,0xFFFF);
39 SSVAL(req->out.hdr,HDR_UID,0);
40 SSVAL(req->out.hdr,HDR_MID,0xFFFF);
41 SCVAL(req->out.hdr,HDR_FLG,0);
42 SSVAL(req->out.hdr,HDR_FLG2,0);
44 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
45 SSVAL(req->out.vwv, VWV(1), 0);
46 SSVAL(req->out.vwv, VWV(2), fnum);
47 SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
48 SCVAL(req->out.vwv, VWV(3)+1, level);
49 SIVAL(req->out.vwv, VWV(4), 0);
50 SSVAL(req->out.vwv, VWV(6), 0);
51 SSVAL(req->out.vwv, VWV(7), 0);
57 /****************************************************************************
58 receive a SMB request from the wire, forming a request_context from the result
59 ****************************************************************************/
60 static struct request_context *receive_smb_request(struct server_context *smb)
64 struct request_context *req;
66 len = read_data(smb->socket.fd, header, 4);
71 len = smb_len(header);
73 req = init_smb_request(smb);
75 GetTimeOfDay(&req->request_time);
76 req->chained_fnum = -1;
78 /* allocate the incoming buffer at the right size */
79 req->in.buffer = talloc(req->mem_ctx, len + NBT_HDR_SIZE);
81 /* fill in the already received header */
82 memcpy(req->in.buffer, header, 4);
84 len2 = read_data(smb->socket.fd, req->in.buffer + NBT_HDR_SIZE, len);
89 /* fill in the rest of the req->in structure */
90 req->in.size = len + NBT_HDR_SIZE;
91 req->in.allocated = req->in.size;
92 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
93 req->in.vwv = req->in.hdr + HDR_VWV;
94 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
95 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
96 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
97 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
99 /* the bcc length is only 16 bits, but some packets
100 (such as SMBwriteX) can be much larger than 64k. We
101 detect this by looking for a large non-chained NBT
102 packet (at least 64k bigger than what is
103 specified). If it is detected then the NBT size is
104 used instead of the bcc size */
105 if (req->in.data_size + 0x10000 <=
106 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
107 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
108 /* its an oversized packet! fun for all the family */
109 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
117 setup the user_ctx element of a request
119 static void setup_user_context(struct request_context *req)
121 struct user_context *ctx;
123 ctx = talloc(req->mem_ctx, sizeof(*ctx));
124 ctx->vuid = SVAL(req->in.hdr, HDR_UID);
125 ctx->vuser = get_valid_user_struct(req->smb, ctx->vuid);
132 These flags determine some of the permissions required to do an operation
134 Note that I don't set NEED_WRITE on some write operations because they
135 are used by some brain-dead clients when printing, and I don't want to
136 force write permissions on print services.
138 #define AS_USER (1<<0)
139 #define NEED_WRITE (1<<1)
140 #define TIME_INIT (1<<2)
141 #define CAN_IPC (1<<3)
142 #define AS_GUEST (1<<5)
143 #define USE_MUTEX (1<<7)
146 define a list of possible SMB messages and their corresponding
147 functions. Any message that has a NULL function is unimplemented -
148 please feel free to contribute implementations!
150 static const struct smb_message_struct
153 void (*fn)(struct request_context *);
156 smb_messages[256] = {
157 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
158 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
159 /* 0x02 */ { "SMBopen",reply_open,AS_USER },
160 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
161 /* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
162 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
163 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
164 /* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
165 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
166 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
167 /* 0x0a */ { "SMBread",reply_read,AS_USER},
168 /* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
169 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
170 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
171 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
172 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
173 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
174 /* 0x11 */ { "SMBexit",reply_exit,0},
175 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
176 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
177 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
178 /* 0x15 */ { NULL, NULL, 0 },
179 /* 0x16 */ { NULL, NULL, 0 },
180 /* 0x17 */ { NULL, NULL, 0 },
181 /* 0x18 */ { NULL, NULL, 0 },
182 /* 0x19 */ { NULL, NULL, 0 },
183 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
184 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
185 /* 0x1c */ { "SMBreadBs",NULL,0 },
186 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
187 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
188 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
189 /* 0x20 */ { "SMBwritec",NULL,0},
190 /* 0x21 */ { NULL, NULL, 0 },
191 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
192 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
193 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
194 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
195 /* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
196 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
197 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
198 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
199 /* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE },
200 /* 0x2b */ { "SMBecho",reply_echo,0},
201 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
202 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
203 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
204 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
205 /* 0x30 */ { NULL, NULL, 0 },
206 /* 0x31 */ { NULL, NULL, 0 },
207 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
208 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
209 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
210 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
211 /* 0x36 */ { NULL, NULL, 0 },
212 /* 0x37 */ { NULL, NULL, 0 },
213 /* 0x38 */ { NULL, NULL, 0 },
214 /* 0x39 */ { NULL, NULL, 0 },
215 /* 0x3a */ { NULL, NULL, 0 },
216 /* 0x3b */ { NULL, NULL, 0 },
217 /* 0x3c */ { NULL, NULL, 0 },
218 /* 0x3d */ { NULL, NULL, 0 },
219 /* 0x3e */ { NULL, NULL, 0 },
220 /* 0x3f */ { NULL, NULL, 0 },
221 /* 0x40 */ { NULL, NULL, 0 },
222 /* 0x41 */ { NULL, NULL, 0 },
223 /* 0x42 */ { NULL, NULL, 0 },
224 /* 0x43 */ { NULL, NULL, 0 },
225 /* 0x44 */ { NULL, NULL, 0 },
226 /* 0x45 */ { NULL, NULL, 0 },
227 /* 0x46 */ { NULL, NULL, 0 },
228 /* 0x47 */ { NULL, NULL, 0 },
229 /* 0x48 */ { NULL, NULL, 0 },
230 /* 0x49 */ { NULL, NULL, 0 },
231 /* 0x4a */ { NULL, NULL, 0 },
232 /* 0x4b */ { NULL, NULL, 0 },
233 /* 0x4c */ { NULL, NULL, 0 },
234 /* 0x4d */ { NULL, NULL, 0 },
235 /* 0x4e */ { NULL, NULL, 0 },
236 /* 0x4f */ { NULL, NULL, 0 },
237 /* 0x50 */ { NULL, NULL, 0 },
238 /* 0x51 */ { NULL, NULL, 0 },
239 /* 0x52 */ { NULL, NULL, 0 },
240 /* 0x53 */ { NULL, NULL, 0 },
241 /* 0x54 */ { NULL, NULL, 0 },
242 /* 0x55 */ { NULL, NULL, 0 },
243 /* 0x56 */ { NULL, NULL, 0 },
244 /* 0x57 */ { NULL, NULL, 0 },
245 /* 0x58 */ { NULL, NULL, 0 },
246 /* 0x59 */ { NULL, NULL, 0 },
247 /* 0x5a */ { NULL, NULL, 0 },
248 /* 0x5b */ { NULL, NULL, 0 },
249 /* 0x5c */ { NULL, NULL, 0 },
250 /* 0x5d */ { NULL, NULL, 0 },
251 /* 0x5e */ { NULL, NULL, 0 },
252 /* 0x5f */ { NULL, NULL, 0 },
253 /* 0x60 */ { NULL, NULL, 0 },
254 /* 0x61 */ { NULL, NULL, 0 },
255 /* 0x62 */ { NULL, NULL, 0 },
256 /* 0x63 */ { NULL, NULL, 0 },
257 /* 0x64 */ { NULL, NULL, 0 },
258 /* 0x65 */ { NULL, NULL, 0 },
259 /* 0x66 */ { NULL, NULL, 0 },
260 /* 0x67 */ { NULL, NULL, 0 },
261 /* 0x68 */ { NULL, NULL, 0 },
262 /* 0x69 */ { NULL, NULL, 0 },
263 /* 0x6a */ { NULL, NULL, 0 },
264 /* 0x6b */ { NULL, NULL, 0 },
265 /* 0x6c */ { NULL, NULL, 0 },
266 /* 0x6d */ { NULL, NULL, 0 },
267 /* 0x6e */ { NULL, NULL, 0 },
268 /* 0x6f */ { NULL, NULL, 0 },
269 /* 0x70 */ { "SMBtcon",reply_tcon,USE_MUTEX},
270 /* 0x71 */ { "SMBtdis",reply_tdis,0},
271 /* 0x72 */ { "SMBnegprot",reply_negprot,USE_MUTEX},
272 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,USE_MUTEX},
273 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
274 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,USE_MUTEX},
275 /* 0x76 */ { NULL, NULL, 0 },
276 /* 0x77 */ { NULL, NULL, 0 },
277 /* 0x78 */ { NULL, NULL, 0 },
278 /* 0x79 */ { NULL, NULL, 0 },
279 /* 0x7a */ { NULL, NULL, 0 },
280 /* 0x7b */ { NULL, NULL, 0 },
281 /* 0x7c */ { NULL, NULL, 0 },
282 /* 0x7d */ { NULL, NULL, 0 },
283 /* 0x7e */ { NULL, NULL, 0 },
284 /* 0x7f */ { NULL, NULL, 0 },
285 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
286 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
287 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
288 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
289 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
290 /* 0x85 */ { NULL, NULL, 0 },
291 /* 0x86 */ { NULL, NULL, 0 },
292 /* 0x87 */ { NULL, NULL, 0 },
293 /* 0x88 */ { NULL, NULL, 0 },
294 /* 0x89 */ { NULL, NULL, 0 },
295 /* 0x8a */ { NULL, NULL, 0 },
296 /* 0x8b */ { NULL, NULL, 0 },
297 /* 0x8c */ { NULL, NULL, 0 },
298 /* 0x8d */ { NULL, NULL, 0 },
299 /* 0x8e */ { NULL, NULL, 0 },
300 /* 0x8f */ { NULL, NULL, 0 },
301 /* 0x90 */ { NULL, NULL, 0 },
302 /* 0x91 */ { NULL, NULL, 0 },
303 /* 0x92 */ { NULL, NULL, 0 },
304 /* 0x93 */ { NULL, NULL, 0 },
305 /* 0x94 */ { NULL, NULL, 0 },
306 /* 0x95 */ { NULL, NULL, 0 },
307 /* 0x96 */ { NULL, NULL, 0 },
308 /* 0x97 */ { NULL, NULL, 0 },
309 /* 0x98 */ { NULL, NULL, 0 },
310 /* 0x99 */ { NULL, NULL, 0 },
311 /* 0x9a */ { NULL, NULL, 0 },
312 /* 0x9b */ { NULL, NULL, 0 },
313 /* 0x9c */ { NULL, NULL, 0 },
314 /* 0x9d */ { NULL, NULL, 0 },
315 /* 0x9e */ { NULL, NULL, 0 },
316 /* 0x9f */ { NULL, NULL, 0 },
317 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
318 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
319 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC },
320 /* 0xa3 */ { NULL, NULL, 0 },
321 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
322 /* 0xa5 */ { "SMBntrename", reply_ntrename, 0 },
323 /* 0xa6 */ { NULL, NULL, 0 },
324 /* 0xa7 */ { NULL, NULL, 0 },
325 /* 0xa8 */ { NULL, NULL, 0 },
326 /* 0xa9 */ { NULL, NULL, 0 },
327 /* 0xaa */ { NULL, NULL, 0 },
328 /* 0xab */ { NULL, NULL, 0 },
329 /* 0xac */ { NULL, NULL, 0 },
330 /* 0xad */ { NULL, NULL, 0 },
331 /* 0xae */ { NULL, NULL, 0 },
332 /* 0xaf */ { NULL, NULL, 0 },
333 /* 0xb0 */ { NULL, NULL, 0 },
334 /* 0xb1 */ { NULL, NULL, 0 },
335 /* 0xb2 */ { NULL, NULL, 0 },
336 /* 0xb3 */ { NULL, NULL, 0 },
337 /* 0xb4 */ { NULL, NULL, 0 },
338 /* 0xb5 */ { NULL, NULL, 0 },
339 /* 0xb6 */ { NULL, NULL, 0 },
340 /* 0xb7 */ { NULL, NULL, 0 },
341 /* 0xb8 */ { NULL, NULL, 0 },
342 /* 0xb9 */ { NULL, NULL, 0 },
343 /* 0xba */ { NULL, NULL, 0 },
344 /* 0xbb */ { NULL, NULL, 0 },
345 /* 0xbc */ { NULL, NULL, 0 },
346 /* 0xbd */ { NULL, NULL, 0 },
347 /* 0xbe */ { NULL, NULL, 0 },
348 /* 0xbf */ { NULL, NULL, 0 },
349 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
350 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
351 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
352 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
353 /* 0xc4 */ { NULL, NULL, 0 },
354 /* 0xc5 */ { NULL, NULL, 0 },
355 /* 0xc6 */ { NULL, NULL, 0 },
356 /* 0xc7 */ { NULL, NULL, 0 },
357 /* 0xc8 */ { NULL, NULL, 0 },
358 /* 0xc9 */ { NULL, NULL, 0 },
359 /* 0xca */ { NULL, NULL, 0 },
360 /* 0xcb */ { NULL, NULL, 0 },
361 /* 0xcc */ { NULL, NULL, 0 },
362 /* 0xcd */ { NULL, NULL, 0 },
363 /* 0xce */ { NULL, NULL, 0 },
364 /* 0xcf */ { NULL, NULL, 0 },
365 /* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
366 /* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
367 /* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
368 /* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
369 /* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
370 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
371 /* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
372 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
373 /* 0xd8 */ { NULL, NULL, 0 },
374 /* 0xd9 */ { NULL, NULL, 0 },
375 /* 0xda */ { NULL, NULL, 0 },
376 /* 0xdb */ { NULL, NULL, 0 },
377 /* 0xdc */ { NULL, NULL, 0 },
378 /* 0xdd */ { NULL, NULL, 0 },
379 /* 0xde */ { NULL, NULL, 0 },
380 /* 0xdf */ { NULL, NULL, 0 },
381 /* 0xe0 */ { NULL, NULL, 0 },
382 /* 0xe1 */ { NULL, NULL, 0 },
383 /* 0xe2 */ { NULL, NULL, 0 },
384 /* 0xe3 */ { NULL, NULL, 0 },
385 /* 0xe4 */ { NULL, NULL, 0 },
386 /* 0xe5 */ { NULL, NULL, 0 },
387 /* 0xe6 */ { NULL, NULL, 0 },
388 /* 0xe7 */ { NULL, NULL, 0 },
389 /* 0xe8 */ { NULL, NULL, 0 },
390 /* 0xe9 */ { NULL, NULL, 0 },
391 /* 0xea */ { NULL, NULL, 0 },
392 /* 0xeb */ { NULL, NULL, 0 },
393 /* 0xec */ { NULL, NULL, 0 },
394 /* 0xed */ { NULL, NULL, 0 },
395 /* 0xee */ { NULL, NULL, 0 },
396 /* 0xef */ { NULL, NULL, 0 },
397 /* 0xf0 */ { NULL, NULL, 0 },
398 /* 0xf1 */ { NULL, NULL, 0 },
399 /* 0xf2 */ { NULL, NULL, 0 },
400 /* 0xf3 */ { NULL, NULL, 0 },
401 /* 0xf4 */ { NULL, NULL, 0 },
402 /* 0xf5 */ { NULL, NULL, 0 },
403 /* 0xf6 */ { NULL, NULL, 0 },
404 /* 0xf7 */ { NULL, NULL, 0 },
405 /* 0xf8 */ { NULL, NULL, 0 },
406 /* 0xf9 */ { NULL, NULL, 0 },
407 /* 0xfa */ { NULL, NULL, 0 },
408 /* 0xfb */ { NULL, NULL, 0 },
409 /* 0xfc */ { NULL, NULL, 0 },
410 /* 0xfd */ { NULL, NULL, 0 },
411 /* 0xfe */ { NULL, NULL, 0 },
412 /* 0xff */ { NULL, NULL, 0 }
415 /****************************************************************************
416 return a string containing the function name of a SMB command
417 ****************************************************************************/
418 static const char *smb_fn_name(uint8 type)
420 const char *unknown_name = "SMBunknown";
422 if (smb_messages[type].name == NULL)
425 return smb_messages[type].name;
429 /****************************************************************************
430 Do a switch on the message type and call the specific reply function for this
431 message. Unlike earlier versions of Samba the reply functions are responsible
432 for sending the reply themselves, rather than returning a size to this function
433 The reply functions may also choose to delay the processing by pushing the message
434 onto the message queue
435 ****************************************************************************/
436 static void switch_message(int type, struct request_context *req)
440 struct server_context *smb = req->smb;
446 if (smb_messages[type].fn == NULL) {
447 DEBUG(0,("Unknown message type %d!\n",type));
452 flags = smb_messages[type].flags;
454 /* In share mode security we must ignore the vuid. */
455 session_tag = (lp_security() == SEC_SHARE) ?
457 SVAL(req->in.hdr,HDR_UID);
459 req->conn = conn_find(req->smb, SVAL(req->in.hdr,HDR_TID));
461 /* setup the user context for this request */
462 setup_user_context(req);
464 /* Ensure this value is replaced in the incoming packet. */
465 SSVAL(req->in.hdr,HDR_UID,session_tag);
468 req->user_ctx->vuid = session_tag;
470 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb->model_ops->get_id(req)));
472 /* does this protocol need to be run as root? */
473 if (!(flags & AS_USER)) {
474 change_to_root_user();
477 /* does this protocol need a valid tree connection? */
478 if ((flags & AS_USER) && !req->conn) {
479 req_reply_error(req, NT_STATUS_NETWORK_NAME_DELETED);
483 /* does this protocol need to be run as the connected user? */
485 if ((flags & AS_USER) && !change_to_user(req->conn,session_tag)) {
486 if (!(flags & AS_GUEST)) {
487 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
491 /* we'll run it as guest */
496 /* this code is to work around a bug is MS client 3 without
497 introducing a security hole - it needs to be able to do
498 print queue checks as guest if it isn't logged in properly */
499 if (flags & AS_USER) {
503 /* does it need write permission? */
504 if ((flags & NEED_WRITE) && !CAN_WRITE(req->conn)) {
505 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
509 /* ipc services are limited */
510 if (req->conn && req->conn->type == NTVFS_IPC && (flags & AS_USER) && !(flags & CAN_IPC)) {
511 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
515 /* load service specific parameters */
516 if (req->conn && !set_current_service(req->conn,(flags & AS_USER)?True:False)) {
517 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
521 /* does this protocol need to be run as guest? */
523 if ((flags & AS_GUEST) &&
524 !change_to_guest()) {
525 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
529 /* THREAD TESTING: use mutex to serialize calls to critical functions with global state */
530 if (flags & USE_MUTEX) {
531 MUTEX_LOCK_BY_ID(MUTEX_SMBD);
533 smb_messages[type].fn(req);
534 if (flags & USE_MUTEX) {
535 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
540 /****************************************************************************
541 Construct a reply to the incoming packet.
542 ****************************************************************************/
543 static void construct_reply(struct request_context *req)
545 uint8 type = CVAL(req->in.hdr,HDR_COM);
547 /* see if its a special NBT packet */
548 if (CVAL(req->in.buffer,0) != 0) {
554 /* Make sure this is an SMB packet */
555 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
556 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
558 exit_server(req->smb, "Non-SMB packet");
562 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
563 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
564 exit_server(req->smb, "Invalid SMB packet");
568 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
569 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
570 exit_server(req->smb, "Invalid SMB packet");
575 req->smbpid = SVAL(req->in.hdr,HDR_PID);
576 req->flags = CVAL(req->in.hdr, HDR_FLG);
577 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
579 switch_message(type, req);
584 we call this when first first part of a possibly chained request has been completed
585 and we need to call the 2nd part, if any
587 void chain_reply(struct request_context *req)
589 uint16 chain_cmd, chain_offset;
594 if (req->in.wct < 2 || req->out.wct < 2) {
595 req_reply_dos_error(req, ERRSRV, ERRerror);
599 chain_cmd = CVAL(req->in.vwv, VWV(0));
600 chain_offset = SVAL(req->in.vwv, VWV(1));
602 if (chain_cmd == SMB_CHAIN_NONE) {
604 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
605 SSVAL(req->out.vwv, VWV(1), 0);
610 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
614 wct = CVAL(req->in.hdr, chain_offset);
615 vwv = req->in.hdr + chain_offset + 1;
617 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
621 data_size = SVAL(vwv, VWV(wct));
622 data = vwv + VWV(wct) + 2;
624 if (data + data_size > req->in.buffer + req->in.size) {
628 /* all seems legit */
632 req->in.data_size = data_size;
637 SSVAL(req->out.vwv, VWV(0), chain_cmd);
638 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
640 /* the current request in the chain might have used an async reply,
641 but that doesn't mean the next element needs to */
642 ZERO_STRUCT(req->async);
643 req->control_flags &= ~REQ_CONTROL_ASYNC;
645 switch_message(chain_cmd, req);
649 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
650 SSVAL(req->out.vwv, VWV(1), 0);
651 req_reply_dos_error(req, ERRSRV, ERRerror);
656 close the socket and shutdown a server_context
658 void server_terminate(struct server_context *smb)
660 close(smb->socket.fd);
661 event_remove_fd_all(smb->events, smb->socket.fd);
665 talloc_destroy(smb->mem_ctx);
670 called when a SMB socket becomes readable
672 void smbd_read_handler(struct event_context *ev, struct fd_event *fde,
673 time_t t, uint16 flags)
675 struct request_context *req;
676 struct server_context *smb = fde->private;
678 req = receive_smb_request(smb);
680 smb->model_ops->terminate_connection(smb, "receive error");
684 construct_reply(req);
686 /* free up temporary memory */
692 process a message from an SMB socket while still processing a
693 previous message this is used by backends who need to ensure that
694 new messages from clients are still processed while they are
695 performing long operations
697 void smbd_process_async(struct server_context *smb)
699 struct request_context *req;
701 req = receive_smb_request(smb);
703 smb->model_ops->terminate_connection(smb, "receive error");
707 construct_reply(req);
712 initialise a server_context from a open socket and register a event handler
713 for reading from that socket
715 void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int fd,
716 void (*read_handler)(struct event_context *, struct fd_event *, time_t, uint16))
718 struct server_context *smb;
723 set_socket_options(fd,"SO_KEEPALIVE");
724 set_socket_options(fd, lp_socket_options());
726 mem_ctx = talloc_init("server_context");
728 smb = (struct server_context *)talloc(mem_ctx, sizeof(*smb));
733 smb->mem_ctx = mem_ctx;
737 sub_set_context(&smb->substitute);
739 /* set an initial client name based on its IP address. This will be replaced with
740 the netbios name later if it gives us one */
741 socket_addr = get_socket_addr(smb->mem_ctx, fd);
742 sub_set_remote_machine(socket_addr);
743 smb->socket.client_addr = socket_addr;
745 /* now initialise a few default values associated with this smb socket */
746 smb->negotiate.max_send = 0xFFFF;
748 /* this is the size that w2k uses, and it appears to be important for
750 smb->negotiate.max_recv = lp_max_xmit();
752 smb->users.next_vuid = VUID_OFFSET;
755 smb->model_ops = model_ops;
759 /* setup a event handler for this socket. We are initially
760 only interested in reading from the socket */
762 fde.handler = read_handler;
764 fde.flags = EVENT_FD_READ;
766 event_add_fd(ev, &fde);
768 /* setup the DCERPC server subsystem */
769 dcesrv_init_context(&smb->dcesrv);