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