r7523: blergh
[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
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                 if (type == SMBntcreateX) {
515                         /* amazingly, the error code depends on the command */
516                         req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRinvnid));
517                 } else {
518                         req_reply_error(req, NT_STATUS_INVALID_HANDLE);
519                 }
520                 return;
521         }
522
523         /* see if the vuid is valid */
524         if ((flags & AS_USER) && !req->session) {
525                 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
526                 return;
527         }
528
529         smb_messages[type].fn(req);
530 }
531
532
533 /****************************************************************************
534  Construct a reply to the incoming packet.
535 ****************************************************************************/
536 static void construct_reply(struct smbsrv_request *req)
537 {
538         uint8_t type = CVAL(req->in.hdr,HDR_COM);
539
540         /* see if its a special NBT packet */
541         if (CVAL(req->in.buffer,0) != 0) {
542                 reply_special(req);
543                 return;
544         }
545
546         /* Make sure this is an SMB packet */   
547         if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
548                 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n", 
549                          req->in.size));
550                 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
551                 return;
552         }
553
554         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
555                 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
556                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
557                 return;
558         }
559
560         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
561                 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
562                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
563                 return;
564         }
565
566         req->flags = CVAL(req->in.hdr, HDR_FLG);
567         req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
568         req->smbpid = SVAL(req->in.hdr,HDR_PID);
569
570         if (!req_signing_check_incoming(req)) {
571                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
572                 return;
573         }
574
575         switch_message(type, req);
576 }
577
578
579 /*
580   we call this when first first part of a possibly chained request has been completed
581   and we need to call the 2nd part, if any
582 */
583 void chain_reply(struct smbsrv_request *req)
584 {
585         uint16_t chain_cmd, chain_offset;
586         uint8_t *vwv, *data;
587         uint16_t wct;
588         uint16_t data_size;
589
590         if (req->in.wct < 2 || req->out.wct < 2) {
591                 req_reply_dos_error(req, ERRSRV, ERRerror);
592                 return;
593         }
594
595         chain_cmd    = CVAL(req->in.vwv, VWV(0));
596         chain_offset = SVAL(req->in.vwv, VWV(1));
597
598         if (chain_cmd == SMB_CHAIN_NONE) {
599                 /* end of chain */
600                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
601                 SSVAL(req->out.vwv, VWV(1), 0);
602                 req_send_reply(req);
603                 return;
604         }
605
606         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
607                 goto error;
608         }
609
610         wct = CVAL(req->in.hdr, chain_offset);
611         vwv = req->in.hdr + chain_offset + 1;
612
613         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
614                 goto error;
615         }
616
617         data_size = SVAL(vwv, VWV(wct));
618         data = vwv + VWV(wct) + 2;
619
620         if (data + data_size > req->in.buffer + req->in.size) {
621                 goto error;
622         }
623
624         /* all seems legit */
625         req->in.vwv = vwv;
626         req->in.wct = wct;
627         req->in.data = data;
628         req->in.data_size = data_size;
629         req->in.ptr = data;
630
631         req->chain_count++;
632
633         SSVAL(req->out.vwv, VWV(0), chain_cmd);
634         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
635
636         /* the current request in the chain might have used an async reply,
637            but that doesn't mean the next element needs to */
638         ZERO_STRUCTP(req->async_states);
639
640         switch_message(chain_cmd, req);
641         return;
642
643 error:
644         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
645         SSVAL(req->out.vwv, VWV(1), 0);
646         req_reply_dos_error(req, ERRSRV, ERRerror);
647 }
648
649
650 /*
651   close the socket and shutdown a server_context
652 */
653 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
654 {
655         stream_terminate_connection(smb_conn->connection, reason);
656 }
657
658 /*
659   called when a SMB socket becomes readable
660 */
661 static void smbsrv_recv(struct stream_connection *conn, uint16_t flags)
662 {
663         struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
664         NTSTATUS status;
665
666         DEBUG(10,("smbsrv_recv\n"));
667
668         status = receive_smb_request(smb_conn);
669         if (NT_STATUS_IS_ERR(status)) {
670                 talloc_free(conn->event.fde);
671                 conn->event.fde = NULL;
672                 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
673                 return;
674         }
675
676         /* free up temporary memory */
677         lp_talloc_free();
678 }
679
680 /*
681   called when a SMB socket becomes writable
682 */
683 static void smbsrv_send(struct stream_connection *conn, uint16_t flags)
684 {
685         struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
686
687         while (smb_conn->pending_send) {
688                 struct smbsrv_request *req = smb_conn->pending_send;
689                 DATA_BLOB blob;
690                 NTSTATUS status;
691                 size_t sendlen;
692
693                 blob.data = req->out.buffer;
694                 blob.length = req->out.size;
695
696                 /* send as much of this request as we can */
697                 status = socket_send(conn->socket, &blob, &sendlen, 0);
698                 if (NT_STATUS_IS_ERR(status)) {
699                         smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
700                         return;
701                 }
702                 if (sendlen == 0) {
703                         break;
704                 }
705
706                 req->out.buffer += sendlen;
707                 req->out.size -= sendlen;
708
709                 /* is the whole request gone? */
710                 if (req->out.size == 0) {
711                         DLIST_REMOVE(smb_conn->pending_send, req);
712                         req_destroy(req);
713                 }
714         }
715
716         /* if no more requests are pending to be sent then
717            we should stop select for write */
718         if (smb_conn->pending_send == NULL) {
719                 EVENT_FD_NOT_WRITEABLE(conn->event.fde);
720         }
721 }
722
723 /*
724   initialise a server_context from a open socket and register a event handler
725   for reading from that socket
726 */
727 static void smbsrv_accept(struct stream_connection *conn)
728 {
729         struct smbsrv_connection *smb_conn;
730
731         DEBUG(5,("smbsrv_accept\n"));
732
733         smb_conn = talloc_zero(conn, struct smbsrv_connection);
734         if (!smb_conn) return;
735
736         /* now initialise a few default values associated with this smb socket */
737         smb_conn->negotiate.max_send = 0xFFFF;
738
739         /* this is the size that w2k uses, and it appears to be important for
740            good performance */
741         smb_conn->negotiate.max_recv = lp_max_xmit();
742
743         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
744
745         smbsrv_vuid_init(smb_conn);
746
747         srv_init_signing(smb_conn);
748
749         smbsrv_tcon_init(smb_conn);
750
751         smb_conn->connection = conn;
752
753         conn->private = smb_conn;
754 }
755
756
757 static const struct stream_server_ops smb_stream_ops = {
758         .name                   = "smb",
759         .accept_connection      = smbsrv_accept,
760         .recv_handler           = smbsrv_recv,
761         .send_handler           = smbsrv_send,
762 };
763
764 /*
765   setup a listening socket on all the SMB ports for a particular address
766 */
767 static NTSTATUS smb_add_socket(struct event_context *event_context,
768                                const struct model_ops *model_ops,
769                                const char *address)
770 {
771         const char **ports = lp_smb_ports();
772         int i;
773         NTSTATUS status;
774
775         for (i=0;ports[i];i++) {
776                 uint16_t port = atoi(ports[i]);
777                 if (port == 0) continue;
778                 status = stream_setup_socket(event_context, model_ops, &smb_stream_ops, 
779                                              "ipv4", address, &port, NULL);
780                 NT_STATUS_NOT_OK_RETURN(status);
781         }
782
783         return NT_STATUS_OK;
784 }
785
786 /*
787   called on startup of the smb server service It's job is to start
788   listening on all configured SMB server sockets
789 */
790 static NTSTATUS smbsrv_init(struct event_context *event_context, const struct model_ops *model_ops)
791 {       
792         NTSTATUS status;
793
794         if (lp_interfaces() && lp_bind_interfaces_only()) {
795                 int num_interfaces = iface_count();
796                 int i;
797
798                 /* We have been given an interfaces line, and been 
799                    told to only bind to those interfaces. Create a
800                    socket per interface and bind to only these.
801                 */
802                 for(i = 0; i < num_interfaces; i++) {
803                         const char *address = iface_n_ip(i);
804                         status = smb_add_socket(event_context, model_ops, address);
805                         NT_STATUS_NOT_OK_RETURN(status);
806                 }
807         } else {
808                 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
809                 status = smb_add_socket(event_context, model_ops, lp_socket_address());
810                 NT_STATUS_NOT_OK_RETURN(status);
811         }
812
813         return NT_STATUS_OK;
814 }
815
816 /* called at smbd startup - register ourselves as a server service */
817 NTSTATUS server_service_smb_init(void)
818 {
819         return register_server_service("smb", smbsrv_init);
820 }