r4726: - use the name tcon and tid instead of conn and cnum
[jelmer/samba4-debian.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_p(req, uint8_t, NBT_HDR_SIZE);
84                 if (req->in.buffer == NULL) {
85                         talloc_free(req);
86                         return NT_STATUS_NO_MEMORY;
87                 }
88                 req->in.size = 0;
89                 smb_conn->partial_req = req;
90         }
91
92         req = smb_conn->partial_req;
93
94         /* read in the header */
95         if (req->in.size < NBT_HDR_SIZE) {
96                 status = socket_recv(smb_conn->connection->socket, 
97                                      req->in.buffer + req->in.size,
98                                      NBT_HDR_SIZE - req->in.size, 
99                                      &nread, 0);
100                 if (NT_STATUS_IS_ERR(status)) {
101                         return status;
102                 }
103                 if (nread == 0) {
104                         return NT_STATUS_OK;
105                 }
106                 req->in.size += nread;
107
108                 /* when we have a full NBT header, then allocate the packet */
109                 if (req->in.size == NBT_HDR_SIZE) {
110                         len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
111                         req->in.buffer = talloc_realloc(req, req->in.buffer, 
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), smb_conn->connection->service->model_ops->get_id(req)));
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 /*
653   called on a fatal error that should cause this server to terminate
654 */
655 static void smbsrv_exit(struct server_service *service, const char *reason)
656 {
657         DEBUG(1,("smbsrv_exit\n"));
658         return;
659 }
660
661 /*
662   add a socket address to the list of events, one event per port
663 */
664 static void smb_add_socket(struct server_service *service, 
665                            const struct model_ops *model_ops,
666                            struct socket_context *socket_ctx, 
667                            struct ipv4_addr *ifip)
668 {
669         const char **ports = lp_smb_ports();
670         int i;
671         char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
672
673         for (i=0;ports[i];i++) {
674                 uint16_t port = atoi(ports[i]);
675                 if (port == 0) continue;
676                 service_setup_socket(service, model_ops, "ipv4", ip_str, &port);
677         }
678
679         talloc_free(ip_str);
680 }
681
682 /****************************************************************************
683  Open the socket communication.
684 ****************************************************************************/
685 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
686 {       
687         DEBUG(1,("smbsrv_init\n"));
688
689         if (lp_interfaces() && lp_bind_interfaces_only()) {
690                 int num_interfaces = iface_count();
691                 int i;
692
693                 /* We have been given an interfaces line, and been 
694                    told to only bind to those interfaces. Create a
695                    socket per interface and bind to only these.
696                 */
697                 for(i = 0; i < num_interfaces; i++) {
698                         struct ipv4_addr *ifip = iface_n_ip(i);
699
700                         if (ifip == NULL) {
701                                 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
702                                 continue;
703                         }
704
705                         smb_add_socket(service, model_ops, NULL, ifip);
706                 }
707         } else {
708                 struct ipv4_addr ifip;
709                 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
710                 ifip = interpret_addr2(lp_socket_address());
711                 smb_add_socket(service, model_ops, NULL, &ifip);
712         }
713 }
714
715 /*
716   called when a SMB socket becomes readable
717 */
718 static void smbsrv_recv(struct server_connection *conn, struct timeval t, uint16_t flags)
719 {
720         struct smbsrv_connection *smb_conn = conn->private_data;
721         NTSTATUS status;
722
723         DEBUG(10,("smbsrv_recv\n"));
724
725         status = receive_smb_request(smb_conn, t);
726         if (NT_STATUS_IS_ERR(status)) {
727                 conn->event.fde->flags = 0;
728                 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
729                 return;
730         }
731
732         /* free up temporary memory */
733         lp_talloc_free();
734 }
735
736 /*
737   called when a SMB socket becomes writable
738 */
739 static void smbsrv_send(struct server_connection *conn, struct timeval t, uint16_t flags)
740 {
741         struct smbsrv_connection *smb_conn = conn->private_data;
742
743         while (smb_conn->pending_send) {
744                 struct smbsrv_request *req = smb_conn->pending_send;
745                 DATA_BLOB blob;
746                 NTSTATUS status;
747                 size_t sendlen;
748
749                 blob.data = req->out.buffer;
750                 blob.length = req->out.size;
751
752                 /* send as much of this request as we can */
753                 status = socket_send(conn->socket, &blob, &sendlen, 0);
754                 if (NT_STATUS_IS_ERR(status)) {
755                         smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
756                         return;
757                 }
758                 if (sendlen == 0) {
759                         break;
760                 }
761
762                 req->out.buffer += sendlen;
763                 req->out.size -= sendlen;
764
765                 /* is the whole request gone? */
766                 if (req->out.size == 0) {
767                         DLIST_REMOVE(smb_conn->pending_send, req);
768                         req_destroy(req);
769                 }
770         }
771
772         /* if no more requests are pending to be sent then
773            we should stop select for write */
774         if (smb_conn->pending_send == NULL) {
775                 conn->event.fde->flags &= ~EVENT_FD_WRITE;
776         }
777 }
778
779 /*
780   called when connection is idle
781 */
782 static void smbsrv_idle(struct server_connection *conn, struct timeval t)
783 {
784         DEBUG(10,("smbsrv_idle: not implemented!\n"));
785         conn->event.idle->next_event = timeval_add(&t, 5, 0);
786         return;
787 }
788
789 static void smbsrv_close(struct server_connection *conn, const char *reason)
790 {
791         struct smbsrv_connection *smb_conn = conn->private_data;
792
793         DEBUG(5,("smbsrv_close: %s\n",reason));
794
795         talloc_free(smb_conn);
796
797         return;
798 }
799
800 /*
801   process a message from an SMB socket while still processing a
802   previous message this is used by backends who need to ensure that
803   new messages from clients are still processed while they are
804   performing long operations
805 */
806 void smbd_process_async(struct smbsrv_connection *smb_conn)
807 {
808         NTSTATUS status;
809         
810         status = receive_smb_request(smb_conn, timeval_current());
811         if (NT_STATUS_IS_ERR(status)) {
812                 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
813         }
814 }
815
816
817 /*
818   initialise a server_context from a open socket and register a event handler
819   for reading from that socket
820 */
821 void smbsrv_accept(struct server_connection *conn)
822 {
823         struct smbsrv_connection *smb_conn;
824
825         DEBUG(5,("smbsrv_accept\n"));
826
827         smb_conn = talloc_zero_p(conn, struct smbsrv_connection);
828         if (!smb_conn) return;
829
830         smb_conn->pid = getpid();
831
832         sub_set_context(&smb_conn->substitute);
833
834         /* now initialise a few default values associated with this smb socket */
835         smb_conn->negotiate.max_send = 0xFFFF;
836
837         /* this is the size that w2k uses, and it appears to be important for
838            good performance */
839         smb_conn->negotiate.max_recv = lp_max_xmit();
840
841         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
842
843         smb_conn->sessions.next_vuid = VUID_OFFSET;
844
845         srv_init_signing(smb_conn);
846
847         smbsrv_tcon_init(smb_conn);
848
849         smb_conn->connection = conn;
850
851         conn->private_data = smb_conn;
852
853         return;
854 }
855
856 static const struct server_service_ops smb_server_ops = {
857         .name                   = "smb",
858         .service_init           = smbsrv_init,
859         .accept_connection      = smbsrv_accept,
860         .recv_handler           = smbsrv_recv,
861         .send_handler           = smbsrv_send,
862         .idle_handler           = smbsrv_idle,
863         .close_connection       = smbsrv_close,
864         .service_exit           = smbsrv_exit,  
865 };
866
867 const struct server_service_ops *smbsrv_get_ops(void)
868 {
869         return &smb_server_ops;
870 }
871
872 NTSTATUS server_service_smb_init(void)
873 {
874         return NT_STATUS_OK;    
875 }