r3500: cleaned up the AS_USER/AS_GUEST stuff in the core smb packet processing
[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 "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->cnum);
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)
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, char, 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, len);
112                         if (req->in.buffer == NULL) {
113                                 return NT_STATUS_NO_MEMORY;
114                         }
115                 } else {
116                         return NT_STATUS_OK;
117                 }
118         }
119
120         /* read in the main packet */
121         len = smb_len(req->in.buffer) + NBT_HDR_SIZE;
122
123         status = socket_recv(smb_conn->connection->socket, 
124                              req->in.buffer + req->in.size,
125                              len - req->in.size, 
126                              &nread, 0);
127         if (NT_STATUS_IS_ERR(status)) {
128                 return status;
129         }
130         if (nread == 0) {
131                 return NT_STATUS_OK;
132         }
133
134         req->in.size += nread;
135
136         if (req->in.size != len) {
137                 return NT_STATUS_OK;
138         }
139
140         /* we have a full packet */
141         GetTimeOfDay(&req->request_time);
142         req->chained_fnum = -1;
143         req->in.allocated = req->in.size;
144         req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
145         req->in.vwv = req->in.hdr + HDR_VWV;
146         req->in.wct = CVAL(req->in.hdr, HDR_WCT);
147         if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
148                 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
149                 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
150
151                 /* the bcc length is only 16 bits, but some packets
152                    (such as SMBwriteX) can be much larger than 64k. We
153                    detect this by looking for a large non-chained NBT
154                    packet (at least 64k bigger than what is
155                    specified). If it is detected then the NBT size is
156                    used instead of the bcc size */
157                 if (req->in.data_size + 0x10000 <= 
158                     req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
159                     (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
160                         /* its an oversized packet! fun for all the family */
161                         req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
162                 }
163         }
164
165         smb_conn->partial_req = NULL;
166
167         construct_reply(req);
168
169         return NT_STATUS_OK;
170 }
171
172 /*
173   These flags determine some of the permissions required to do an operation 
174 */
175 #define AS_USER (1<<0)
176 #define USE_MUTEX (1<<1)
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",NULL,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,USE_MUTEX},
303 /* 0x71 */ { "SMBtdis",reply_tdis,0},
304 /* 0x72 */ { "SMBnegprot",reply_negprot,USE_MUTEX},
305 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,USE_MUTEX},
306 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
307 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,USE_MUTEX},
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 = conn_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         /* THREAD TESTING: use mutex to serialize calls to critical
524            functions with global state */
525         if (flags & USE_MUTEX) {
526                 MUTEX_LOCK_BY_ID(MUTEX_SMBD);
527         }
528         smb_messages[type].fn(req);
529         if (flags & USE_MUTEX) {
530                 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
531         }
532 }
533
534
535 /****************************************************************************
536  Construct a reply to the incoming packet.
537 ****************************************************************************/
538 static void construct_reply(struct smbsrv_request *req)
539 {
540         uint8_t type = CVAL(req->in.hdr,HDR_COM);
541
542         /* see if its a special NBT packet */
543         if (CVAL(req->in.buffer,0) != 0) {
544                 reply_special(req);
545                 return;
546         }
547
548         /* Make sure this is an SMB packet */   
549         if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
550                 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n", 
551                          req->in.size));
552                 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
553                 return;
554         }
555
556         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
557                 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
558                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
559                 return;
560         }
561
562         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
563                 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
564                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
565                 return;
566         }
567
568         req->flags = CVAL(req->in.hdr, HDR_FLG);
569         req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
570         req->smbpid = SVAL(req->in.hdr,HDR_PID);
571
572         if (!req_signing_check_incoming(req)) {
573                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
574                 return;
575         }
576
577         switch_message(type, req);
578 }
579
580
581 /*
582   we call this when first first part of a possibly chained request has been completed
583   and we need to call the 2nd part, if any
584 */
585 void chain_reply(struct smbsrv_request *req)
586 {
587         uint16_t chain_cmd, chain_offset;
588         char *vwv, *data;
589         uint16_t wct;
590         uint16_t data_size;
591
592         if (req->in.wct < 2 || req->out.wct < 2) {
593                 req_reply_dos_error(req, ERRSRV, ERRerror);
594                 return;
595         }
596
597         chain_cmd    = CVAL(req->in.vwv, VWV(0));
598         chain_offset = SVAL(req->in.vwv, VWV(1));
599
600         if (chain_cmd == SMB_CHAIN_NONE) {
601                 /* end of chain */
602                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
603                 SSVAL(req->out.vwv, VWV(1), 0);
604                 req_send_reply(req);
605                 return;
606         }
607
608         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
609                 goto error;
610         }
611
612         wct = CVAL(req->in.hdr, chain_offset);
613         vwv = req->in.hdr + chain_offset + 1;
614
615         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
616                 goto error;
617         }
618
619         data_size = SVAL(vwv, VWV(wct));
620         data = vwv + VWV(wct) + 2;
621
622         if (data + data_size > req->in.buffer + req->in.size) {
623                 goto error;
624         }
625
626         /* all seems legit */
627         req->in.vwv = vwv;
628         req->in.wct = wct;
629         req->in.data = data;
630         req->in.data_size = data_size;
631         req->in.ptr = data;
632
633         req->chain_count++;
634
635         SSVAL(req->out.vwv, VWV(0), chain_cmd);
636         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
637
638         /* the current request in the chain might have used an async reply,
639            but that doesn't mean the next element needs to */
640         ZERO_STRUCTP(req->async_states);
641
642         switch_message(chain_cmd, req);
643         return;
644
645 error:
646         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
647         SSVAL(req->out.vwv, VWV(1), 0);
648         req_reply_dos_error(req, ERRSRV, ERRerror);
649 }
650
651
652 /*
653   close the socket and shutdown a server_context
654 */
655 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
656 {
657         server_terminate_connection(smb_conn->connection, reason);
658 }
659
660 /*
661   called on a fatal error that should cause this server to terminate
662 */
663 static void smbsrv_exit(struct server_service *service, const char *reason)
664 {
665         DEBUG(1,("smbsrv_exit\n"));
666         return;
667 }
668
669 /*
670   add a socket address to the list of events, one event per port
671 */
672 static void add_socket(struct server_service *service, 
673                        const struct model_ops *model_ops,
674                        struct socket_context *socket_ctx, 
675                        struct ipv4_addr *ifip)
676 {
677         const char **ports = lp_smb_ports();
678         int i;
679         char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
680
681         for (i=0;ports[i];i++) {
682                 uint16_t port = atoi(ports[i]);
683                 if (port == 0) continue;
684                 service_setup_socket(service, model_ops, "ipv4", ip_str, &port);
685         }
686
687         talloc_free(ip_str);
688 }
689
690 /****************************************************************************
691  Open the socket communication.
692 ****************************************************************************/
693 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
694 {       
695         DEBUG(1,("smbsrv_init\n"));
696
697         if (lp_interfaces() && lp_bind_interfaces_only()) {
698                 int num_interfaces = iface_count();
699                 int i;
700
701                 /* We have been given an interfaces line, and been 
702                    told to only bind to those interfaces. Create a
703                    socket per interface and bind to only these.
704                 */
705                 for(i = 0; i < num_interfaces; i++) {
706                         struct ipv4_addr *ifip = iface_n_ip(i);
707
708                         if (ifip == NULL) {
709                                 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
710                                 continue;
711                         }
712
713                         add_socket(service, model_ops, NULL, ifip);
714                 }
715         } else {
716                 struct ipv4_addr ifip;
717                 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
718                 ifip = interpret_addr2(lp_socket_address());
719                 add_socket(service, model_ops, NULL, &ifip);
720         }
721 }
722
723 /*
724   called when a SMB socket becomes readable
725 */
726 static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
727 {
728         struct smbsrv_connection *smb_conn = conn->private_data;
729         NTSTATUS status;
730
731         DEBUG(10,("smbsrv_recv\n"));
732
733         status = receive_smb_request(smb_conn);
734         if (NT_STATUS_IS_ERR(status)) {
735                 conn->event.fde->flags = 0;
736                 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
737                 return;
738         }
739
740         /* free up temporary memory */
741         lp_talloc_free();
742 }
743
744 /*
745   called when a SMB socket becomes writable
746 */
747 static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
748 {
749         struct smbsrv_connection *smb_conn = conn->private_data;
750
751         while (smb_conn->pending_send) {
752                 struct smbsrv_request *req = smb_conn->pending_send;
753                 DATA_BLOB blob;
754                 NTSTATUS status;
755                 size_t sendlen;
756
757                 blob.data = req->out.buffer;
758                 blob.length = req->out.size;
759
760                 /* send as much of this request as we can */
761                 status = socket_send(conn->socket, &blob, &sendlen, 0);
762                 if (NT_STATUS_IS_ERR(status)) {
763                         smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
764                         return;
765                 }
766                 if (sendlen == 0) {
767                         break;
768                 }
769
770                 req->out.buffer += sendlen;
771                 req->out.size -= sendlen;
772
773                 /* is the whole request gone? */
774                 if (req->out.size == 0) {
775                         DLIST_REMOVE(smb_conn->pending_send, req);
776                         req_destroy(req);
777                 }
778         }
779
780         /* if no more requests are pending to be sent then
781            we should stop select for write */
782         if (smb_conn->pending_send == NULL) {
783                 conn->event.fde->flags &= ~EVENT_FD_WRITE;
784         }
785 }
786
787 /*
788   called when connection is idle
789 */
790 static void smbsrv_idle(struct server_connection *conn, time_t t)
791 {
792         DEBUG(10,("smbsrv_idle: not implemented!\n"));
793         conn->event.idle->next_event = t + 5;
794
795         return;
796 }
797
798 static void smbsrv_close(struct server_connection *conn, const char *reason)
799 {
800         struct smbsrv_connection *smb_conn = conn->private_data;
801
802         DEBUG(5,("smbsrv_close: %s\n",reason));
803
804         conn_close_all(smb_conn);
805
806         talloc_free(smb_conn);
807
808         return;
809 }
810
811 /*
812   process a message from an SMB socket while still processing a
813   previous message this is used by backends who need to ensure that
814   new messages from clients are still processed while they are
815   performing long operations
816 */
817 void smbd_process_async(struct smbsrv_connection *smb_conn)
818 {
819         NTSTATUS status;
820         
821         status = receive_smb_request(smb_conn);
822         if (NT_STATUS_IS_ERR(status)) {
823                 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
824         }
825 }
826
827
828 /*
829   initialise a server_context from a open socket and register a event handler
830   for reading from that socket
831 */
832 void smbsrv_accept(struct server_connection *conn)
833 {
834         struct smbsrv_connection *smb_conn;
835         int fd;
836
837         DEBUG(5,("smbsrv_accept\n"));
838
839         smb_conn = talloc_zero_p(conn, struct smbsrv_connection);
840         if (!smb_conn) return;
841
842         smb_conn->pid = getpid();
843
844         sub_set_context(&smb_conn->substitute);
845
846         /* now initialise a few default values associated with this smb socket */
847         smb_conn->negotiate.max_send = 0xFFFF;
848
849         /* this is the size that w2k uses, and it appears to be important for
850            good performance */
851         smb_conn->negotiate.max_recv = lp_max_xmit();
852
853         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
854
855         smb_conn->sessions.next_vuid = VUID_OFFSET;
856
857         srv_init_signing(smb_conn);
858
859         conn_init(smb_conn);
860
861         smb_conn->connection = conn;
862
863         conn->private_data = smb_conn;
864
865         fd = socket_get_fd(conn->socket);
866         set_blocking(fd, True);
867
868         /* setup the DCERPC server subsystem */
869         dcesrv_init_context(smb_conn, &smb_conn->dcesrv);
870
871         return;
872 }
873
874 static const struct server_service_ops smb_server_ops = {
875         .name                   = "smb",
876         .service_init           = smbsrv_init,
877         .accept_connection      = smbsrv_accept,
878         .recv_handler           = smbsrv_recv,
879         .send_handler           = smbsrv_send,
880         .idle_handler           = smbsrv_idle,
881         .close_connection       = smbsrv_close,
882         .service_exit           = smbsrv_exit,  
883 };
884
885 const struct server_service_ops *smbsrv_get_ops(void)
886 {
887         return &smb_server_ops;
888 }
889
890 NTSTATUS server_service_smb_init(void)
891 {
892         return NT_STATUS_OK;    
893 }