f798accc3f0287a79ecb948c6b9b43efad8f7e40
[kai/samba.git] / source / smb_server / smb_server.c
1 /* 
2    Unix SMB/CIFS implementation.
3    process incoming packets - main loop
4    Copyright (C) Andrew Tridgell 1992-2003
5    Copyright (C) James J Myers 2003 <myersjj@samba.org>
6    
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.
11    
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.
16    
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.
20 */
21
22 #include "includes.h"
23
24
25 /*
26   send an oplock break request to a client
27 */
28 BOOL req_send_oplock_break(struct tcon_context *conn, uint16 fnum, uint8 level)
29 {
30         struct request_context *req;
31
32         req = init_smb_request(conn->smb);
33
34         req_setup_reply(req, 8, 0);
35         
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);
43
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);
52
53         req_send_reply(req);
54         return True;
55 }
56
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)
61 {
62         ssize_t len, len2;
63         char header[4];
64         struct request_context *req;
65
66         len = read_data(smb->socket.fd, header, 4);
67         if (len != 4) {
68                 return NULL;
69         }
70
71         len = smb_len(header);
72
73         req = init_smb_request(smb);
74
75         GetTimeOfDay(&req->request_time);
76         req->chained_fnum = -1;
77         
78         /* allocate the incoming buffer at the right size */
79         req->in.buffer = talloc(req->mem_ctx, len + NBT_HDR_SIZE);
80
81         /* fill in the already received header */
82         memcpy(req->in.buffer, header, 4);
83
84         len2 = read_data(smb->socket.fd, req->in.buffer + NBT_HDR_SIZE, len);
85         if (len2 != len) {
86                 return NULL;
87         }
88
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));
98
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);
110                 }
111         }
112
113         return req;
114 }
115
116 /*
117   setup the user_ctx element of a request
118 */
119 static void setup_user_context(struct request_context *req)
120 {
121         struct user_context *ctx;
122
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);
126
127         req->user_ctx = ctx;
128 }
129
130
131 /*
132 These flags determine some of the permissions required to do an operation 
133
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.
137 */
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)
144
145 /* 
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!
149 */
150 static const struct smb_message_struct
151 {
152         const char *name;
153         void (*fn)(struct request_context *);
154         int flags;
155 }
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 }
413 };
414
415 /****************************************************************************
416 return a string containing the function name of a SMB command
417 ****************************************************************************/
418 static const char *smb_fn_name(uint8 type)
419 {
420         const char *unknown_name = "SMBunknown";
421
422         if (smb_messages[type].name == NULL)
423                 return unknown_name;
424
425         return smb_messages[type].name;
426 }
427
428
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)
437 {
438         int flags;
439         uint16 session_tag;
440         struct server_context *smb = req->smb;
441
442         type &= 0xff;
443
444         errno = 0;
445
446         if (smb_messages[type].fn == NULL) {
447                 DEBUG(0,("Unknown message type %d!\n",type));
448                 reply_unknown(req);
449                 return;
450         }
451
452         flags = smb_messages[type].flags;
453
454         /* In share mode security we must ignore the vuid. */
455         session_tag = (lp_security() == SEC_SHARE) ? 
456                 UID_FIELD_INVALID : 
457                 SVAL(req->in.hdr,HDR_UID);
458
459         req->conn = conn_find(req->smb, SVAL(req->in.hdr,HDR_TID));
460
461         /* setup the user context for this request */
462         setup_user_context(req);
463
464         /* Ensure this value is replaced in the incoming packet. */
465         SSVAL(req->in.hdr,HDR_UID,session_tag);
466
467         if (req->user_ctx) {
468                 req->user_ctx->vuid = session_tag;
469         }
470         DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb->model_ops->get_id(req)));
471
472         /* does this protocol need to be run as root? */
473         if (!(flags & AS_USER)) {
474                 change_to_root_user();
475         }
476         
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);
480                 return;
481         }
482
483         /* does this protocol need to be run as the connected user? */
484 #if HACK_REWRITE
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);
488                         return;
489                 }
490
491                 /* we'll run it as guest */
492                 flags &= ~AS_USER;
493         }
494 #endif
495
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) {
500                 flags &= ~AS_GUEST;
501         }
502         
503         /* does it need write permission? */
504         if ((flags & NEED_WRITE) && !CAN_WRITE(req->conn)) {
505                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
506                 return;
507         }
508         
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);
512                 return;
513         }
514         
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);
518                 return;
519         }
520         
521         /* does this protocol need to be run as guest? */
522 #if HACK_REWRITE
523         if ((flags & AS_GUEST) && 
524             !change_to_guest()) {
525                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
526                 return;
527         }
528 #endif
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);
532         }
533         smb_messages[type].fn(req);
534         if (flags & USE_MUTEX) {
535                 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
536         }
537 }
538
539
540 /****************************************************************************
541  Construct a reply to the incoming packet.
542 ****************************************************************************/
543 static void construct_reply(struct request_context *req)
544 {
545         uint8 type = CVAL(req->in.hdr,HDR_COM);
546
547         /* see if its a special NBT packet */
548         if (CVAL(req->in.buffer,0) != 0) {
549                 reply_special(req);
550                 return;
551         }
552
553
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", 
557                          req->in.size));
558                 exit_server(req->smb, "Non-SMB packet");
559                 return;
560         }
561
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");
565                 return;
566         }
567
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");
571                 return;
572         }
573
574
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);
578
579         switch_message(type, req);
580 }
581
582
583 /*
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
586 */
587 void chain_reply(struct request_context *req)
588 {
589         uint16 chain_cmd, chain_offset;
590         char *vwv, *data;
591         uint16 wct;
592         uint16 data_size;
593
594         if (req->in.wct < 2 || req->out.wct < 2) {
595                 req_reply_dos_error(req, ERRSRV, ERRerror);
596                 return;
597         }
598
599         chain_cmd    = CVAL(req->in.vwv, VWV(0));
600         chain_offset = SVAL(req->in.vwv, VWV(1));
601
602         if (chain_cmd == SMB_CHAIN_NONE) {
603                 /* end of chain */
604                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
605                 SSVAL(req->out.vwv, VWV(1), 0);
606                 req_send_reply(req);
607                 return;
608         }
609
610         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
611                 goto error;
612         }
613
614         wct = CVAL(req->in.hdr, chain_offset);
615         vwv = req->in.hdr + chain_offset + 1;
616
617         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
618                 goto error;
619         }
620
621         data_size = SVAL(vwv, VWV(wct));
622         data = vwv + VWV(wct) + 2;
623
624         if (data + data_size > req->in.buffer + req->in.size) {
625                 goto error;
626         }
627
628         /* all seems legit */
629         req->in.vwv = vwv;
630         req->in.wct = wct;
631         req->in.data = data;
632         req->in.data_size = data_size;
633         req->in.ptr = data;
634
635         req->chain_count++;
636
637         SSVAL(req->out.vwv, VWV(0), chain_cmd);
638         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
639
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;
644
645         switch_message(chain_cmd, req);
646         return;
647
648 error:
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);
652 }
653
654
655 /*
656   close the socket and shutdown a server_context
657 */
658 void server_terminate(struct server_context *smb)
659 {
660         close(smb->socket.fd);
661         event_remove_fd_all(smb->events, smb->socket.fd);
662
663         conn_close_all(smb);
664
665         talloc_destroy(smb->mem_ctx);
666 }
667
668
669 /*
670   called when a SMB socket becomes readable
671 */
672 void smbd_read_handler(struct event_context *ev, struct fd_event *fde, 
673                        time_t t, uint16 flags)
674 {
675         struct request_context *req;
676         struct server_context *smb = fde->private;
677         
678         req = receive_smb_request(smb);
679         if (!req) {
680                 smb->model_ops->terminate_connection(smb, "receive error");
681                 return;
682         }
683
684         construct_reply(req);
685
686         /* free up temporary memory */
687         lp_talloc_free();
688 }
689
690
691 /*
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
696 */
697 void smbd_process_async(struct server_context *smb)
698 {
699         struct request_context *req;
700         
701         req = receive_smb_request(smb);
702         if (!req) {
703                 smb->model_ops->terminate_connection(smb, "receive error");
704                 return;
705         }
706
707         construct_reply(req);
708 }
709
710
711 /*
712   initialise a server_context from a open socket and register a event handler
713   for reading from that socket
714 */
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))
717 {
718         struct server_context *smb;
719         TALLOC_CTX *mem_ctx;
720         struct fd_event fde;
721         char *socket_addr;
722
723         set_socket_options(fd,"SO_KEEPALIVE");
724         set_socket_options(fd, lp_socket_options());
725
726         mem_ctx = talloc_init("server_context");
727
728         smb = (struct server_context *)talloc(mem_ctx, sizeof(*smb));
729         if (!smb) return;
730
731         ZERO_STRUCTP(smb);
732
733         smb->mem_ctx = mem_ctx;
734         smb->socket.fd = fd;
735         smb->pid = getpid();
736
737         sub_set_context(&smb->substitute);
738
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;
744
745         /* now initialise a few default values associated with this smb socket */
746         smb->negotiate.max_send = 0xFFFF;
747
748         /* this is the size that w2k uses, and it appears to be important for
749            good performance */
750         smb->negotiate.max_recv = lp_max_xmit();
751
752         smb->users.next_vuid = VUID_OFFSET;
753         
754         smb->events = ev;
755         smb->model_ops = model_ops;
756
757         conn_init(smb);
758
759         /* setup a event handler for this socket. We are initially
760            only interested in reading from the socket */
761         fde.fd = fd;
762         fde.handler = read_handler;
763         fde.private = smb;
764         fde.flags = EVENT_FD_READ;
765
766         event_add_fd(ev, &fde);
767
768         /* setup the DCERPC server subsystem */
769         dcesrv_init_context(&smb->dcesrv);
770 }