This commit was generated by cvs2svn to compensate for changes in r30,
[ira/wip.git] / source4 / smbd / process.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 SIG_ATOMIC_T reload_after_sighup = 0;
25 SIG_ATOMIC_T got_sig_term = 0;
26
27 /*
28   send an oplock break request to a client
29 */
30 BOOL req_send_oplock_break(struct tcon_context *conn, uint16 fnum, uint8 level)
31 {
32         struct request_context *req;
33
34         req = init_smb_request(conn->smb);
35
36         req_setup_reply(req, 8, 0);
37         
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);
45
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);
53
54         req_send_reply(req);
55         return True;
56 }
57
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)
62 {
63         ssize_t len, len2;
64         char header[4];
65         struct request_context *req;
66
67         len = read_data(smb->socket.fd, header, 4);
68         if (len != 4) {
69                 return NULL;
70         }
71
72         len = smb_len(header);
73
74         req = init_smb_request(smb);
75
76         GetTimeOfDay(&req->request_time);
77         req->chained_fnum = -1;
78         
79         /* allocate the incoming buffer at the right size */
80         req->in.buffer = talloc(req->mem_ctx, len + NBT_HDR_SIZE);
81
82         /* fill in the already received header */
83         memcpy(req->in.buffer, header, 4);
84
85         len2 = read_data(smb->socket.fd, req->in.buffer + NBT_HDR_SIZE, len);
86         if (len2 != len) {
87                 return NULL;
88         }
89
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));
99
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);
111                 }
112         }
113
114         return req;
115 }
116
117 /*
118   setup the user_ctx element of a request
119 */
120 static void setup_user_context(struct request_context *req)
121 {
122         struct user_context *ctx;
123
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);
127
128         req->user_ctx = ctx;
129 }
130
131
132 /*
133 These flags determine some of the permissions required to do an operation 
134
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.
138 */
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)
145
146 /* 
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!
150 */
151 static const struct smb_message_struct
152 {
153         const char *name;
154         void (*fn)(struct request_context *);
155         int flags;
156 }
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 }
414 };
415
416 /****************************************************************************
417 return a string containing the function name of a SMB command
418 ****************************************************************************/
419 static const char *smb_fn_name(uint8 type)
420 {
421         const char *unknown_name = "SMBunknown";
422
423         if (smb_messages[type].name == NULL)
424                 return unknown_name;
425
426         return smb_messages[type].name;
427 }
428
429
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)
438 {
439         int flags;
440         uint16 session_tag;
441         struct server_context *smb = req->smb;
442
443         type &= 0xff;
444
445         errno = 0;
446
447         if (smb_messages[type].fn == NULL) {
448                 DEBUG(0,("Unknown message type %d!\n",type));
449                 reply_unknown(req);
450                 return;
451         }
452
453         flags = smb_messages[type].flags;
454
455         /* In share mode security we must ignore the vuid. */
456         session_tag = (lp_security() == SEC_SHARE) ? 
457                 UID_FIELD_INVALID : 
458                 SVAL(req->in.hdr,HDR_UID);
459
460         req->conn = conn_find(req->smb, SVAL(req->in.hdr,HDR_TID));
461
462         /* setup the user context for this request */
463         setup_user_context(req);
464
465         /* Ensure this value is replaced in the incoming packet. */
466         SSVAL(req->in.hdr,HDR_UID,session_tag);
467
468         if (req->user_ctx) {
469                 req->user_ctx->vuid = session_tag;
470         }
471         DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb->model_ops->get_id(req)));
472
473         /* does this protocol need to be run as root? */
474         if (!(flags & AS_USER)) {
475                 change_to_root_user();
476         }
477         
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);
481                 return;
482         }
483
484         /* does this protocol need to be run as the connected user? */
485 #if HACK_REWRITE
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);
489                         return;
490                 }
491
492                 /* we'll run it as guest */
493                 flags &= ~AS_USER;
494         }
495 #endif
496
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) {
501                 flags &= ~AS_GUEST;
502         }
503         
504         /* does it need write permission? */
505         if ((flags & NEED_WRITE) && !CAN_WRITE(req->conn)) {
506                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
507                 return;
508         }
509         
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);
513                 return;
514         }
515         
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);
519                 return;
520         }
521         
522         /* does this protocol need to be run as guest? */
523 #if HACK_REWRITE
524         if ((flags & AS_GUEST) && 
525             !change_to_guest()) {
526                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
527                 return;
528         }
529 #endif
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);
533         }
534         smb_messages[type].fn(req);
535         if (flags & USE_MUTEX) {
536                 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
537         }
538 }
539
540
541 /****************************************************************************
542  Construct a reply to the incoming packet.
543 ****************************************************************************/
544 static void construct_reply(struct request_context *req)
545 {
546         uint8 type = CVAL(req->in.hdr,HDR_COM);
547
548         /* see if its a special NBT packet */
549         if (CVAL(req->in.buffer,0) != 0) {
550                 reply_special(req);
551                 return;
552         }
553
554
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", 
558                          req->in.size));
559                 exit_server(req->smb, "Non-SMB packet");
560                 return;
561         }
562
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");
566                 return;
567         }
568
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");
572                 return;
573         }
574
575
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);
579
580         switch_message(type, req);
581 }
582
583
584 /*
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
587 */
588 void chain_reply(struct request_context *req)
589 {
590         uint16 chain_cmd, chain_offset;
591         char *vwv, *data;
592         uint16 wct;
593         uint16 data_size;
594
595         if (req->in.wct < 2 || req->out.wct < 2) {
596                 req_reply_dos_error(req, ERRSRV, ERRerror);
597                 return;
598         }
599
600         chain_cmd    = CVAL(req->in.vwv, VWV(0));
601         chain_offset = SVAL(req->in.vwv, VWV(1));
602
603         if (chain_cmd == SMB_CHAIN_NONE) {
604                 /* end of chain */
605                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
606                 SSVAL(req->out.vwv, VWV(1), 0);
607                 req_send_reply(req);
608                 return;
609         }
610
611         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
612                 goto error;
613         }
614
615         wct = CVAL(req->in.hdr, chain_offset);
616         vwv = req->in.hdr + chain_offset + 1;
617
618         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
619                 goto error;
620         }
621
622         data_size = SVAL(vwv, VWV(wct));
623         data = vwv + VWV(wct) + 2;
624
625         if (data + data_size > req->in.buffer + req->in.size) {
626                 goto error;
627         }
628
629         /* all seems legit */
630         req->in.vwv = vwv;
631         req->in.wct = wct;
632         req->in.data = data;
633         req->in.data_size = data_size;
634         req->in.ptr = data;
635
636         req->chain_count++;
637
638         SSVAL(req->out.vwv, VWV(0), chain_cmd);
639         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
640
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;
645
646         switch_message(chain_cmd, req);
647         return;
648
649 error:
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);
653 }
654
655
656 /*
657   close the socket and shutdown a server_context
658 */
659 void server_terminate(struct server_context *smb)
660 {
661         close(smb->socket.fd);
662         event_remove_fd_all(smb->events, smb->socket.fd);
663
664         conn_close_all(smb);
665
666         talloc_destroy(smb->mem_ctx);
667 }
668
669
670 /*
671   called when a SMB socket becomes readable
672 */
673 static void smbd_read_handler(struct event_context *ev, struct fd_event *fde, 
674                               time_t t, uint16 flags)
675 {
676         struct request_context *req;
677         struct server_context *smb = fde->private;
678         
679         req = receive_smb_request(smb);
680         if (!req) {
681                 smb->model_ops->terminate_connection(smb, "receive error");
682                 return;
683         }
684
685         construct_reply(req);
686
687         /* free up temporary memory */
688         lp_talloc_free();
689 }
690
691
692 /*
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
697 */
698 void smbd_process_async(struct server_context *smb)
699 {
700         struct request_context *req;
701         
702         req = receive_smb_request(smb);
703         if (!req) {
704                 smb->model_ops->terminate_connection(smb, "receive error");
705                 return;
706         }
707
708         construct_reply(req);
709 }
710
711
712 /*
713   initialise a server_context from a open socket and register a event handler
714   for reading from that socket
715 */
716 void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int fd)
717 {
718         struct server_context *smb;
719         TALLOC_CTX *mem_ctx;
720         struct fd_event fde;
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         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));
742
743         /* now initialise a few default values associated with this smb socket */
744         smb->negotiate.max_send = 0xFFFF;
745
746         /* this is the size that w2k uses, and it appears to be important for
747            good performance */
748         smb->negotiate.max_recv = 4356;
749
750         smb->users.next_vuid = VUID_OFFSET;
751         
752         smb->events = ev;
753         smb->model_ops = model_ops;
754
755         conn_init(smb);
756
757         /* setup a event handler for this socket. We are initially
758            only interested in reading from the socket */
759         fde.fd = fd;
760         fde.handler = smbd_read_handler;
761         fde.private = smb;
762         fde.flags = EVENT_FD_READ;
763
764         event_add_fd(ev, &fde);
765 }
766
767
768 /*
769  * initialize an smb process
770  */
771 void smbd_process_init(void)
772 {
773         TALLOC_CTX *mem_ctx;
774         
775         mem_ctx = talloc_init("smbd_process_init talloc");
776         if (!mem_ctx) {
777                 DEBUG(0,("smbd_process_init: ERROR: No memory\n"));
778                 exit(1);
779         }
780         namecache_enable();
781
782         if (!locking_init(0))
783                 exit(1);
784
785         if (!share_info_db_init())
786                 exit(1);
787
788         if (!init_registry())
789                 exit(1);
790
791         if(!initialize_password_db(False))
792                 exit(1);
793
794         /* possibly reload the services file. */
795         reload_services(NULL, True);
796
797         if(!get_global_sam_sid()) {
798                 DEBUG(0,("ERROR: Samba cannot create a SAM SID.\n"));
799                 exit(1);
800         }
801
802         if (!init_account_policy()) {
803                 DEBUG(0,("Could not open account policy tdb.\n"));
804                 exit(1);
805         }
806
807         if (*lp_rootdir()) {
808                 if (sys_chroot(lp_rootdir()) == 0)
809                         DEBUG(2,("Changed root to %s\n", lp_rootdir()));
810         }
811
812         /* Setup oplocks */
813         if (!init_oplocks())
814                 exit(1);
815         
816         /* Setup change notify */
817         if (!init_change_notify())
818                 exit(1);
819
820         /* Setup privileges database */
821         if (!privilege_init())
822                 exit(1);
823
824         /* Setup the NTVFS subsystem */
825         if (!ntvfs_init())
826                 exit(1);
827
828         /* re-initialise the timezone */
829         TimeInit();
830         
831         talloc_destroy(mem_ctx);
832 }
833