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