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