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