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