r3443: the next stage in the include files re-organisation.
[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
628         if (!req_signing_check_incoming(req)) {
629                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
630                 return;
631         }
632
633         switch_message(type, req);
634 }
635
636
637 /*
638   we call this when first first part of a possibly chained request has been completed
639   and we need to call the 2nd part, if any
640 */
641 void chain_reply(struct smbsrv_request *req)
642 {
643         uint16_t chain_cmd, chain_offset;
644         char *vwv, *data;
645         uint16_t wct;
646         uint16_t data_size;
647
648         if (req->in.wct < 2 || req->out.wct < 2) {
649                 req_reply_dos_error(req, ERRSRV, ERRerror);
650                 return;
651         }
652
653         chain_cmd    = CVAL(req->in.vwv, VWV(0));
654         chain_offset = SVAL(req->in.vwv, VWV(1));
655
656         if (chain_cmd == SMB_CHAIN_NONE) {
657                 /* end of chain */
658                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
659                 SSVAL(req->out.vwv, VWV(1), 0);
660                 req_send_reply(req);
661                 return;
662         }
663
664         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
665                 goto error;
666         }
667
668         wct = CVAL(req->in.hdr, chain_offset);
669         vwv = req->in.hdr + chain_offset + 1;
670
671         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
672                 goto error;
673         }
674
675         data_size = SVAL(vwv, VWV(wct));
676         data = vwv + VWV(wct) + 2;
677
678         if (data + data_size > req->in.buffer + req->in.size) {
679                 goto error;
680         }
681
682         /* all seems legit */
683         req->in.vwv = vwv;
684         req->in.wct = wct;
685         req->in.data = data;
686         req->in.data_size = data_size;
687         req->in.ptr = data;
688
689         req->chain_count++;
690
691         SSVAL(req->out.vwv, VWV(0), chain_cmd);
692         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
693
694         /* the current request in the chain might have used an async reply,
695            but that doesn't mean the next element needs to */
696         ZERO_STRUCTP(req->async_states);
697
698         switch_message(chain_cmd, req);
699         return;
700
701 error:
702         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
703         SSVAL(req->out.vwv, VWV(1), 0);
704         req_reply_dos_error(req, ERRSRV, ERRerror);
705 }
706
707
708 /*
709   close the socket and shutdown a server_context
710 */
711 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
712 {
713         server_terminate_connection(smb_conn->connection, reason);
714 }
715
716 /*
717   called on a fatal error that should cause this server to terminate
718 */
719 static void smbsrv_exit(struct server_service *service, const char *reason)
720 {
721         DEBUG(1,("smbsrv_exit\n"));
722         return;
723 }
724
725 /*
726   add a socket address to the list of events, one event per port
727 */
728 static void add_socket(struct server_service *service, 
729                        const struct model_ops *model_ops,
730                        struct socket_context *socket_ctx, 
731                        struct ipv4_addr *ifip)
732 {
733         const char **ports = lp_smb_ports();
734         int i;
735         char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip));
736
737         for (i=0;ports[i];i++) {
738                 uint16_t port = atoi(ports[i]);
739                 if (port == 0) continue;
740                 service_setup_socket(service, model_ops, "ipv4", ip_str, &port);
741         }
742
743         talloc_free(ip_str);
744 }
745
746 /****************************************************************************
747  Open the socket communication.
748 ****************************************************************************/
749 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
750 {       
751         DEBUG(1,("smbsrv_init\n"));
752
753         if (lp_interfaces() && lp_bind_interfaces_only()) {
754                 int num_interfaces = iface_count();
755                 int i;
756
757                 /* We have been given an interfaces line, and been 
758                    told to only bind to those interfaces. Create a
759                    socket per interface and bind to only these.
760                 */
761                 for(i = 0; i < num_interfaces; i++) {
762                         struct ipv4_addr *ifip = iface_n_ip(i);
763
764                         if (ifip == NULL) {
765                                 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
766                                 continue;
767                         }
768
769                         add_socket(service, model_ops, NULL, ifip);
770                 }
771         } else {
772                 struct ipv4_addr ifip;
773                 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
774                 ifip = interpret_addr2(lp_socket_address());
775                 add_socket(service, model_ops, NULL, &ifip);
776         }
777 }
778
779 /*
780   called when a SMB socket becomes readable
781 */
782 static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
783 {
784         struct smbsrv_connection *smb_conn = conn->private_data;
785         NTSTATUS status;
786
787         DEBUG(10,("smbsrv_recv\n"));
788
789         status = receive_smb_request(smb_conn);
790         if (NT_STATUS_IS_ERR(status)) {
791                 conn->event.fde->flags = 0;
792                 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
793                 return;
794         }
795
796         /* free up temporary memory */
797         lp_talloc_free();
798 }
799
800 /*
801   called when a SMB socket becomes writable
802 */
803 static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
804 {
805         struct smbsrv_connection *smb_conn = conn->private_data;
806
807         while (smb_conn->pending_send) {
808                 struct smbsrv_request *req = smb_conn->pending_send;
809                 DATA_BLOB blob;
810                 NTSTATUS status;
811                 size_t sendlen;
812
813                 blob.data = req->out.buffer;
814                 blob.length = req->out.size;
815
816                 /* send as much of this request as we can */
817                 status = socket_send(conn->socket, &blob, &sendlen, 0);
818                 if (NT_STATUS_IS_ERR(status)) {
819                         smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
820                         return;
821                 }
822                 if (sendlen == 0) {
823                         break;
824                 }
825
826                 req->out.buffer += sendlen;
827                 req->out.size -= sendlen;
828
829                 /* is the whole request gone? */
830                 if (req->out.size == 0) {
831                         DLIST_REMOVE(smb_conn->pending_send, req);
832                         req_destroy(req);
833                 }
834         }
835
836         /* if no more requests are pending to be sent then
837            we should stop select for write */
838         if (smb_conn->pending_send == NULL) {
839                 conn->event.fde->flags &= ~EVENT_FD_WRITE;
840         }
841 }
842
843 /*
844   called when connection is idle
845 */
846 static void smbsrv_idle(struct server_connection *conn, time_t t)
847 {
848         DEBUG(10,("smbsrv_idle: not implemented!\n"));
849         conn->event.idle->next_event = t + 5;
850
851         return;
852 }
853
854 static void smbsrv_close(struct server_connection *conn, const char *reason)
855 {
856         struct smbsrv_connection *smb_conn = conn->private_data;
857
858         DEBUG(5,("smbsrv_close: %s\n",reason));
859
860         conn_close_all(smb_conn);
861
862         talloc_free(smb_conn);
863
864         return;
865 }
866
867 /*
868   process a message from an SMB socket while still processing a
869   previous message this is used by backends who need to ensure that
870   new messages from clients are still processed while they are
871   performing long operations
872 */
873 void smbd_process_async(struct smbsrv_connection *smb_conn)
874 {
875         NTSTATUS status;
876         
877         status = receive_smb_request(smb_conn);
878         if (NT_STATUS_IS_ERR(status)) {
879                 smbsrv_terminate_connection(smb_conn, nt_errstr(status));
880         }
881 }
882
883
884 /*
885   initialise a server_context from a open socket and register a event handler
886   for reading from that socket
887 */
888 void smbsrv_accept(struct server_connection *conn)
889 {
890         struct smbsrv_connection *smb_conn;
891         int fd;
892
893         DEBUG(5,("smbsrv_accept\n"));
894
895         smb_conn = talloc_zero_p(conn, struct smbsrv_connection);
896         if (!smb_conn) return;
897
898         smb_conn->pid = getpid();
899
900         sub_set_context(&smb_conn->substitute);
901
902         /* now initialise a few default values associated with this smb socket */
903         smb_conn->negotiate.max_send = 0xFFFF;
904
905         /* this is the size that w2k uses, and it appears to be important for
906            good performance */
907         smb_conn->negotiate.max_recv = lp_max_xmit();
908
909         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
910
911         smb_conn->sessions.next_vuid = VUID_OFFSET;
912
913         srv_init_signing(smb_conn);
914
915         conn_init(smb_conn);
916
917         smb_conn->connection = conn;
918
919         conn->private_data = smb_conn;
920
921         fd = socket_get_fd(conn->socket);
922         set_blocking(fd, True);
923
924         /* setup the DCERPC server subsystem */
925         dcesrv_init_context(smb_conn, &smb_conn->dcesrv);
926
927         return;
928 }
929
930 static const struct server_service_ops smb_server_ops = {
931         .name                   = "smb",
932         .service_init           = smbsrv_init,
933         .accept_connection      = smbsrv_accept,
934         .recv_handler           = smbsrv_recv,
935         .send_handler           = smbsrv_send,
936         .idle_handler           = smbsrv_idle,
937         .close_connection       = smbsrv_close,
938         .service_exit           = smbsrv_exit,  
939 };
940
941 const struct server_service_ops *smbsrv_get_ops(void)
942 {
943         return &smb_server_ops;
944 }
945
946 NTSTATUS server_service_smb_init(void)
947 {
948         return NT_STATUS_OK;    
949 }