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