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