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 SSVAL(req->out.vwv, VWV(3), level);
48 SIVAL(req->out.vwv, VWV(4), 0);
49 SSVAL(req->out.vwv, VWV(6), 0);
50 SSVAL(req->out.vwv, VWV(7), 0);
56 /****************************************************************************
57 receive a SMB request from the wire, forming a request_context from the result
58 ****************************************************************************/
59 static struct request_context *receive_smb_request(struct server_context *smb)
63 struct request_context *req;
65 len = read_data(smb->socket.fd, header, 4);
70 len = smb_len(header);
72 req = init_smb_request(smb);
74 GetTimeOfDay(&req->request_time);
75 req->chained_fnum = -1;
77 /* allocate the incoming buffer at the right size */
78 req->in.buffer = talloc(req->mem_ctx, len + NBT_HDR_SIZE);
80 /* fill in the already received header */
81 memcpy(req->in.buffer, header, 4);
83 len2 = read_data(smb->socket.fd, req->in.buffer + NBT_HDR_SIZE, len);
88 /* fill in the rest of the req->in structure */
89 req->in.size = len + NBT_HDR_SIZE;
90 req->in.allocated = req->in.size;
91 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
92 req->in.vwv = req->in.hdr + HDR_VWV;
93 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
94 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
95 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
96 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
98 /* the bcc length is only 16 bits, but some packets
99 (such as SMBwriteX) can be much larger than 64k. We
100 detect this by looking for a large non-chained NBT
101 packet (at least 64k bigger than what is
102 specified). If it is detected then the NBT size is
103 used instead of the bcc size */
104 if (req->in.data_size + 0x10000 <=
105 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
106 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
107 /* its an oversized packet! fun for all the family */
108 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
116 setup the user_ctx element of a request
118 static void setup_user_context(struct request_context *req)
120 struct user_context *ctx;
122 ctx = talloc(req->mem_ctx, sizeof(*ctx));
123 ctx->vuid = SVAL(req->in.hdr, HDR_UID);
124 ctx->vuser = get_valid_user_struct(req->smb, ctx->vuid);
131 These flags determine some of the permissions required to do an operation
133 Note that I don't set NEED_WRITE on some write operations because they
134 are used by some brain-dead clients when printing, and I don't want to
135 force write permissions on print services.
137 #define AS_USER (1<<0)
138 #define NEED_WRITE (1<<1)
139 #define TIME_INIT (1<<2)
140 #define CAN_IPC (1<<3)
141 #define AS_GUEST (1<<5)
142 #define USE_MUTEX (1<<7)
145 define a list of possible SMB messages and their corresponding
146 functions. Any message that has a NULL function is unimplemented -
147 please feel free to contribute implementations!
149 static const struct smb_message_struct
152 void (*fn)(struct request_context *);
155 smb_messages[256] = {
156 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
157 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
158 /* 0x02 */ { "SMBopen",reply_open,AS_USER },
159 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
160 /* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
161 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
162 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
163 /* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
164 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
165 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
166 /* 0x0a */ { "SMBread",reply_read,AS_USER},
167 /* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
168 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
169 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
170 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
171 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
172 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
173 /* 0x11 */ { "SMBexit",reply_exit,0},
174 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
175 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
176 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
177 /* 0x15 */ { NULL, NULL, 0 },
178 /* 0x16 */ { NULL, NULL, 0 },
179 /* 0x17 */ { NULL, NULL, 0 },
180 /* 0x18 */ { NULL, NULL, 0 },
181 /* 0x19 */ { NULL, NULL, 0 },
182 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
183 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
184 /* 0x1c */ { "SMBreadBs",NULL,0 },
185 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
186 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
187 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
188 /* 0x20 */ { "SMBwritec",NULL,0},
189 /* 0x21 */ { NULL, NULL, 0 },
190 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
191 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
192 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
193 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
194 /* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
195 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
196 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
197 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
198 /* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE },
199 /* 0x2b */ { "SMBecho",reply_echo,0},
200 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
201 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
202 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
203 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
204 /* 0x30 */ { NULL, NULL, 0 },
205 /* 0x31 */ { NULL, NULL, 0 },
206 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
207 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
208 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
209 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
210 /* 0x36 */ { NULL, NULL, 0 },
211 /* 0x37 */ { NULL, NULL, 0 },
212 /* 0x38 */ { NULL, NULL, 0 },
213 /* 0x39 */ { NULL, NULL, 0 },
214 /* 0x3a */ { NULL, NULL, 0 },
215 /* 0x3b */ { NULL, NULL, 0 },
216 /* 0x3c */ { NULL, NULL, 0 },
217 /* 0x3d */ { NULL, NULL, 0 },
218 /* 0x3e */ { NULL, NULL, 0 },
219 /* 0x3f */ { NULL, NULL, 0 },
220 /* 0x40 */ { NULL, NULL, 0 },
221 /* 0x41 */ { NULL, NULL, 0 },
222 /* 0x42 */ { NULL, NULL, 0 },
223 /* 0x43 */ { NULL, NULL, 0 },
224 /* 0x44 */ { NULL, NULL, 0 },
225 /* 0x45 */ { NULL, NULL, 0 },
226 /* 0x46 */ { NULL, NULL, 0 },
227 /* 0x47 */ { NULL, NULL, 0 },
228 /* 0x48 */ { NULL, NULL, 0 },
229 /* 0x49 */ { NULL, NULL, 0 },
230 /* 0x4a */ { NULL, NULL, 0 },
231 /* 0x4b */ { NULL, NULL, 0 },
232 /* 0x4c */ { NULL, NULL, 0 },
233 /* 0x4d */ { NULL, NULL, 0 },
234 /* 0x4e */ { NULL, NULL, 0 },
235 /* 0x4f */ { NULL, NULL, 0 },
236 /* 0x50 */ { NULL, NULL, 0 },
237 /* 0x51 */ { NULL, NULL, 0 },
238 /* 0x52 */ { NULL, NULL, 0 },
239 /* 0x53 */ { NULL, NULL, 0 },
240 /* 0x54 */ { NULL, NULL, 0 },
241 /* 0x55 */ { NULL, NULL, 0 },
242 /* 0x56 */ { NULL, NULL, 0 },
243 /* 0x57 */ { NULL, NULL, 0 },
244 /* 0x58 */ { NULL, NULL, 0 },
245 /* 0x59 */ { NULL, NULL, 0 },
246 /* 0x5a */ { NULL, NULL, 0 },
247 /* 0x5b */ { NULL, NULL, 0 },
248 /* 0x5c */ { NULL, NULL, 0 },
249 /* 0x5d */ { NULL, NULL, 0 },
250 /* 0x5e */ { NULL, NULL, 0 },
251 /* 0x5f */ { NULL, NULL, 0 },
252 /* 0x60 */ { NULL, NULL, 0 },
253 /* 0x61 */ { NULL, NULL, 0 },
254 /* 0x62 */ { NULL, NULL, 0 },
255 /* 0x63 */ { NULL, NULL, 0 },
256 /* 0x64 */ { NULL, NULL, 0 },
257 /* 0x65 */ { NULL, NULL, 0 },
258 /* 0x66 */ { NULL, NULL, 0 },
259 /* 0x67 */ { NULL, NULL, 0 },
260 /* 0x68 */ { NULL, NULL, 0 },
261 /* 0x69 */ { NULL, NULL, 0 },
262 /* 0x6a */ { NULL, NULL, 0 },
263 /* 0x6b */ { NULL, NULL, 0 },
264 /* 0x6c */ { NULL, NULL, 0 },
265 /* 0x6d */ { NULL, NULL, 0 },
266 /* 0x6e */ { NULL, NULL, 0 },
267 /* 0x6f */ { NULL, NULL, 0 },
268 /* 0x70 */ { "SMBtcon",reply_tcon,USE_MUTEX},
269 /* 0x71 */ { "SMBtdis",reply_tdis,0},
270 /* 0x72 */ { "SMBnegprot",reply_negprot,USE_MUTEX},
271 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,USE_MUTEX},
272 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
273 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,USE_MUTEX},
274 /* 0x76 */ { NULL, NULL, 0 },
275 /* 0x77 */ { NULL, NULL, 0 },
276 /* 0x78 */ { NULL, NULL, 0 },
277 /* 0x79 */ { NULL, NULL, 0 },
278 /* 0x7a */ { NULL, NULL, 0 },
279 /* 0x7b */ { NULL, NULL, 0 },
280 /* 0x7c */ { NULL, NULL, 0 },
281 /* 0x7d */ { NULL, NULL, 0 },
282 /* 0x7e */ { NULL, NULL, 0 },
283 /* 0x7f */ { NULL, NULL, 0 },
284 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
285 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
286 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
287 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
288 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
289 /* 0x85 */ { NULL, NULL, 0 },
290 /* 0x86 */ { NULL, NULL, 0 },
291 /* 0x87 */ { NULL, NULL, 0 },
292 /* 0x88 */ { NULL, NULL, 0 },
293 /* 0x89 */ { NULL, NULL, 0 },
294 /* 0x8a */ { NULL, NULL, 0 },
295 /* 0x8b */ { NULL, NULL, 0 },
296 /* 0x8c */ { NULL, NULL, 0 },
297 /* 0x8d */ { NULL, NULL, 0 },
298 /* 0x8e */ { NULL, NULL, 0 },
299 /* 0x8f */ { NULL, NULL, 0 },
300 /* 0x90 */ { NULL, NULL, 0 },
301 /* 0x91 */ { NULL, NULL, 0 },
302 /* 0x92 */ { NULL, NULL, 0 },
303 /* 0x93 */ { NULL, NULL, 0 },
304 /* 0x94 */ { NULL, NULL, 0 },
305 /* 0x95 */ { NULL, NULL, 0 },
306 /* 0x96 */ { NULL, NULL, 0 },
307 /* 0x97 */ { NULL, NULL, 0 },
308 /* 0x98 */ { NULL, NULL, 0 },
309 /* 0x99 */ { NULL, NULL, 0 },
310 /* 0x9a */ { NULL, NULL, 0 },
311 /* 0x9b */ { NULL, NULL, 0 },
312 /* 0x9c */ { NULL, NULL, 0 },
313 /* 0x9d */ { NULL, NULL, 0 },
314 /* 0x9e */ { NULL, NULL, 0 },
315 /* 0x9f */ { NULL, NULL, 0 },
316 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
317 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
318 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC },
319 /* 0xa3 */ { NULL, NULL, 0 },
320 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
321 /* 0xa5 */ { "SMBntrename", reply_ntrename, 0 },
322 /* 0xa6 */ { NULL, NULL, 0 },
323 /* 0xa7 */ { NULL, NULL, 0 },
324 /* 0xa8 */ { NULL, NULL, 0 },
325 /* 0xa9 */ { NULL, NULL, 0 },
326 /* 0xaa */ { NULL, NULL, 0 },
327 /* 0xab */ { NULL, NULL, 0 },
328 /* 0xac */ { NULL, NULL, 0 },
329 /* 0xad */ { NULL, NULL, 0 },
330 /* 0xae */ { NULL, NULL, 0 },
331 /* 0xaf */ { NULL, NULL, 0 },
332 /* 0xb0 */ { NULL, NULL, 0 },
333 /* 0xb1 */ { NULL, NULL, 0 },
334 /* 0xb2 */ { NULL, NULL, 0 },
335 /* 0xb3 */ { NULL, NULL, 0 },
336 /* 0xb4 */ { NULL, NULL, 0 },
337 /* 0xb5 */ { NULL, NULL, 0 },
338 /* 0xb6 */ { NULL, NULL, 0 },
339 /* 0xb7 */ { NULL, NULL, 0 },
340 /* 0xb8 */ { NULL, NULL, 0 },
341 /* 0xb9 */ { NULL, NULL, 0 },
342 /* 0xba */ { NULL, NULL, 0 },
343 /* 0xbb */ { NULL, NULL, 0 },
344 /* 0xbc */ { NULL, NULL, 0 },
345 /* 0xbd */ { NULL, NULL, 0 },
346 /* 0xbe */ { NULL, NULL, 0 },
347 /* 0xbf */ { NULL, NULL, 0 },
348 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
349 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
350 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
351 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
352 /* 0xc4 */ { NULL, NULL, 0 },
353 /* 0xc5 */ { NULL, NULL, 0 },
354 /* 0xc6 */ { NULL, NULL, 0 },
355 /* 0xc7 */ { NULL, NULL, 0 },
356 /* 0xc8 */ { NULL, NULL, 0 },
357 /* 0xc9 */ { NULL, NULL, 0 },
358 /* 0xca */ { NULL, NULL, 0 },
359 /* 0xcb */ { NULL, NULL, 0 },
360 /* 0xcc */ { NULL, NULL, 0 },
361 /* 0xcd */ { NULL, NULL, 0 },
362 /* 0xce */ { NULL, NULL, 0 },
363 /* 0xcf */ { NULL, NULL, 0 },
364 /* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
365 /* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
366 /* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
367 /* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
368 /* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
369 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
370 /* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
371 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
372 /* 0xd8 */ { NULL, NULL, 0 },
373 /* 0xd9 */ { NULL, NULL, 0 },
374 /* 0xda */ { NULL, NULL, 0 },
375 /* 0xdb */ { NULL, NULL, 0 },
376 /* 0xdc */ { NULL, NULL, 0 },
377 /* 0xdd */ { NULL, NULL, 0 },
378 /* 0xde */ { NULL, NULL, 0 },
379 /* 0xdf */ { NULL, NULL, 0 },
380 /* 0xe0 */ { NULL, NULL, 0 },
381 /* 0xe1 */ { NULL, NULL, 0 },
382 /* 0xe2 */ { NULL, NULL, 0 },
383 /* 0xe3 */ { NULL, NULL, 0 },
384 /* 0xe4 */ { NULL, NULL, 0 },
385 /* 0xe5 */ { NULL, NULL, 0 },
386 /* 0xe6 */ { NULL, NULL, 0 },
387 /* 0xe7 */ { NULL, NULL, 0 },
388 /* 0xe8 */ { NULL, NULL, 0 },
389 /* 0xe9 */ { NULL, NULL, 0 },
390 /* 0xea */ { NULL, NULL, 0 },
391 /* 0xeb */ { NULL, NULL, 0 },
392 /* 0xec */ { NULL, NULL, 0 },
393 /* 0xed */ { NULL, NULL, 0 },
394 /* 0xee */ { NULL, NULL, 0 },
395 /* 0xef */ { NULL, NULL, 0 },
396 /* 0xf0 */ { NULL, NULL, 0 },
397 /* 0xf1 */ { NULL, NULL, 0 },
398 /* 0xf2 */ { NULL, NULL, 0 },
399 /* 0xf3 */ { NULL, NULL, 0 },
400 /* 0xf4 */ { NULL, NULL, 0 },
401 /* 0xf5 */ { NULL, NULL, 0 },
402 /* 0xf6 */ { NULL, NULL, 0 },
403 /* 0xf7 */ { NULL, NULL, 0 },
404 /* 0xf8 */ { NULL, NULL, 0 },
405 /* 0xf9 */ { NULL, NULL, 0 },
406 /* 0xfa */ { NULL, NULL, 0 },
407 /* 0xfb */ { NULL, NULL, 0 },
408 /* 0xfc */ { NULL, NULL, 0 },
409 /* 0xfd */ { NULL, NULL, 0 },
410 /* 0xfe */ { NULL, NULL, 0 },
411 /* 0xff */ { NULL, NULL, 0 }
414 /****************************************************************************
415 return a string containing the function name of a SMB command
416 ****************************************************************************/
417 static const char *smb_fn_name(uint8 type)
419 const char *unknown_name = "SMBunknown";
421 if (smb_messages[type].name == NULL)
424 return smb_messages[type].name;
428 /****************************************************************************
429 Do a switch on the message type and call the specific reply function for this
430 message. Unlike earlier versions of Samba the reply functions are responsible
431 for sending the reply themselves, rather than returning a size to this function
432 The reply functions may also choose to delay the processing by pushing the message
433 onto the message queue
434 ****************************************************************************/
435 static void switch_message(int type, struct request_context *req)
439 struct server_context *smb = req->smb;
445 if (smb_messages[type].fn == NULL) {
446 DEBUG(0,("Unknown message type %d!\n",type));
451 flags = smb_messages[type].flags;
453 /* In share mode security we must ignore the vuid. */
454 session_tag = (lp_security() == SEC_SHARE) ?
456 SVAL(req->in.hdr,HDR_UID);
458 req->conn = conn_find(req->smb, SVAL(req->in.hdr,HDR_TID));
460 /* setup the user context for this request */
461 setup_user_context(req);
463 /* Ensure this value is replaced in the incoming packet. */
464 SSVAL(req->in.hdr,HDR_UID,session_tag);
467 req->user_ctx->vuid = session_tag;
469 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb->model_ops->get_id(req)));
471 /* does this protocol need to be run as root? */
472 if (!(flags & AS_USER)) {
473 change_to_root_user();
476 /* does this protocol need a valid tree connection? */
477 if ((flags & AS_USER) && !req->conn) {
478 req_reply_error(req, NT_STATUS_NETWORK_NAME_DELETED);
482 /* does this protocol need to be run as the connected user? */
484 if ((flags & AS_USER) && !change_to_user(req->conn,session_tag)) {
485 if (!(flags & AS_GUEST)) {
486 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
490 /* we'll run it as guest */
495 /* this code is to work around a bug is MS client 3 without
496 introducing a security hole - it needs to be able to do
497 print queue checks as guest if it isn't logged in properly */
498 if (flags & AS_USER) {
502 /* does it need write permission? */
503 if ((flags & NEED_WRITE) && !CAN_WRITE(req->conn)) {
504 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
508 /* ipc services are limited */
509 if (req->conn && req->conn->type == NTVFS_IPC && (flags & AS_USER) && !(flags & CAN_IPC)) {
510 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
514 /* load service specific parameters */
515 if (req->conn && !set_current_service(req->conn,(flags & AS_USER)?True:False)) {
516 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
520 /* does this protocol need to be run as guest? */
522 if ((flags & AS_GUEST) &&
523 !change_to_guest()) {
524 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
528 /* THREAD TESTING: use mutex to serialize calls to critical functions with global state */
529 if (flags & USE_MUTEX) {
530 MUTEX_LOCK_BY_ID(MUTEX_SMBD);
532 smb_messages[type].fn(req);
533 if (flags & USE_MUTEX) {
534 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
539 /****************************************************************************
540 Construct a reply to the incoming packet.
541 ****************************************************************************/
542 static void construct_reply(struct request_context *req)
544 uint8 type = CVAL(req->in.hdr,HDR_COM);
546 /* see if its a special NBT packet */
547 if (CVAL(req->in.buffer,0) != 0) {
553 /* Make sure this is an SMB packet */
554 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
555 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
557 exit_server(req->smb, "Non-SMB packet");
561 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
562 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
563 exit_server(req->smb, "Invalid SMB packet");
567 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
568 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
569 exit_server(req->smb, "Invalid SMB packet");
574 req->smbpid = SVAL(req->in.hdr,HDR_PID);
575 req->flags = CVAL(req->in.hdr, HDR_FLG);
576 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
578 switch_message(type, req);
583 we call this when first first part of a possibly chained request has been completed
584 and we need to call the 2nd part, if any
586 void chain_reply(struct request_context *req)
588 uint16 chain_cmd, chain_offset;
593 if (req->in.wct < 2 || req->out.wct < 2) {
594 req_reply_dos_error(req, ERRSRV, ERRerror);
598 chain_cmd = CVAL(req->in.vwv, VWV(0));
599 chain_offset = SVAL(req->in.vwv, VWV(1));
601 if (chain_cmd == SMB_CHAIN_NONE) {
603 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
604 SSVAL(req->out.vwv, VWV(1), 0);
609 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
613 wct = CVAL(req->in.hdr, chain_offset);
614 vwv = req->in.hdr + chain_offset + 1;
616 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
620 data_size = SVAL(vwv, VWV(wct));
621 data = vwv + VWV(wct) + 2;
623 if (data + data_size > req->in.buffer + req->in.size) {
627 /* all seems legit */
631 req->in.data_size = data_size;
636 SSVAL(req->out.vwv, VWV(0), chain_cmd);
637 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
639 /* the current request in the chain might have used an async reply,
640 but that doesn't mean the next element needs to */
641 ZERO_STRUCT(req->async);
642 req->control_flags &= ~REQ_CONTROL_ASYNC;
644 switch_message(chain_cmd, req);
648 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
649 SSVAL(req->out.vwv, VWV(1), 0);
650 req_reply_dos_error(req, ERRSRV, ERRerror);
655 close the socket and shutdown a server_context
657 void server_terminate(struct server_context *smb)
659 close(smb->socket.fd);
660 event_remove_fd_all(smb->events, smb->socket.fd);
664 talloc_destroy(smb->mem_ctx);
669 called when a SMB socket becomes readable
671 void smbd_read_handler(struct event_context *ev, struct fd_event *fde,
672 time_t t, uint16 flags)
674 struct request_context *req;
675 struct server_context *smb = fde->private;
677 req = receive_smb_request(smb);
679 smb->model_ops->terminate_connection(smb, "receive error");
683 construct_reply(req);
685 /* free up temporary memory */
691 process a message from an SMB socket while still processing a
692 previous message this is used by backends who need to ensure that
693 new messages from clients are still processed while they are
694 performing long operations
696 void smbd_process_async(struct server_context *smb)
698 struct request_context *req;
700 req = receive_smb_request(smb);
702 smb->model_ops->terminate_connection(smb, "receive error");
706 construct_reply(req);
711 initialise a server_context from a open socket and register a event handler
712 for reading from that socket
714 void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int fd,
715 void (*read_handler)(struct event_context *, struct fd_event *, time_t, uint16))
717 struct server_context *smb;
722 set_socket_options(fd,"SO_KEEPALIVE");
723 set_socket_options(fd, lp_socket_options());
725 mem_ctx = talloc_init("server_context");
727 smb = (struct server_context *)talloc(mem_ctx, sizeof(*smb));
732 smb->mem_ctx = mem_ctx;
736 sub_set_context(&smb->substitute);
738 /* set an initial client name based on its IP address. This will be replaced with
739 the netbios name later if it gives us one */
740 socket_addr = get_socket_addr(smb->mem_ctx, fd);
741 sub_set_remote_machine(socket_addr);
742 smb->socket.client_addr = socket_addr;
744 /* now initialise a few default values associated with this smb socket */
745 smb->negotiate.max_send = 0xFFFF;
747 /* this is the size that w2k uses, and it appears to be important for
749 smb->negotiate.max_recv = lp_max_xmit();
751 smb->users.next_vuid = VUID_OFFSET;
754 smb->model_ops = model_ops;
758 /* setup a event handler for this socket. We are initially
759 only interested in reading from the socket */
761 fde.handler = read_handler;
763 fde.flags = EVENT_FD_READ;
765 event_add_fd(ev, &fde);
767 /* setup the DCERPC server subsystem */
768 dcesrv_init_context(&smb->dcesrv);