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 /* see if the vuid is valid */
484 if ((flags & AS_USER) && !req->user_ctx->vuser) {
485 if (!(flags & AS_GUEST)) {
486 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
491 /* does this protocol need to be run as the connected user? */
493 if ((flags & AS_USER) && !change_to_user(req->conn,session_tag)) {
494 if (!(flags & AS_GUEST)) {
495 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
499 /* we'll run it as guest */
504 /* this code is to work around a bug is MS client 3 without
505 introducing a security hole - it needs to be able to do
506 print queue checks as guest if it isn't logged in properly */
507 if (flags & AS_USER) {
511 /* does it need write permission? */
512 if ((flags & NEED_WRITE) && !CAN_WRITE(req->conn)) {
513 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
517 /* ipc services are limited */
518 if (req->conn && req->conn->type == NTVFS_IPC && (flags & AS_USER) && !(flags & CAN_IPC)) {
519 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
523 /* load service specific parameters */
524 if (req->conn && !set_current_service(req->conn,(flags & AS_USER)?True:False)) {
525 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
529 /* does this protocol need to be run as guest? */
531 if ((flags & AS_GUEST) &&
532 !change_to_guest()) {
533 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
537 /* THREAD TESTING: use mutex to serialize calls to critical functions with global state */
538 if (flags & USE_MUTEX) {
539 MUTEX_LOCK_BY_ID(MUTEX_SMBD);
541 smb_messages[type].fn(req);
542 if (flags & USE_MUTEX) {
543 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
548 /****************************************************************************
549 Construct a reply to the incoming packet.
550 ****************************************************************************/
551 static void construct_reply(struct request_context *req)
553 uint8 type = CVAL(req->in.hdr,HDR_COM);
555 /* see if its a special NBT packet */
556 if (CVAL(req->in.buffer,0) != 0) {
562 /* Make sure this is an SMB packet */
563 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
564 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
566 exit_server(req->smb, "Non-SMB packet");
570 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
571 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
572 exit_server(req->smb, "Invalid SMB packet");
576 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
577 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
578 exit_server(req->smb, "Invalid SMB packet");
583 req->smbpid = SVAL(req->in.hdr,HDR_PID);
584 req->flags = CVAL(req->in.hdr, HDR_FLG);
585 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
587 switch_message(type, req);
592 we call this when first first part of a possibly chained request has been completed
593 and we need to call the 2nd part, if any
595 void chain_reply(struct request_context *req)
597 uint16 chain_cmd, chain_offset;
602 if (req->in.wct < 2 || req->out.wct < 2) {
603 req_reply_dos_error(req, ERRSRV, ERRerror);
607 chain_cmd = CVAL(req->in.vwv, VWV(0));
608 chain_offset = SVAL(req->in.vwv, VWV(1));
610 if (chain_cmd == SMB_CHAIN_NONE) {
612 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
613 SSVAL(req->out.vwv, VWV(1), 0);
618 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
622 wct = CVAL(req->in.hdr, chain_offset);
623 vwv = req->in.hdr + chain_offset + 1;
625 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
629 data_size = SVAL(vwv, VWV(wct));
630 data = vwv + VWV(wct) + 2;
632 if (data + data_size > req->in.buffer + req->in.size) {
636 /* all seems legit */
640 req->in.data_size = data_size;
645 SSVAL(req->out.vwv, VWV(0), chain_cmd);
646 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
648 /* the current request in the chain might have used an async reply,
649 but that doesn't mean the next element needs to */
650 ZERO_STRUCT(req->async);
651 req->control_flags &= ~REQ_CONTROL_ASYNC;
653 switch_message(chain_cmd, req);
657 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
658 SSVAL(req->out.vwv, VWV(1), 0);
659 req_reply_dos_error(req, ERRSRV, ERRerror);
664 close the socket and shutdown a server_context
666 void server_terminate(struct server_context *smb)
668 close(smb->socket.fd);
669 event_remove_fd_all(smb->events, smb->socket.fd);
673 talloc_destroy(smb->mem_ctx);
678 called when a SMB socket becomes readable
680 void smbd_read_handler(struct event_context *ev, struct fd_event *fde,
681 time_t t, uint16 flags)
683 struct request_context *req;
684 struct server_context *smb = fde->private;
686 req = receive_smb_request(smb);
688 smb->model_ops->terminate_connection(smb, "receive error");
692 construct_reply(req);
694 /* free up temporary memory */
700 process a message from an SMB socket while still processing a
701 previous message this is used by backends who need to ensure that
702 new messages from clients are still processed while they are
703 performing long operations
705 void smbd_process_async(struct server_context *smb)
707 struct request_context *req;
709 req = receive_smb_request(smb);
711 smb->model_ops->terminate_connection(smb, "receive error");
715 construct_reply(req);
720 initialise a server_context from a open socket and register a event handler
721 for reading from that socket
723 void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int fd,
724 void (*read_handler)(struct event_context *, struct fd_event *, time_t, uint16))
726 struct server_context *smb;
731 set_socket_options(fd,"SO_KEEPALIVE");
732 set_socket_options(fd, lp_socket_options());
734 mem_ctx = talloc_init("server_context");
736 smb = (struct server_context *)talloc(mem_ctx, sizeof(*smb));
741 smb->mem_ctx = mem_ctx;
745 sub_set_context(&smb->substitute);
747 /* set an initial client name based on its IP address. This will be replaced with
748 the netbios name later if it gives us one */
749 socket_addr = get_socket_addr(smb->mem_ctx, fd);
750 sub_set_remote_machine(socket_addr);
751 smb->socket.client_addr = socket_addr;
753 /* now initialise a few default values associated with this smb socket */
754 smb->negotiate.max_send = 0xFFFF;
756 /* this is the size that w2k uses, and it appears to be important for
758 smb->negotiate.max_recv = lp_max_xmit();
760 smb->negotiate.zone_offset = get_time_zone(time(NULL));
762 smb->users.next_vuid = VUID_OFFSET;
765 smb->model_ops = model_ops;
769 /* setup a event handler for this socket. We are initially
770 only interested in reading from the socket */
772 fde.handler = read_handler;
774 fde.flags = EVENT_FD_READ;
776 event_add_fd(ev, &fde);
778 /* setup the DCERPC server subsystem */
779 dcesrv_init_context(&smb->dcesrv);