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.
24 SIG_ATOMIC_T reload_after_sighup = 0;
25 SIG_ATOMIC_T got_sig_term = 0;
28 send an oplock break request to a client
30 BOOL req_send_oplock_break(struct tcon_context *conn, uint16 fnum, uint8 level)
32 struct request_context *req;
34 req = init_smb_request(conn->smb);
36 req_setup_reply(req, 8, 0);
38 SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
39 SSVAL(req->out.hdr,HDR_TID,conn->cnum);
40 SSVAL(req->out.hdr,HDR_PID,0xFFFF);
41 SSVAL(req->out.hdr,HDR_UID,0);
42 SSVAL(req->out.hdr,HDR_MID,0xFFFF);
43 SCVAL(req->out.hdr,HDR_FLG,0);
44 SSVAL(req->out.hdr,HDR_FLG2,0);
46 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
47 SSVAL(req->out.vwv, VWV(1), 0);
48 SSVAL(req->out.vwv, VWV(2), fnum);
49 SSVAL(req->out.vwv, VWV(3), 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 request_context *receive_smb_request(struct server_context *smb)
65 struct request_context *req;
67 len = read_data(smb->socket.fd, header, 4);
72 len = smb_len(header);
74 req = init_smb_request(smb);
76 GetTimeOfDay(&req->request_time);
77 req->chained_fnum = -1;
79 /* allocate the incoming buffer at the right size */
80 req->in.buffer = talloc(req->mem_ctx, len + NBT_HDR_SIZE);
82 /* fill in the already received header */
83 memcpy(req->in.buffer, header, 4);
85 len2 = read_data(smb->socket.fd, req->in.buffer + NBT_HDR_SIZE, len);
90 /* fill in the rest of the req->in structure */
91 req->in.size = len + NBT_HDR_SIZE;
92 req->in.allocated = req->in.size;
93 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
94 req->in.vwv = req->in.hdr + HDR_VWV;
95 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
96 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
97 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
98 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
100 /* the bcc length is only 16 bits, but some packets
101 (such as SMBwriteX) can be much larger than 64k. We
102 detect this by looking for a large non-chained NBT
103 packet (at least 64k bigger than what is
104 specified). If it is detected then the NBT size is
105 used instead of the bcc size */
106 if (req->in.data_size + 0x10000 <=
107 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
108 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
109 /* its an oversized packet! fun for all the family */
110 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
118 setup the user_ctx element of a request
120 static void setup_user_context(struct request_context *req)
122 struct user_context *ctx;
124 ctx = talloc(req->mem_ctx, sizeof(*ctx));
125 ctx->vuid = SVAL(req->in.hdr, HDR_UID);
126 ctx->vuser = get_valid_user_struct(req->smb, ctx->vuid);
133 These flags determine some of the permissions required to do an operation
135 Note that I don't set NEED_WRITE on some write operations because they
136 are used by some brain-dead clients when printing, and I don't want to
137 force write permissions on print services.
139 #define AS_USER (1<<0)
140 #define NEED_WRITE (1<<1)
141 #define TIME_INIT (1<<2)
142 #define CAN_IPC (1<<3)
143 #define AS_GUEST (1<<5)
144 #define USE_MUTEX (1<<7)
147 define a list of possible SMB messages and their corresponding
148 functions. Any message that has a NULL function is unimplemented -
149 please feel free to contribute implementations!
151 static const struct smb_message_struct
154 void (*fn)(struct request_context *);
157 smb_messages[256] = {
158 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
159 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
160 /* 0x02 */ { "SMBopen",reply_open,AS_USER },
161 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
162 /* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
163 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
164 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
165 /* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
166 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
167 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
168 /* 0x0a */ { "SMBread",reply_read,AS_USER},
169 /* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
170 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
171 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
172 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
173 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
174 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
175 /* 0x11 */ { "SMBexit",reply_exit,0},
176 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
177 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
178 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
179 /* 0x15 */ { NULL, NULL, 0 },
180 /* 0x16 */ { NULL, NULL, 0 },
181 /* 0x17 */ { NULL, NULL, 0 },
182 /* 0x18 */ { NULL, NULL, 0 },
183 /* 0x19 */ { NULL, NULL, 0 },
184 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
185 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
186 /* 0x1c */ { "SMBreadBs",NULL,0 },
187 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
188 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
189 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
190 /* 0x20 */ { "SMBwritec",NULL,0},
191 /* 0x21 */ { NULL, NULL, 0 },
192 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
193 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
194 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
195 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
196 /* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
197 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
198 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
199 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
200 /* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE },
201 /* 0x2b */ { "SMBecho",reply_echo,0},
202 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
203 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
204 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
205 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
206 /* 0x30 */ { NULL, NULL, 0 },
207 /* 0x31 */ { NULL, NULL, 0 },
208 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
209 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
210 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
211 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
212 /* 0x36 */ { NULL, NULL, 0 },
213 /* 0x37 */ { NULL, NULL, 0 },
214 /* 0x38 */ { NULL, NULL, 0 },
215 /* 0x39 */ { NULL, NULL, 0 },
216 /* 0x3a */ { NULL, NULL, 0 },
217 /* 0x3b */ { NULL, NULL, 0 },
218 /* 0x3c */ { NULL, NULL, 0 },
219 /* 0x3d */ { NULL, NULL, 0 },
220 /* 0x3e */ { NULL, NULL, 0 },
221 /* 0x3f */ { NULL, NULL, 0 },
222 /* 0x40 */ { NULL, NULL, 0 },
223 /* 0x41 */ { NULL, NULL, 0 },
224 /* 0x42 */ { NULL, NULL, 0 },
225 /* 0x43 */ { NULL, NULL, 0 },
226 /* 0x44 */ { NULL, NULL, 0 },
227 /* 0x45 */ { NULL, NULL, 0 },
228 /* 0x46 */ { NULL, NULL, 0 },
229 /* 0x47 */ { NULL, NULL, 0 },
230 /* 0x48 */ { NULL, NULL, 0 },
231 /* 0x49 */ { NULL, NULL, 0 },
232 /* 0x4a */ { NULL, NULL, 0 },
233 /* 0x4b */ { NULL, NULL, 0 },
234 /* 0x4c */ { NULL, NULL, 0 },
235 /* 0x4d */ { NULL, NULL, 0 },
236 /* 0x4e */ { NULL, NULL, 0 },
237 /* 0x4f */ { NULL, NULL, 0 },
238 /* 0x50 */ { NULL, NULL, 0 },
239 /* 0x51 */ { NULL, NULL, 0 },
240 /* 0x52 */ { NULL, NULL, 0 },
241 /* 0x53 */ { NULL, NULL, 0 },
242 /* 0x54 */ { NULL, NULL, 0 },
243 /* 0x55 */ { NULL, NULL, 0 },
244 /* 0x56 */ { NULL, NULL, 0 },
245 /* 0x57 */ { NULL, NULL, 0 },
246 /* 0x58 */ { NULL, NULL, 0 },
247 /* 0x59 */ { NULL, NULL, 0 },
248 /* 0x5a */ { NULL, NULL, 0 },
249 /* 0x5b */ { NULL, NULL, 0 },
250 /* 0x5c */ { NULL, NULL, 0 },
251 /* 0x5d */ { NULL, NULL, 0 },
252 /* 0x5e */ { NULL, NULL, 0 },
253 /* 0x5f */ { NULL, NULL, 0 },
254 /* 0x60 */ { NULL, NULL, 0 },
255 /* 0x61 */ { NULL, NULL, 0 },
256 /* 0x62 */ { NULL, NULL, 0 },
257 /* 0x63 */ { NULL, NULL, 0 },
258 /* 0x64 */ { NULL, NULL, 0 },
259 /* 0x65 */ { NULL, NULL, 0 },
260 /* 0x66 */ { NULL, NULL, 0 },
261 /* 0x67 */ { NULL, NULL, 0 },
262 /* 0x68 */ { NULL, NULL, 0 },
263 /* 0x69 */ { NULL, NULL, 0 },
264 /* 0x6a */ { NULL, NULL, 0 },
265 /* 0x6b */ { NULL, NULL, 0 },
266 /* 0x6c */ { NULL, NULL, 0 },
267 /* 0x6d */ { NULL, NULL, 0 },
268 /* 0x6e */ { NULL, NULL, 0 },
269 /* 0x6f */ { NULL, NULL, 0 },
270 /* 0x70 */ { "SMBtcon",reply_tcon,USE_MUTEX},
271 /* 0x71 */ { "SMBtdis",reply_tdis,0},
272 /* 0x72 */ { "SMBnegprot",reply_negprot,USE_MUTEX},
273 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,USE_MUTEX},
274 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
275 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,USE_MUTEX},
276 /* 0x76 */ { NULL, NULL, 0 },
277 /* 0x77 */ { NULL, NULL, 0 },
278 /* 0x78 */ { NULL, NULL, 0 },
279 /* 0x79 */ { NULL, NULL, 0 },
280 /* 0x7a */ { NULL, NULL, 0 },
281 /* 0x7b */ { NULL, NULL, 0 },
282 /* 0x7c */ { NULL, NULL, 0 },
283 /* 0x7d */ { NULL, NULL, 0 },
284 /* 0x7e */ { NULL, NULL, 0 },
285 /* 0x7f */ { NULL, NULL, 0 },
286 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
287 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
288 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
289 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
290 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
291 /* 0x85 */ { NULL, NULL, 0 },
292 /* 0x86 */ { NULL, NULL, 0 },
293 /* 0x87 */ { NULL, NULL, 0 },
294 /* 0x88 */ { NULL, NULL, 0 },
295 /* 0x89 */ { NULL, NULL, 0 },
296 /* 0x8a */ { NULL, NULL, 0 },
297 /* 0x8b */ { NULL, NULL, 0 },
298 /* 0x8c */ { NULL, NULL, 0 },
299 /* 0x8d */ { NULL, NULL, 0 },
300 /* 0x8e */ { NULL, NULL, 0 },
301 /* 0x8f */ { NULL, NULL, 0 },
302 /* 0x90 */ { NULL, NULL, 0 },
303 /* 0x91 */ { NULL, NULL, 0 },
304 /* 0x92 */ { NULL, NULL, 0 },
305 /* 0x93 */ { NULL, NULL, 0 },
306 /* 0x94 */ { NULL, NULL, 0 },
307 /* 0x95 */ { NULL, NULL, 0 },
308 /* 0x96 */ { NULL, NULL, 0 },
309 /* 0x97 */ { NULL, NULL, 0 },
310 /* 0x98 */ { NULL, NULL, 0 },
311 /* 0x99 */ { NULL, NULL, 0 },
312 /* 0x9a */ { NULL, NULL, 0 },
313 /* 0x9b */ { NULL, NULL, 0 },
314 /* 0x9c */ { NULL, NULL, 0 },
315 /* 0x9d */ { NULL, NULL, 0 },
316 /* 0x9e */ { NULL, NULL, 0 },
317 /* 0x9f */ { NULL, NULL, 0 },
318 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
319 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
320 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC },
321 /* 0xa3 */ { NULL, NULL, 0 },
322 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
323 /* 0xa5 */ { NULL, NULL, 0 },
324 /* 0xa6 */ { NULL, NULL, 0 },
325 /* 0xa7 */ { NULL, NULL, 0 },
326 /* 0xa8 */ { NULL, NULL, 0 },
327 /* 0xa9 */ { NULL, NULL, 0 },
328 /* 0xaa */ { NULL, NULL, 0 },
329 /* 0xab */ { NULL, NULL, 0 },
330 /* 0xac */ { NULL, NULL, 0 },
331 /* 0xad */ { NULL, NULL, 0 },
332 /* 0xae */ { NULL, NULL, 0 },
333 /* 0xaf */ { NULL, NULL, 0 },
334 /* 0xb0 */ { NULL, NULL, 0 },
335 /* 0xb1 */ { NULL, NULL, 0 },
336 /* 0xb2 */ { NULL, NULL, 0 },
337 /* 0xb3 */ { NULL, NULL, 0 },
338 /* 0xb4 */ { NULL, NULL, 0 },
339 /* 0xb5 */ { NULL, NULL, 0 },
340 /* 0xb6 */ { NULL, NULL, 0 },
341 /* 0xb7 */ { NULL, NULL, 0 },
342 /* 0xb8 */ { NULL, NULL, 0 },
343 /* 0xb9 */ { NULL, NULL, 0 },
344 /* 0xba */ { NULL, NULL, 0 },
345 /* 0xbb */ { NULL, NULL, 0 },
346 /* 0xbc */ { NULL, NULL, 0 },
347 /* 0xbd */ { NULL, NULL, 0 },
348 /* 0xbe */ { NULL, NULL, 0 },
349 /* 0xbf */ { NULL, NULL, 0 },
350 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
351 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
352 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
353 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
354 /* 0xc4 */ { NULL, NULL, 0 },
355 /* 0xc5 */ { NULL, NULL, 0 },
356 /* 0xc6 */ { NULL, NULL, 0 },
357 /* 0xc7 */ { NULL, NULL, 0 },
358 /* 0xc8 */ { NULL, NULL, 0 },
359 /* 0xc9 */ { NULL, NULL, 0 },
360 /* 0xca */ { NULL, NULL, 0 },
361 /* 0xcb */ { NULL, NULL, 0 },
362 /* 0xcc */ { NULL, NULL, 0 },
363 /* 0xcd */ { NULL, NULL, 0 },
364 /* 0xce */ { NULL, NULL, 0 },
365 /* 0xcf */ { NULL, NULL, 0 },
366 /* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
367 /* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
368 /* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
369 /* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
370 /* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
371 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
372 /* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
373 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
374 /* 0xd8 */ { NULL, NULL, 0 },
375 /* 0xd9 */ { NULL, NULL, 0 },
376 /* 0xda */ { NULL, NULL, 0 },
377 /* 0xdb */ { NULL, NULL, 0 },
378 /* 0xdc */ { NULL, NULL, 0 },
379 /* 0xdd */ { NULL, NULL, 0 },
380 /* 0xde */ { NULL, NULL, 0 },
381 /* 0xdf */ { NULL, NULL, 0 },
382 /* 0xe0 */ { NULL, NULL, 0 },
383 /* 0xe1 */ { NULL, NULL, 0 },
384 /* 0xe2 */ { NULL, NULL, 0 },
385 /* 0xe3 */ { NULL, NULL, 0 },
386 /* 0xe4 */ { NULL, NULL, 0 },
387 /* 0xe5 */ { NULL, NULL, 0 },
388 /* 0xe6 */ { NULL, NULL, 0 },
389 /* 0xe7 */ { NULL, NULL, 0 },
390 /* 0xe8 */ { NULL, NULL, 0 },
391 /* 0xe9 */ { NULL, NULL, 0 },
392 /* 0xea */ { NULL, NULL, 0 },
393 /* 0xeb */ { NULL, NULL, 0 },
394 /* 0xec */ { NULL, NULL, 0 },
395 /* 0xed */ { NULL, NULL, 0 },
396 /* 0xee */ { NULL, NULL, 0 },
397 /* 0xef */ { NULL, NULL, 0 },
398 /* 0xf0 */ { NULL, NULL, 0 },
399 /* 0xf1 */ { NULL, NULL, 0 },
400 /* 0xf2 */ { NULL, NULL, 0 },
401 /* 0xf3 */ { NULL, NULL, 0 },
402 /* 0xf4 */ { NULL, NULL, 0 },
403 /* 0xf5 */ { NULL, NULL, 0 },
404 /* 0xf6 */ { NULL, NULL, 0 },
405 /* 0xf7 */ { NULL, NULL, 0 },
406 /* 0xf8 */ { NULL, NULL, 0 },
407 /* 0xf9 */ { NULL, NULL, 0 },
408 /* 0xfa */ { NULL, NULL, 0 },
409 /* 0xfb */ { NULL, NULL, 0 },
410 /* 0xfc */ { NULL, NULL, 0 },
411 /* 0xfd */ { NULL, NULL, 0 },
412 /* 0xfe */ { NULL, NULL, 0 },
413 /* 0xff */ { NULL, NULL, 0 }
416 /****************************************************************************
417 return a string containing the function name of a SMB command
418 ****************************************************************************/
419 static const char *smb_fn_name(uint8 type)
421 const char *unknown_name = "SMBunknown";
423 if (smb_messages[type].name == NULL)
426 return smb_messages[type].name;
430 /****************************************************************************
431 Do a switch on the message type and call the specific reply function for this
432 message. Unlike earlier versions of Samba the reply functions are responsible
433 for sending the reply themselves, rather than returning a size to this function
434 The reply functions may also choose to delay the processing by pushing the message
435 onto the message queue
436 ****************************************************************************/
437 static void switch_message(int type, struct request_context *req)
441 struct server_context *smb = req->smb;
447 if (smb_messages[type].fn == NULL) {
448 DEBUG(0,("Unknown message type %d!\n",type));
453 flags = smb_messages[type].flags;
455 /* In share mode security we must ignore the vuid. */
456 session_tag = (lp_security() == SEC_SHARE) ?
458 SVAL(req->in.hdr,HDR_UID);
460 req->conn = conn_find(req->smb, SVAL(req->in.hdr,HDR_TID));
462 /* setup the user context for this request */
463 setup_user_context(req);
465 /* Ensure this value is replaced in the incoming packet. */
466 SSVAL(req->in.hdr,HDR_UID,session_tag);
469 req->user_ctx->vuid = session_tag;
471 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb->model_ops->get_id(req)));
473 /* does this protocol need to be run as root? */
474 if (!(flags & AS_USER)) {
475 change_to_root_user();
478 /* does this protocol need a valid tree connection? */
479 if ((flags & AS_USER) && !req->conn) {
480 req_reply_error(req, NT_STATUS_NETWORK_NAME_DELETED);
484 /* does this protocol need to be run as the connected user? */
486 if ((flags & AS_USER) && !change_to_user(req->conn,session_tag)) {
487 if (!(flags & AS_GUEST)) {
488 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
492 /* we'll run it as guest */
497 /* this code is to work around a bug is MS client 3 without
498 introducing a security hole - it needs to be able to do
499 print queue checks as guest if it isn't logged in properly */
500 if (flags & AS_USER) {
504 /* does it need write permission? */
505 if ((flags & NEED_WRITE) && !CAN_WRITE(req->conn)) {
506 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
510 /* ipc services are limited */
511 if (req->conn && req->conn->type == NTVFS_IPC && (flags & AS_USER) && !(flags & CAN_IPC)) {
512 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
516 /* load service specific parameters */
517 if (req->conn && !set_current_service(req->conn,(flags & AS_USER)?True:False)) {
518 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
522 /* does this protocol need to be run as guest? */
524 if ((flags & AS_GUEST) &&
525 !change_to_guest()) {
526 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
530 /* THREAD TESTING: use mutex to serialize calls to critical functions with global state */
531 if (flags & USE_MUTEX) {
532 MUTEX_LOCK_BY_ID(MUTEX_SMBD);
534 smb_messages[type].fn(req);
535 if (flags & USE_MUTEX) {
536 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
541 /****************************************************************************
542 Construct a reply to the incoming packet.
543 ****************************************************************************/
544 static void construct_reply(struct request_context *req)
546 uint8 type = CVAL(req->in.hdr,HDR_COM);
548 /* see if its a special NBT packet */
549 if (CVAL(req->in.buffer,0) != 0) {
555 /* Make sure this is an SMB packet */
556 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
557 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
559 exit_server(req->smb, "Non-SMB packet");
563 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
564 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
565 exit_server(req->smb, "Invalid SMB packet");
569 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
570 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
571 exit_server(req->smb, "Invalid SMB packet");
576 req->smbpid = SVAL(req->in.hdr,HDR_PID);
577 req->flags = CVAL(req->in.hdr, HDR_FLG);
578 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
580 switch_message(type, req);
585 we call this when first first part of a possibly chained request has been completed
586 and we need to call the 2nd part, if any
588 void chain_reply(struct request_context *req)
590 uint16 chain_cmd, chain_offset;
595 if (req->in.wct < 2 || req->out.wct < 2) {
596 req_reply_dos_error(req, ERRSRV, ERRerror);
600 chain_cmd = CVAL(req->in.vwv, VWV(0));
601 chain_offset = SVAL(req->in.vwv, VWV(1));
603 if (chain_cmd == SMB_CHAIN_NONE) {
605 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
606 SSVAL(req->out.vwv, VWV(1), 0);
611 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
615 wct = CVAL(req->in.hdr, chain_offset);
616 vwv = req->in.hdr + chain_offset + 1;
618 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
622 data_size = SVAL(vwv, VWV(wct));
623 data = vwv + VWV(wct) + 2;
625 if (data + data_size > req->in.buffer + req->in.size) {
629 /* all seems legit */
633 req->in.data_size = data_size;
638 SSVAL(req->out.vwv, VWV(0), chain_cmd);
639 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
641 /* the current request in the chain might have used an async reply,
642 but that doesn't mean the next element needs to */
643 ZERO_STRUCT(req->async);
644 req->control_flags &= ~REQ_CONTROL_ASYNC;
646 switch_message(chain_cmd, req);
650 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
651 SSVAL(req->out.vwv, VWV(1), 0);
652 req_reply_dos_error(req, ERRSRV, ERRerror);
657 close the socket and shutdown a server_context
659 void server_terminate(struct server_context *smb)
661 close(smb->socket.fd);
662 event_remove_fd_all(smb->events, smb->socket.fd);
666 talloc_destroy(smb->mem_ctx);
671 called when a SMB socket becomes readable
673 static void smbd_read_handler(struct event_context *ev, struct fd_event *fde,
674 time_t t, uint16 flags)
676 struct request_context *req;
677 struct server_context *smb = fde->private;
679 req = receive_smb_request(smb);
681 smb->model_ops->terminate_connection(smb, "receive error");
685 construct_reply(req);
687 /* free up temporary memory */
693 process a message from an SMB socket while still processing a
694 previous message this is used by backends who need to ensure that
695 new messages from clients are still processed while they are
696 performing long operations
698 void smbd_process_async(struct server_context *smb)
700 struct request_context *req;
702 req = receive_smb_request(smb);
704 smb->model_ops->terminate_connection(smb, "receive error");
708 construct_reply(req);
713 initialise a server_context from a open socket and register a event handler
714 for reading from that socket
716 void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int fd)
718 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 sub_set_remote_machine(strdup(get_socket_addr(smb->mem_ctx, fd)));
741 smb->socket.client_addr = talloc_strdup(smb->mem_ctx, get_socket_addr(smb->mem_ctx, fd));
743 /* now initialise a few default values associated with this smb socket */
744 smb->negotiate.max_send = 0xFFFF;
746 /* this is the size that w2k uses, and it appears to be important for
748 smb->negotiate.max_recv = 4356;
750 smb->users.next_vuid = VUID_OFFSET;
753 smb->model_ops = model_ops;
757 /* setup a event handler for this socket. We are initially
758 only interested in reading from the socket */
760 fde.handler = smbd_read_handler;
762 fde.flags = EVENT_FD_READ;
764 event_add_fd(ev, &fde);
769 * initialize an smb process
771 void smbd_process_init(void)
775 mem_ctx = talloc_init("smbd_process_init talloc");
777 DEBUG(0,("smbd_process_init: ERROR: No memory\n"));
782 if (!locking_init(0))
785 if (!share_info_db_init())
788 if (!init_registry())
791 if(!initialize_password_db(False))
794 /* possibly reload the services file. */
795 reload_services(NULL, True);
797 if(!get_global_sam_sid()) {
798 DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n"));
802 if (!init_account_policy()) {
803 DEBUG(0,("Could not open account policy tdb.\n"));
808 if (sys_chroot(lp_rootdir()) == 0)
809 DEBUG(2,("Changed root to %s\n", lp_rootdir()));
816 /* Setup change notify */
817 if (!init_change_notify())
820 /* Setup privileges database */
821 if (!privilege_init())
824 /* Setup the NTVFS subsystem */
828 /* re-initialise the timezone */
831 talloc_destroy(mem_ctx);