r1507: fixed the handling of SMB chaining with the new server structure. You
[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 smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
29 {
30         struct smbsrv_request *req;
31
32         req = init_smb_request(tcon->smb_conn);
33
34         req_setup_reply(req, 8, 0);
35         
36         SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
37         SSVAL(req->out.hdr,HDR_TID,tcon->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 smbsrv_request *receive_smb_request(struct smbsrv_connection *smb_conn)
61 {
62         ssize_t len, len2;
63         char header[4];
64         struct smbsrv_request *req;
65
66         len = read_data(smb_conn->connection->socket->fde->fd, header, 4);
67         if (len != 4) {
68                 return NULL;
69         }
70
71         len = smb_len(header);
72
73         req = init_smb_request(smb_conn);
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_conn->connection->socket->fde->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 These flags determine some of the permissions required to do an operation 
118
119 Note that I don't set NEED_WRITE on some write operations because they
120 are used by some brain-dead clients when printing, and I don't want to
121 force write permissions on print services.
122 */
123 #define AS_USER (1<<0)
124 #define NEED_WRITE (1<<1)
125 #define TIME_INIT (1<<2)
126 #define CAN_IPC (1<<3)
127 #define AS_GUEST (1<<5)
128 #define USE_MUTEX (1<<7)
129
130 /* 
131    define a list of possible SMB messages and their corresponding
132    functions. Any message that has a NULL function is unimplemented -
133    please feel free to contribute implementations!
134 */
135 static const struct smb_message_struct
136 {
137         const char *name;
138         void (*fn)(struct smbsrv_request *);
139         int flags;
140 }
141  smb_messages[256] = {
142 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
143 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
144 /* 0x02 */ { "SMBopen",reply_open,AS_USER },
145 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
146 /* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
147 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
148 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
149 /* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
150 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
151 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
152 /* 0x0a */ { "SMBread",reply_read,AS_USER},
153 /* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
154 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
155 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
156 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
157 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER}, 
158 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
159 /* 0x11 */ { "SMBexit",reply_exit,0},
160 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
161 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
162 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
163 /* 0x15 */ { NULL, NULL, 0 },
164 /* 0x16 */ { NULL, NULL, 0 },
165 /* 0x17 */ { NULL, NULL, 0 },
166 /* 0x18 */ { NULL, NULL, 0 },
167 /* 0x19 */ { NULL, NULL, 0 },
168 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
169 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
170 /* 0x1c */ { "SMBreadBs",NULL,0 },
171 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
172 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
173 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
174 /* 0x20 */ { "SMBwritec",NULL,0},
175 /* 0x21 */ { NULL, NULL, 0 },
176 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
177 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
178 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
179 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
180 /* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
181 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
182 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
183 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
184 /* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE },
185 /* 0x2b */ { "SMBecho",reply_echo,0},
186 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
187 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
188 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
189 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
190 /* 0x30 */ { NULL, NULL, 0 },
191 /* 0x31 */ { NULL, NULL, 0 },
192 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
193 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
194 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
195 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
196 /* 0x36 */ { NULL, NULL, 0 },
197 /* 0x37 */ { NULL, NULL, 0 },
198 /* 0x38 */ { NULL, NULL, 0 },
199 /* 0x39 */ { NULL, NULL, 0 },
200 /* 0x3a */ { NULL, NULL, 0 },
201 /* 0x3b */ { NULL, NULL, 0 },
202 /* 0x3c */ { NULL, NULL, 0 },
203 /* 0x3d */ { NULL, NULL, 0 },
204 /* 0x3e */ { NULL, NULL, 0 },
205 /* 0x3f */ { NULL, NULL, 0 },
206 /* 0x40 */ { NULL, NULL, 0 },
207 /* 0x41 */ { NULL, NULL, 0 },
208 /* 0x42 */ { NULL, NULL, 0 },
209 /* 0x43 */ { NULL, NULL, 0 },
210 /* 0x44 */ { NULL, NULL, 0 },
211 /* 0x45 */ { NULL, NULL, 0 },
212 /* 0x46 */ { NULL, NULL, 0 },
213 /* 0x47 */ { NULL, NULL, 0 },
214 /* 0x48 */ { NULL, NULL, 0 },
215 /* 0x49 */ { NULL, NULL, 0 },
216 /* 0x4a */ { NULL, NULL, 0 },
217 /* 0x4b */ { NULL, NULL, 0 },
218 /* 0x4c */ { NULL, NULL, 0 },
219 /* 0x4d */ { NULL, NULL, 0 },
220 /* 0x4e */ { NULL, NULL, 0 },
221 /* 0x4f */ { NULL, NULL, 0 },
222 /* 0x50 */ { NULL, NULL, 0 },
223 /* 0x51 */ { NULL, NULL, 0 },
224 /* 0x52 */ { NULL, NULL, 0 },
225 /* 0x53 */ { NULL, NULL, 0 },
226 /* 0x54 */ { NULL, NULL, 0 },
227 /* 0x55 */ { NULL, NULL, 0 },
228 /* 0x56 */ { NULL, NULL, 0 },
229 /* 0x57 */ { NULL, NULL, 0 },
230 /* 0x58 */ { NULL, NULL, 0 },
231 /* 0x59 */ { NULL, NULL, 0 },
232 /* 0x5a */ { NULL, NULL, 0 },
233 /* 0x5b */ { NULL, NULL, 0 },
234 /* 0x5c */ { NULL, NULL, 0 },
235 /* 0x5d */ { NULL, NULL, 0 },
236 /* 0x5e */ { NULL, NULL, 0 },
237 /* 0x5f */ { NULL, NULL, 0 },
238 /* 0x60 */ { NULL, NULL, 0 },
239 /* 0x61 */ { NULL, NULL, 0 },
240 /* 0x62 */ { NULL, NULL, 0 },
241 /* 0x63 */ { NULL, NULL, 0 },
242 /* 0x64 */ { NULL, NULL, 0 },
243 /* 0x65 */ { NULL, NULL, 0 },
244 /* 0x66 */ { NULL, NULL, 0 },
245 /* 0x67 */ { NULL, NULL, 0 },
246 /* 0x68 */ { NULL, NULL, 0 },
247 /* 0x69 */ { NULL, NULL, 0 },
248 /* 0x6a */ { NULL, NULL, 0 },
249 /* 0x6b */ { NULL, NULL, 0 },
250 /* 0x6c */ { NULL, NULL, 0 },
251 /* 0x6d */ { NULL, NULL, 0 },
252 /* 0x6e */ { NULL, NULL, 0 },
253 /* 0x6f */ { NULL, NULL, 0 },
254 /* 0x70 */ { "SMBtcon",reply_tcon,USE_MUTEX},
255 /* 0x71 */ { "SMBtdis",reply_tdis,0},
256 /* 0x72 */ { "SMBnegprot",reply_negprot,USE_MUTEX},
257 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,USE_MUTEX},
258 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
259 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,USE_MUTEX},
260 /* 0x76 */ { NULL, NULL, 0 },
261 /* 0x77 */ { NULL, NULL, 0 },
262 /* 0x78 */ { NULL, NULL, 0 },
263 /* 0x79 */ { NULL, NULL, 0 },
264 /* 0x7a */ { NULL, NULL, 0 },
265 /* 0x7b */ { NULL, NULL, 0 },
266 /* 0x7c */ { NULL, NULL, 0 },
267 /* 0x7d */ { NULL, NULL, 0 },
268 /* 0x7e */ { NULL, NULL, 0 },
269 /* 0x7f */ { NULL, NULL, 0 },
270 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
271 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
272 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
273 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
274 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
275 /* 0x85 */ { NULL, NULL, 0 },
276 /* 0x86 */ { NULL, NULL, 0 },
277 /* 0x87 */ { NULL, NULL, 0 },
278 /* 0x88 */ { NULL, NULL, 0 },
279 /* 0x89 */ { NULL, NULL, 0 },
280 /* 0x8a */ { NULL, NULL, 0 },
281 /* 0x8b */ { NULL, NULL, 0 },
282 /* 0x8c */ { NULL, NULL, 0 },
283 /* 0x8d */ { NULL, NULL, 0 },
284 /* 0x8e */ { NULL, NULL, 0 },
285 /* 0x8f */ { NULL, NULL, 0 },
286 /* 0x90 */ { NULL, NULL, 0 },
287 /* 0x91 */ { NULL, NULL, 0 },
288 /* 0x92 */ { NULL, NULL, 0 },
289 /* 0x93 */ { NULL, NULL, 0 },
290 /* 0x94 */ { NULL, NULL, 0 },
291 /* 0x95 */ { NULL, NULL, 0 },
292 /* 0x96 */ { NULL, NULL, 0 },
293 /* 0x97 */ { NULL, NULL, 0 },
294 /* 0x98 */ { NULL, NULL, 0 },
295 /* 0x99 */ { NULL, NULL, 0 },
296 /* 0x9a */ { NULL, NULL, 0 },
297 /* 0x9b */ { NULL, NULL, 0 },
298 /* 0x9c */ { NULL, NULL, 0 },
299 /* 0x9d */ { NULL, NULL, 0 },
300 /* 0x9e */ { NULL, NULL, 0 },
301 /* 0x9f */ { NULL, NULL, 0 },
302 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
303 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
304 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC },
305 /* 0xa3 */ { NULL, NULL, 0 },
306 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
307 /* 0xa5 */ { "SMBntrename", reply_ntrename, 0 },
308 /* 0xa6 */ { NULL, NULL, 0 },
309 /* 0xa7 */ { NULL, NULL, 0 },
310 /* 0xa8 */ { NULL, NULL, 0 },
311 /* 0xa9 */ { NULL, NULL, 0 },
312 /* 0xaa */ { NULL, NULL, 0 },
313 /* 0xab */ { NULL, NULL, 0 },
314 /* 0xac */ { NULL, NULL, 0 },
315 /* 0xad */ { NULL, NULL, 0 },
316 /* 0xae */ { NULL, NULL, 0 },
317 /* 0xaf */ { NULL, NULL, 0 },
318 /* 0xb0 */ { NULL, NULL, 0 },
319 /* 0xb1 */ { NULL, NULL, 0 },
320 /* 0xb2 */ { NULL, NULL, 0 },
321 /* 0xb3 */ { NULL, NULL, 0 },
322 /* 0xb4 */ { NULL, NULL, 0 },
323 /* 0xb5 */ { NULL, NULL, 0 },
324 /* 0xb6 */ { NULL, NULL, 0 },
325 /* 0xb7 */ { NULL, NULL, 0 },
326 /* 0xb8 */ { NULL, NULL, 0 },
327 /* 0xb9 */ { NULL, NULL, 0 },
328 /* 0xba */ { NULL, NULL, 0 },
329 /* 0xbb */ { NULL, NULL, 0 },
330 /* 0xbc */ { NULL, NULL, 0 },
331 /* 0xbd */ { NULL, NULL, 0 },
332 /* 0xbe */ { NULL, NULL, 0 },
333 /* 0xbf */ { NULL, NULL, 0 },
334 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
335 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
336 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
337 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
338 /* 0xc4 */ { NULL, NULL, 0 },
339 /* 0xc5 */ { NULL, NULL, 0 },
340 /* 0xc6 */ { NULL, NULL, 0 },
341 /* 0xc7 */ { NULL, NULL, 0 },
342 /* 0xc8 */ { NULL, NULL, 0 },
343 /* 0xc9 */ { NULL, NULL, 0 },
344 /* 0xca */ { NULL, NULL, 0 },
345 /* 0xcb */ { NULL, NULL, 0 },
346 /* 0xcc */ { NULL, NULL, 0 },
347 /* 0xcd */ { NULL, NULL, 0 },
348 /* 0xce */ { NULL, NULL, 0 },
349 /* 0xcf */ { NULL, NULL, 0 },
350 /* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
351 /* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
352 /* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
353 /* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
354 /* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
355 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
356 /* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
357 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
358 /* 0xd8 */ { NULL, NULL, 0 },
359 /* 0xd9 */ { NULL, NULL, 0 },
360 /* 0xda */ { NULL, NULL, 0 },
361 /* 0xdb */ { NULL, NULL, 0 },
362 /* 0xdc */ { NULL, NULL, 0 },
363 /* 0xdd */ { NULL, NULL, 0 },
364 /* 0xde */ { NULL, NULL, 0 },
365 /* 0xdf */ { NULL, NULL, 0 },
366 /* 0xe0 */ { NULL, NULL, 0 },
367 /* 0xe1 */ { NULL, NULL, 0 },
368 /* 0xe2 */ { NULL, NULL, 0 },
369 /* 0xe3 */ { NULL, NULL, 0 },
370 /* 0xe4 */ { NULL, NULL, 0 },
371 /* 0xe5 */ { NULL, NULL, 0 },
372 /* 0xe6 */ { NULL, NULL, 0 },
373 /* 0xe7 */ { NULL, NULL, 0 },
374 /* 0xe8 */ { NULL, NULL, 0 },
375 /* 0xe9 */ { NULL, NULL, 0 },
376 /* 0xea */ { NULL, NULL, 0 },
377 /* 0xeb */ { NULL, NULL, 0 },
378 /* 0xec */ { NULL, NULL, 0 },
379 /* 0xed */ { NULL, NULL, 0 },
380 /* 0xee */ { NULL, NULL, 0 },
381 /* 0xef */ { NULL, NULL, 0 },
382 /* 0xf0 */ { NULL, NULL, 0 },
383 /* 0xf1 */ { NULL, NULL, 0 },
384 /* 0xf2 */ { NULL, NULL, 0 },
385 /* 0xf3 */ { NULL, NULL, 0 },
386 /* 0xf4 */ { NULL, NULL, 0 },
387 /* 0xf5 */ { NULL, NULL, 0 },
388 /* 0xf6 */ { NULL, NULL, 0 },
389 /* 0xf7 */ { NULL, NULL, 0 },
390 /* 0xf8 */ { NULL, NULL, 0 },
391 /* 0xf9 */ { NULL, NULL, 0 },
392 /* 0xfa */ { NULL, NULL, 0 },
393 /* 0xfb */ { NULL, NULL, 0 },
394 /* 0xfc */ { NULL, NULL, 0 },
395 /* 0xfd */ { NULL, NULL, 0 },
396 /* 0xfe */ { NULL, NULL, 0 },
397 /* 0xff */ { NULL, NULL, 0 }
398 };
399
400 /****************************************************************************
401 return a string containing the function name of a SMB command
402 ****************************************************************************/
403 static const char *smb_fn_name(uint8_t type)
404 {
405         const char *unknown_name = "SMBunknown";
406
407         if (smb_messages[type].name == NULL)
408                 return unknown_name;
409
410         return smb_messages[type].name;
411 }
412
413
414 /****************************************************************************
415  Do a switch on the message type and call the specific reply function for this 
416 message. Unlike earlier versions of Samba the reply functions are responsible
417 for sending the reply themselves, rather than returning a size to this function
418 The reply functions may also choose to delay the processing by pushing the message
419 onto the message queue
420 ****************************************************************************/
421 static void switch_message(int type, struct smbsrv_request *req)
422 {
423         int flags;
424         struct smbsrv_connection *smb_conn = req->smb_conn;
425         uint16_t session_tag;
426
427         type &= 0xff;
428
429         errno = 0;
430
431         if (smb_messages[type].fn == NULL) {
432                 DEBUG(0,("Unknown message type %d!\n",type));
433                 reply_unknown(req);
434                 return;
435         }
436
437         flags = smb_messages[type].flags;
438
439         req->tcon = conn_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
440
441         if (req->session == NULL) {
442                 /* setup the user context for this request if it
443                    hasn't already been initialised (to cope with SMB
444                    chaining) */
445
446                 /* In share mode security we must ignore the vuid. */
447                 if (lp_security() == SEC_SHARE) {
448                         session_tag = UID_FIELD_INVALID;
449                 } else {
450                         session_tag = SVAL(req->in.hdr,HDR_UID);
451                 }
452
453                 req->session = smbsrv_session_find(req->smb_conn, session_tag);
454                 if (req->session) {
455                         req->session->vuid = session_tag;
456                 }
457         } else {
458                 session_tag = req->session->vuid;
459         }
460
461         DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb_conn->connection->service->model_ops->get_id(req)));
462
463         /* does this protocol need to be run as root? */
464         if (!(flags & AS_USER)) {
465                 change_to_root_user();
466         }
467         
468         /* does this protocol need a valid tree connection? */
469         if ((flags & AS_USER) && !req->tcon) {
470                 req_reply_error(req, NT_STATUS_NETWORK_NAME_DELETED);
471                 return;
472         }
473
474         /* see if the vuid is valid */
475         if ((flags & AS_USER) && !req->session) {
476                 if (!(flags & AS_GUEST)) {
477                         req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
478                         return;
479                 }
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->tcon,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->tcon)) {
504                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
505                 return;
506         }
507         
508         /* ipc services are limited */
509         if (req->tcon && req->tcon->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->tcon && !set_current_service(req->tcon,(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 smbsrv_request *req)
543 {
544         uint8_t 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         /* Make sure this is an SMB packet */   
553         if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
554                 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n", 
555                          req->in.size));
556                 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
557                 return;
558         }
559
560         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
561                 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
562                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
563                 return;
564         }
565
566         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
567                 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
568                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
569                 return;
570         }
571
572
573         req->smbpid = SVAL(req->in.hdr,HDR_PID);        
574         req->flags = CVAL(req->in.hdr, HDR_FLG);
575         req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
576
577         if (!req_signing_check_incoming(req)) {
578                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
579                 return;
580         }
581
582         switch_message(type, req);
583 }
584
585
586 /*
587   we call this when first first part of a possibly chained request has been completed
588   and we need to call the 2nd part, if any
589 */
590 void chain_reply(struct smbsrv_request *req)
591 {
592         uint16_t chain_cmd, chain_offset;
593         char *vwv, *data;
594         uint16_t wct;
595         uint16_t data_size;
596
597         if (req->in.wct < 2 || req->out.wct < 2) {
598                 req_reply_dos_error(req, ERRSRV, ERRerror);
599                 return;
600         }
601
602         chain_cmd    = CVAL(req->in.vwv, VWV(0));
603         chain_offset = SVAL(req->in.vwv, VWV(1));
604
605         if (chain_cmd == SMB_CHAIN_NONE) {
606                 /* end of chain */
607                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
608                 SSVAL(req->out.vwv, VWV(1), 0);
609                 req_send_reply(req);
610                 return;
611         }
612
613         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
614                 goto error;
615         }
616
617         wct = CVAL(req->in.hdr, chain_offset);
618         vwv = req->in.hdr + chain_offset + 1;
619
620         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
621                 goto error;
622         }
623
624         data_size = SVAL(vwv, VWV(wct));
625         data = vwv + VWV(wct) + 2;
626
627         if (data + data_size > req->in.buffer + req->in.size) {
628                 goto error;
629         }
630
631         /* all seems legit */
632         req->in.vwv = vwv;
633         req->in.wct = wct;
634         req->in.data = data;
635         req->in.data_size = data_size;
636         req->in.ptr = data;
637
638         req->chain_count++;
639
640         SSVAL(req->out.vwv, VWV(0), chain_cmd);
641         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
642
643         /* the current request in the chain might have used an async reply,
644            but that doesn't mean the next element needs to */
645         ZERO_STRUCT(req->async);
646         req->control_flags &= ~REQ_CONTROL_ASYNC;
647
648         switch_message(chain_cmd, req);
649         return;
650
651 error:
652         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
653         SSVAL(req->out.vwv, VWV(1), 0);
654         req_reply_dos_error(req, ERRSRV, ERRerror);
655 }
656
657
658 /*
659   close the socket and shutdown a server_context
660 */
661 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
662 {
663         server_terminate_connection(smb_conn->connection, reason);
664 }
665
666 /*
667   called on a fatal error that should cause this server to terminate
668 */
669 static void smbsrv_exit(struct server_service *service, const char *reason)
670 {
671         DEBUG(1,("smbsrv_exit\n"));
672         return;
673 }
674
675 /*
676   add a socket address to the list of events, one event per port
677 */
678 static void add_socket(struct server_service *service, 
679                        const struct model_ops *model_ops,
680                        struct socket_context *socket_ctx, 
681                        struct in_addr *ifip)
682 {
683         char *ptr, *tok;
684         const char *delim = ", ";
685
686         for (tok=strtok_r(lp_smb_ports(), delim, &ptr); 
687              tok; 
688              tok=strtok_r(NULL, delim, &ptr)) {
689                 uint16_t port = atoi(tok);
690                 if (port == 0) continue;
691                 service_setup_socket(service, model_ops, socket_ctx, ifip, &port);
692         }
693 }
694
695 /****************************************************************************
696  Open the socket communication.
697 ****************************************************************************/
698 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
699 {       
700         DEBUG(1,("smbsrv_init\n"));
701
702         if (lp_interfaces() && lp_bind_interfaces_only()) {
703                 int num_interfaces = iface_count();
704                 int i;
705
706                 /* We have been given an interfaces line, and been 
707                    told to only bind to those interfaces. Create a
708                    socket per interface and bind to only these.
709                 */
710                 for(i = 0; i < num_interfaces; i++) {
711                         struct in_addr *ifip = iface_n_ip(i);
712
713                         if (ifip == NULL) {
714                                 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
715                                 continue;
716                         }
717
718                         add_socket(service, model_ops, NULL, ifip);
719                 }
720         } else {
721                 struct in_addr *ifip;
722                 TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd");
723
724                 if (!mem_ctx) {
725                         smb_panic("No memory");
726                 }       
727
728                 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
729                 ifip = interpret_addr2(mem_ctx, lp_socket_address());
730                 add_socket(service, model_ops, NULL, ifip);
731
732                 talloc_destroy(mem_ctx);
733         }
734 }
735
736 /*
737   called when a SMB socket becomes readable
738 */
739 static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
740 {
741         struct smbsrv_request *req;
742         struct smbsrv_connection *smb_conn = conn->private_data;
743
744         DEBUG(10,("smbsrv_recv\n"));
745
746         req = receive_smb_request(smb_conn);
747         if (!req) {
748                 smbsrv_terminate_connection(smb_conn, "receive error");
749                 return;
750         }
751
752         construct_reply(req);
753
754         /* free up temporary memory */
755         lp_talloc_free();
756         return;
757 }
758
759 /*
760   called when a SMB socket becomes writable
761 */
762 static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
763 {
764         DEBUG(10,("smbsrv_send\n"));
765         return;
766 }
767
768 /*
769   called when connection is idle
770 */
771 static void smbsrv_idle(struct server_connection *conn, time_t t)
772 {
773         DEBUG(10,("smbsrv_idle: not implemented!\n"));
774         conn->event.idle->next_event = t + 5;
775
776         return;
777 }
778
779 static void smbsrv_close(struct server_connection *conn, const char *reason)
780 {
781         struct smbsrv_connection *smb_conn = conn->private_data;
782
783         DEBUG(5,("smbsrv_close: %s\n",reason));
784
785         close(conn->event.fde->fd);
786         event_remove_fd_all(conn->event.ctx, conn->socket->fde->fd);
787         event_remove_timed(conn->event.ctx, conn->event.idle);
788
789         conn_close_all(smb_conn);
790
791         talloc_destroy(smb_conn->mem_ctx);
792         return;
793 }
794
795 /*
796   process a message from an SMB socket while still processing a
797   previous message this is used by backends who need to ensure that
798   new messages from clients are still processed while they are
799   performing long operations
800 */
801 void smbd_process_async(struct smbsrv_connection *smb_conn)
802 {
803         struct smbsrv_request *req;
804         
805         req = receive_smb_request(smb_conn);
806         if (!req) {
807                 smbsrv_terminate_connection(smb_conn, "receive error");
808                 return;
809         }
810
811         construct_reply(req);
812 }
813
814
815 /*
816   initialise a server_context from a open socket and register a event handler
817   for reading from that socket
818 */
819 void smbsrv_accept(struct server_connection *conn)
820 {
821         struct smbsrv_connection *smb_conn;
822         TALLOC_CTX *mem_ctx;
823         char *socket_addr;
824
825         DEBUG(5,("smbsrv_accept\n"));
826
827         mem_ctx = talloc_init("smbsrv_context");
828
829         smb_conn = talloc_p(mem_ctx, struct smbsrv_connection);
830         if (!smb_conn) return;
831
832         ZERO_STRUCTP(smb_conn);
833
834         smb_conn->mem_ctx = mem_ctx;
835         smb_conn->pid = getpid();
836
837         sub_set_context(&smb_conn->substitute);
838
839         /* set an initial client name based on its IP address. This will be replaced with
840            the netbios name later if it gives us one */
841         socket_addr = get_socket_addr(smb_conn->mem_ctx, conn->socket->fde->fd);
842         sub_set_remote_machine(socket_addr);
843
844         /* now initialise a few default values associated with this smb socket */
845         smb_conn->negotiate.max_send = 0xFFFF;
846
847         /* this is the size that w2k uses, and it appears to be important for
848            good performance */
849         smb_conn->negotiate.max_recv = lp_max_xmit();
850
851         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
852
853         smb_conn->sessions.next_vuid = VUID_OFFSET;
854
855         conn_init(smb_conn);
856
857         smb_conn->connection = conn;
858
859         conn->private_data = smb_conn;
860
861         /* setup the DCERPC server subsystem */
862         dcesrv_init_context(&smb_conn->dcesrv);
863
864         return;
865 }
866
867 static const struct server_service_ops smb_server_ops = {
868         .name                   = "smb",
869         .service_init           = smbsrv_init,
870         .accept_connection      = smbsrv_accept,
871         .recv_handler           = smbsrv_recv,
872         .send_handler           = smbsrv_send,
873         .idle_handler           = smbsrv_idle,
874         .close_connection       = smbsrv_close,
875         .service_exit           = smbsrv_exit,  
876 };
877
878 const struct server_service_ops *smbsrv_get_ops(void)
879 {
880         return &smb_server_ops;
881 }
882
883 NTSTATUS server_service_smb_init(void)
884 {
885         return NT_STATUS_OK;    
886 }