r11744: make sure the session is completed authenticated!!!
[amitay/samba.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 "lib/events/events.h"
25 #include "system/time.h"
26 #include "dlinklist.h"
27 #include "smbd/service_stream.h"
28 #include "smb_server/smb_server.h"
29 #include "lib/messaging/irpc.h"
30 #include "lib/stream/packet.h"
31
32
33 /*
34   send an oplock break request to a client
35 */
36 BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
37 {
38         struct smbsrv_request *req;
39
40         req = init_smb_request(tcon->smb_conn);
41
42         req_setup_reply(req, 8, 0);
43         
44         SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
45         SSVAL(req->out.hdr,HDR_TID,tcon->tid);
46         SSVAL(req->out.hdr,HDR_PID,0xFFFF);
47         SSVAL(req->out.hdr,HDR_UID,0);
48         SSVAL(req->out.hdr,HDR_MID,0xFFFF);
49         SCVAL(req->out.hdr,HDR_FLG,0);
50         SSVAL(req->out.hdr,HDR_FLG2,0);
51
52         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
53         SSVAL(req->out.vwv, VWV(1), 0);
54         SSVAL(req->out.vwv, VWV(2), fnum);
55         SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
56         SCVAL(req->out.vwv, VWV(3)+1, level);
57         SIVAL(req->out.vwv, VWV(4), 0);
58         SSVAL(req->out.vwv, VWV(6), 0);
59         SSVAL(req->out.vwv, VWV(7), 0);
60
61         req_send_reply(req);
62         return True;
63 }
64
65 static void switch_message(int type, struct smbsrv_request *req);
66
67 /****************************************************************************
68 receive a SMB request header from the wire, forming a request_context
69 from the result
70 ****************************************************************************/
71 static NTSTATUS receive_smb_request(void *private, DATA_BLOB blob)
72 {
73         struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
74         struct smbsrv_request *req;
75         uint8_t command;
76
77         /* see if its a special NBT packet */
78         if (CVAL(blob.data, 0) != 0) {
79                 req = init_smb_request(smb_conn);
80                 NT_STATUS_HAVE_NO_MEMORY(req);
81
82                 ZERO_STRUCT(req->in);
83
84                 req->in.buffer = talloc_steal(req, blob.data);
85                 req->in.size = blob.length;
86                 req->request_time = timeval_current();
87
88                 reply_special(req);
89                 return NT_STATUS_OK;
90         }
91
92         if ((NBT_HDR_SIZE + MIN_SMB_SIZE) > blob.length) {
93                 DEBUG(2,("Invalid SMB packet: length %d\n", blob.length));
94                 smbsrv_terminate_connection(smb_conn, "Invalid SMB packet");
95                 return NT_STATUS_OK;
96         }
97
98         /* Make sure this is an SMB packet */
99         if (IVAL(blob.data, NBT_HDR_SIZE) != SMB_MAGIC) {
100                 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
101                          blob.length));
102                 smbsrv_terminate_connection(smb_conn, "Non-SMB packet");
103                 return NT_STATUS_OK;
104         }
105
106         req = init_smb_request(smb_conn);
107         NT_STATUS_HAVE_NO_MEMORY(req);
108
109         req->in.buffer = talloc_steal(req, blob.data);
110         req->in.size = blob.length;
111         req->request_time = timeval_current();
112         req->chained_fnum = -1;
113         req->in.allocated = req->in.size;
114         req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
115         req->in.vwv = req->in.hdr + HDR_VWV;
116         req->in.wct = CVAL(req->in.hdr, HDR_WCT);
117         if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
118                 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
119                 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
120
121                 /* the bcc length is only 16 bits, but some packets
122                    (such as SMBwriteX) can be much larger than 64k. We
123                    detect this by looking for a large non-chained NBT
124                    packet (at least 64k bigger than what is
125                    specified). If it is detected then the NBT size is
126                    used instead of the bcc size */
127                 if (req->in.data_size + 0x10000 <= 
128                     req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
129                     (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
130                         /* its an oversized packet! fun for all the family */
131                         req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
132                 }
133         }
134
135         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
136                 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
137                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
138                 return NT_STATUS_OK;
139         }
140  
141         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
142                 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
143                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
144                 return NT_STATUS_OK;
145         }
146
147         req->flags      = CVAL(req->in.hdr, HDR_FLG);
148         req->flags2     = SVAL(req->in.hdr, HDR_FLG2);
149         req->smbpid     = SVAL(req->in.hdr, HDR_PID);
150
151         if (!req_signing_check_incoming(req)) {
152                 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
153                 return NT_STATUS_OK;
154         }
155
156         command = CVAL(req->in.hdr, HDR_COM);
157         switch_message(command, req);
158         return NT_STATUS_OK;
159 }
160
161 /*
162   These flags determine some of the permissions required to do an operation 
163 */
164 #define AS_USER (1<<0)
165 #define SIGNING_NO_REPLY (1<<1)
166
167 /* 
168    define a list of possible SMB messages and their corresponding
169    functions. Any message that has a NULL function is unimplemented -
170    please feel free to contribute implementations!
171 */
172 static const struct smb_message_struct
173 {
174         const char *name;
175         void (*fn)(struct smbsrv_request *);
176         int flags;
177 }
178  smb_messages[256] = {
179 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER},
180 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER},
181 /* 0x02 */ { "SMBopen",reply_open,AS_USER},
182 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
183 /* 0x04 */ { "SMBclose",reply_close,AS_USER},
184 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
185 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER},
186 /* 0x07 */ { "SMBmv",reply_mv,AS_USER},
187 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
188 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER},
189 /* 0x0a */ { "SMBread",reply_read,AS_USER},
190 /* 0x0b */ { "SMBwrite",reply_write,AS_USER},
191 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
192 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
193 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
194 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER}, 
195 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
196 /* 0x11 */ { "SMBexit",reply_exit,0},
197 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
198 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
199 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
200 /* 0x15 */ { NULL, NULL, 0 },
201 /* 0x16 */ { NULL, NULL, 0 },
202 /* 0x17 */ { NULL, NULL, 0 },
203 /* 0x18 */ { NULL, NULL, 0 },
204 /* 0x19 */ { NULL, NULL, 0 },
205 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
206 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
207 /* 0x1c */ { "SMBreadBs",NULL,0 },
208 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
209 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
210 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
211 /* 0x20 */ { "SMBwritec",NULL,0},
212 /* 0x21 */ { NULL, NULL, 0 },
213 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER},
214 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER},
215 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER},
216 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER},
217 /* 0x26 */ { "SMBtranss",reply_transs,AS_USER},
218 /* 0x27 */ { "SMBioctl",reply_ioctl,AS_USER},
219 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
220 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER},
221 /* 0x2a */ { "SMBmove",NULL,AS_USER},
222 /* 0x2b */ { "SMBecho",reply_echo,0},
223 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
224 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER},
225 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER},
226 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER},
227 /* 0x30 */ { NULL, NULL, 0 },
228 /* 0x31 */ { NULL, NULL, 0 },
229 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER},
230 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
231 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
232 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
233 /* 0x36 */ { NULL, NULL, 0 },
234 /* 0x37 */ { NULL, NULL, 0 },
235 /* 0x38 */ { NULL, NULL, 0 },
236 /* 0x39 */ { NULL, NULL, 0 },
237 /* 0x3a */ { NULL, NULL, 0 },
238 /* 0x3b */ { NULL, NULL, 0 },
239 /* 0x3c */ { NULL, NULL, 0 },
240 /* 0x3d */ { NULL, NULL, 0 },
241 /* 0x3e */ { NULL, NULL, 0 },
242 /* 0x3f */ { NULL, NULL, 0 },
243 /* 0x40 */ { NULL, NULL, 0 },
244 /* 0x41 */ { NULL, NULL, 0 },
245 /* 0x42 */ { NULL, NULL, 0 },
246 /* 0x43 */ { NULL, NULL, 0 },
247 /* 0x44 */ { NULL, NULL, 0 },
248 /* 0x45 */ { NULL, NULL, 0 },
249 /* 0x46 */ { NULL, NULL, 0 },
250 /* 0x47 */ { NULL, NULL, 0 },
251 /* 0x48 */ { NULL, NULL, 0 },
252 /* 0x49 */ { NULL, NULL, 0 },
253 /* 0x4a */ { NULL, NULL, 0 },
254 /* 0x4b */ { NULL, NULL, 0 },
255 /* 0x4c */ { NULL, NULL, 0 },
256 /* 0x4d */ { NULL, NULL, 0 },
257 /* 0x4e */ { NULL, NULL, 0 },
258 /* 0x4f */ { NULL, NULL, 0 },
259 /* 0x50 */ { NULL, NULL, 0 },
260 /* 0x51 */ { NULL, NULL, 0 },
261 /* 0x52 */ { NULL, NULL, 0 },
262 /* 0x53 */ { NULL, NULL, 0 },
263 /* 0x54 */ { NULL, NULL, 0 },
264 /* 0x55 */ { NULL, NULL, 0 },
265 /* 0x56 */ { NULL, NULL, 0 },
266 /* 0x57 */ { NULL, NULL, 0 },
267 /* 0x58 */ { NULL, NULL, 0 },
268 /* 0x59 */ { NULL, NULL, 0 },
269 /* 0x5a */ { NULL, NULL, 0 },
270 /* 0x5b */ { NULL, NULL, 0 },
271 /* 0x5c */ { NULL, NULL, 0 },
272 /* 0x5d */ { NULL, NULL, 0 },
273 /* 0x5e */ { NULL, NULL, 0 },
274 /* 0x5f */ { NULL, NULL, 0 },
275 /* 0x60 */ { NULL, NULL, 0 },
276 /* 0x61 */ { NULL, NULL, 0 },
277 /* 0x62 */ { NULL, NULL, 0 },
278 /* 0x63 */ { NULL, NULL, 0 },
279 /* 0x64 */ { NULL, NULL, 0 },
280 /* 0x65 */ { NULL, NULL, 0 },
281 /* 0x66 */ { NULL, NULL, 0 },
282 /* 0x67 */ { NULL, NULL, 0 },
283 /* 0x68 */ { NULL, NULL, 0 },
284 /* 0x69 */ { NULL, NULL, 0 },
285 /* 0x6a */ { NULL, NULL, 0 },
286 /* 0x6b */ { NULL, NULL, 0 },
287 /* 0x6c */ { NULL, NULL, 0 },
288 /* 0x6d */ { NULL, NULL, 0 },
289 /* 0x6e */ { NULL, NULL, 0 },
290 /* 0x6f */ { NULL, NULL, 0 },
291 /* 0x70 */ { "SMBtcon",reply_tcon,0},
292 /* 0x71 */ { "SMBtdis",reply_tdis,0},
293 /* 0x72 */ { "SMBnegprot",reply_negprot,0},
294 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,0},
295 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
296 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
297 /* 0x76 */ { NULL, NULL, 0 },
298 /* 0x77 */ { NULL, NULL, 0 },
299 /* 0x78 */ { NULL, NULL, 0 },
300 /* 0x79 */ { NULL, NULL, 0 },
301 /* 0x7a */ { NULL, NULL, 0 },
302 /* 0x7b */ { NULL, NULL, 0 },
303 /* 0x7c */ { NULL, NULL, 0 },
304 /* 0x7d */ { NULL, NULL, 0 },
305 /* 0x7e */ { NULL, NULL, 0 },
306 /* 0x7f */ { NULL, NULL, 0 },
307 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
308 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
309 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
310 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
311 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
312 /* 0x85 */ { NULL, NULL, 0 },
313 /* 0x86 */ { NULL, NULL, 0 },
314 /* 0x87 */ { NULL, NULL, 0 },
315 /* 0x88 */ { NULL, NULL, 0 },
316 /* 0x89 */ { NULL, NULL, 0 },
317 /* 0x8a */ { NULL, NULL, 0 },
318 /* 0x8b */ { NULL, NULL, 0 },
319 /* 0x8c */ { NULL, NULL, 0 },
320 /* 0x8d */ { NULL, NULL, 0 },
321 /* 0x8e */ { NULL, NULL, 0 },
322 /* 0x8f */ { NULL, NULL, 0 },
323 /* 0x90 */ { NULL, NULL, 0 },
324 /* 0x91 */ { NULL, NULL, 0 },
325 /* 0x92 */ { NULL, NULL, 0 },
326 /* 0x93 */ { NULL, NULL, 0 },
327 /* 0x94 */ { NULL, NULL, 0 },
328 /* 0x95 */ { NULL, NULL, 0 },
329 /* 0x96 */ { NULL, NULL, 0 },
330 /* 0x97 */ { NULL, NULL, 0 },
331 /* 0x98 */ { NULL, NULL, 0 },
332 /* 0x99 */ { NULL, NULL, 0 },
333 /* 0x9a */ { NULL, NULL, 0 },
334 /* 0x9b */ { NULL, NULL, 0 },
335 /* 0x9c */ { NULL, NULL, 0 },
336 /* 0x9d */ { NULL, NULL, 0 },
337 /* 0x9e */ { NULL, NULL, 0 },
338 /* 0x9f */ { NULL, NULL, 0 },
339 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER},
340 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER},
341 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER},
342 /* 0xa3 */ { NULL, NULL, 0 },
343 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, AS_USER|SIGNING_NO_REPLY},
344 /* 0xa5 */ { "SMBntrename", reply_ntrename, AS_USER},
345 /* 0xa6 */ { NULL, NULL, 0 },
346 /* 0xa7 */ { NULL, NULL, 0 },
347 /* 0xa8 */ { NULL, NULL, 0 },
348 /* 0xa9 */ { NULL, NULL, 0 },
349 /* 0xaa */ { NULL, NULL, 0 },
350 /* 0xab */ { NULL, NULL, 0 },
351 /* 0xac */ { NULL, NULL, 0 },
352 /* 0xad */ { NULL, NULL, 0 },
353 /* 0xae */ { NULL, NULL, 0 },
354 /* 0xaf */ { NULL, NULL, 0 },
355 /* 0xb0 */ { NULL, NULL, 0 },
356 /* 0xb1 */ { NULL, NULL, 0 },
357 /* 0xb2 */ { NULL, NULL, 0 },
358 /* 0xb3 */ { NULL, NULL, 0 },
359 /* 0xb4 */ { NULL, NULL, 0 },
360 /* 0xb5 */ { NULL, NULL, 0 },
361 /* 0xb6 */ { NULL, NULL, 0 },
362 /* 0xb7 */ { NULL, NULL, 0 },
363 /* 0xb8 */ { NULL, NULL, 0 },
364 /* 0xb9 */ { NULL, NULL, 0 },
365 /* 0xba */ { NULL, NULL, 0 },
366 /* 0xbb */ { NULL, NULL, 0 },
367 /* 0xbc */ { NULL, NULL, 0 },
368 /* 0xbd */ { NULL, NULL, 0 },
369 /* 0xbe */ { NULL, NULL, 0 },
370 /* 0xbf */ { NULL, NULL, 0 },
371 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
372 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
373 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
374 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
375 /* 0xc4 */ { NULL, NULL, 0 },
376 /* 0xc5 */ { NULL, NULL, 0 },
377 /* 0xc6 */ { NULL, NULL, 0 },
378 /* 0xc7 */ { NULL, NULL, 0 },
379 /* 0xc8 */ { NULL, NULL, 0 },
380 /* 0xc9 */ { NULL, NULL, 0 },
381 /* 0xca */ { NULL, NULL, 0 },
382 /* 0xcb */ { NULL, NULL, 0 },
383 /* 0xcc */ { NULL, NULL, 0 },
384 /* 0xcd */ { NULL, NULL, 0 },
385 /* 0xce */ { NULL, NULL, 0 },
386 /* 0xcf */ { NULL, NULL, 0 },
387 /* 0xd0 */ { "SMBsends",reply_sends,0},
388 /* 0xd1 */ { "SMBsendb",NULL,0},
389 /* 0xd2 */ { "SMBfwdname",NULL,0},
390 /* 0xd3 */ { "SMBcancelf",NULL,0},
391 /* 0xd4 */ { "SMBgetmac",NULL,0},
392 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,0},
393 /* 0xd6 */ { "SMBsendend",reply_sendend,0},
394 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,0},
395 /* 0xd8 */ { NULL, NULL, 0 },
396 /* 0xd9 */ { NULL, NULL, 0 },
397 /* 0xda */ { NULL, NULL, 0 },
398 /* 0xdb */ { NULL, NULL, 0 },
399 /* 0xdc */ { NULL, NULL, 0 },
400 /* 0xdd */ { NULL, NULL, 0 },
401 /* 0xde */ { NULL, NULL, 0 },
402 /* 0xdf */ { NULL, NULL, 0 },
403 /* 0xe0 */ { NULL, NULL, 0 },
404 /* 0xe1 */ { NULL, NULL, 0 },
405 /* 0xe2 */ { NULL, NULL, 0 },
406 /* 0xe3 */ { NULL, NULL, 0 },
407 /* 0xe4 */ { NULL, NULL, 0 },
408 /* 0xe5 */ { NULL, NULL, 0 },
409 /* 0xe6 */ { NULL, NULL, 0 },
410 /* 0xe7 */ { NULL, NULL, 0 },
411 /* 0xe8 */ { NULL, NULL, 0 },
412 /* 0xe9 */ { NULL, NULL, 0 },
413 /* 0xea */ { NULL, NULL, 0 },
414 /* 0xeb */ { NULL, NULL, 0 },
415 /* 0xec */ { NULL, NULL, 0 },
416 /* 0xed */ { NULL, NULL, 0 },
417 /* 0xee */ { NULL, NULL, 0 },
418 /* 0xef */ { NULL, NULL, 0 },
419 /* 0xf0 */ { NULL, NULL, 0 },
420 /* 0xf1 */ { NULL, NULL, 0 },
421 /* 0xf2 */ { NULL, NULL, 0 },
422 /* 0xf3 */ { NULL, NULL, 0 },
423 /* 0xf4 */ { NULL, NULL, 0 },
424 /* 0xf5 */ { NULL, NULL, 0 },
425 /* 0xf6 */ { NULL, NULL, 0 },
426 /* 0xf7 */ { NULL, NULL, 0 },
427 /* 0xf8 */ { NULL, NULL, 0 },
428 /* 0xf9 */ { NULL, NULL, 0 },
429 /* 0xfa */ { NULL, NULL, 0 },
430 /* 0xfb */ { NULL, NULL, 0 },
431 /* 0xfc */ { NULL, NULL, 0 },
432 /* 0xfd */ { NULL, NULL, 0 },
433 /* 0xfe */ { NULL, NULL, 0 },
434 /* 0xff */ { NULL, NULL, 0 }
435 };
436
437 /****************************************************************************
438 return a string containing the function name of a SMB command
439 ****************************************************************************/
440 static const char *smb_fn_name(uint8_t type)
441 {
442         const char *unknown_name = "SMBunknown";
443
444         if (smb_messages[type].name == NULL)
445                 return unknown_name;
446
447         return smb_messages[type].name;
448 }
449
450
451 /****************************************************************************
452  Do a switch on the message type and call the specific reply function for this 
453 message. Unlike earlier versions of Samba the reply functions are responsible
454 for sending the reply themselves, rather than returning a size to this function
455 The reply functions may also choose to delay the processing by pushing the message
456 onto the message queue
457 ****************************************************************************/
458 static void switch_message(int type, struct smbsrv_request *req)
459 {
460         int flags;
461         struct smbsrv_connection *smb_conn = req->smb_conn;
462         uint16_t session_tag;
463         NTSTATUS status;
464
465         type &= 0xff;
466
467         errno = 0;
468
469         if (smb_messages[type].fn == NULL) {
470                 DEBUG(0,("Unknown message type %d!\n",type));
471                 reply_unknown(req);
472                 return;
473         }
474
475         flags = smb_messages[type].flags;
476
477         req->tcon = smbsrv_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
478
479         if (req->session == NULL) {
480                 /* setup the user context for this request if it
481                    hasn't already been initialised (to cope with SMB
482                    chaining) */
483
484                 /* In share mode security we must ignore the vuid. */
485                 if (smb_conn->config.security == SEC_SHARE) {
486                         session_tag = UID_FIELD_INVALID;
487                 } else {
488                         session_tag = SVAL(req->in.hdr,HDR_UID);
489                 }
490
491                 req->session = smbsrv_session_find(req->smb_conn, session_tag);
492                 if (req->session) {
493                         req->session->vuid = session_tag;
494                 }
495         } else {
496                 session_tag = req->session->vuid;
497         }
498
499         DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id));
500
501         /* this must be called before we do any reply */
502         if (flags & SIGNING_NO_REPLY) {
503                 req_signing_no_reply(req);
504         }
505
506         /* see if the vuid is valid */
507         if ((flags & AS_USER) && (!req->session || !req->session->finished_sesssetup)) {
508                 /* amazingly, the error code depends on the command */
509                 switch (type) {
510                         case SMBntcreateX:
511                         case SMBntcancel:
512                                 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
513                                 break;
514                         default:
515                                 status = NT_STATUS_INVALID_HANDLE;
516                                 break;
517                 }
518                 /* 
519                  * TODO:
520                  * don't know how to handle smb signing for this case 
521                  * so just skip the reply
522                  */
523                 if ((flags & SIGNING_NO_REPLY) &&
524                     (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
525                         DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
526                                 smb_fn_name(type), nt_errstr(status)));
527                         req_destroy(req);
528                         return;
529                 }
530                 req_reply_error(req, status);
531                 return;
532         }
533
534         /* does this protocol need a valid tree connection? */
535         if ((flags & AS_USER) && !req->tcon) {
536                 /* amazingly, the error code depends on the command */
537                 switch (type) {
538                         case SMBntcreateX:
539                         case SMBntcancel:
540                                 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
541                                 break;
542                         default:
543                                 status = NT_STATUS_INVALID_HANDLE;
544                                 break;
545                 }
546                 /* 
547                  * TODO:
548                  * don't know how to handle smb signing for this case 
549                  * so just skip the reply
550                  */
551                 if ((flags & SIGNING_NO_REPLY) &&
552                     (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
553                         DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
554                                 smb_fn_name(type), nt_errstr(status)));
555                         req_destroy(req);
556                         return;
557                 }
558                 req_reply_error(req, status);
559                 return;
560         }
561
562         smb_messages[type].fn(req);
563 }
564
565 /*
566   we call this when first first part of a possibly chained request has been completed
567   and we need to call the 2nd part, if any
568 */
569 void chain_reply(struct smbsrv_request *req)
570 {
571         uint16_t chain_cmd, chain_offset;
572         uint8_t *vwv, *data;
573         uint16_t wct;
574         uint16_t data_size;
575
576         if (req->in.wct < 2 || req->out.wct < 2) {
577                 req_reply_dos_error(req, ERRSRV, ERRerror);
578                 return;
579         }
580
581         chain_cmd    = CVAL(req->in.vwv, VWV(0));
582         chain_offset = SVAL(req->in.vwv, VWV(1));
583
584         if (chain_cmd == SMB_CHAIN_NONE) {
585                 /* end of chain */
586                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
587                 SSVAL(req->out.vwv, VWV(1), 0);
588                 req_send_reply(req);
589                 return;
590         }
591
592         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
593                 goto error;
594         }
595
596         wct = CVAL(req->in.hdr, chain_offset);
597         vwv = req->in.hdr + chain_offset + 1;
598
599         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
600                 goto error;
601         }
602
603         data_size = SVAL(vwv, VWV(wct));
604         data = vwv + VWV(wct) + 2;
605
606         if (data + data_size > req->in.buffer + req->in.size) {
607                 goto error;
608         }
609
610         /* all seems legit */
611         req->in.vwv = vwv;
612         req->in.wct = wct;
613         req->in.data = data;
614         req->in.data_size = data_size;
615         req->in.ptr = data;
616
617         req->chain_count++;
618
619         SSVAL(req->out.vwv, VWV(0), chain_cmd);
620         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
621
622         /* the current request in the chain might have used an async reply,
623            but that doesn't mean the next element needs to */
624         ZERO_STRUCTP(req->async_states);
625
626         switch_message(chain_cmd, req);
627         return;
628
629 error:
630         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
631         SSVAL(req->out.vwv, VWV(1), 0);
632         req_reply_dos_error(req, ERRSRV, ERRerror);
633 }
634
635
636 /*
637   close the socket and shutdown a server_context
638 */
639 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
640 {
641         smb_conn->terminate = reason;
642 }
643
644 /*
645   called when a SMB socket becomes readable
646 */
647 static void smbsrv_recv(struct stream_connection *conn, uint16_t flags)
648 {
649         struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection);
650
651         DEBUG(10,("smbsrv_recv\n"));
652
653         packet_recv(smb_conn->packet);
654         if (smb_conn->terminate) {
655                 talloc_free(conn->event.fde);
656                 conn->event.fde = NULL;
657                 stream_terminate_connection(smb_conn->connection, smb_conn->terminate);
658                 return;
659         }
660
661         /* free up temporary memory */
662         lp_talloc_free();
663 }
664
665 /*
666   called when a SMB socket becomes writable
667 */
668 static void smbsrv_send(struct stream_connection *conn, uint16_t flags)
669 {
670         struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, 
671                                                              struct smbsrv_connection);
672         packet_queue_run(smb_conn->packet);
673 }
674
675
676 /*
677   handle socket recv errors
678 */
679 static void smbsrv_recv_error(void *private, NTSTATUS status)
680 {
681         struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
682         
683         smbsrv_terminate_connection(smb_conn, nt_errstr(status));
684 }
685
686 /*
687   initialise a server_context from a open socket and register a event handler
688   for reading from that socket
689 */
690 static void smbsrv_accept(struct stream_connection *conn)
691 {
692         struct smbsrv_connection *smb_conn;
693
694         DEBUG(5,("smbsrv_accept\n"));
695
696         smb_conn = talloc_zero(conn, struct smbsrv_connection);
697         if (!smb_conn) return;
698
699         /* now initialise a few default values associated with this smb socket */
700         smb_conn->negotiate.max_send = 0xFFFF;
701
702         /* this is the size that w2k uses, and it appears to be important for
703            good performance */
704         smb_conn->negotiate.max_recv = lp_max_xmit();
705
706         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
707
708         smb_conn->negotiate.called_name = NULL;
709         smb_conn->negotiate.calling_name = NULL;
710
711         smb_conn->packet = packet_init(smb_conn);
712         if (smb_conn->packet == NULL) {
713                 stream_terminate_connection(conn, "out of memory");
714                 return;
715         }
716         packet_set_private(smb_conn->packet, smb_conn);
717         packet_set_socket(smb_conn->packet, conn->socket);
718         packet_set_callback(smb_conn->packet, receive_smb_request);
719         packet_set_full_request(smb_conn->packet, packet_full_request_nbt);
720         packet_set_error_handler(smb_conn->packet, smbsrv_recv_error);
721         packet_set_event_context(smb_conn->packet, conn->event.ctx);
722         packet_set_fde(smb_conn->packet, conn->event.fde);
723         packet_set_serialise(smb_conn->packet);
724
725         smbsrv_vuid_init(smb_conn);
726
727         srv_init_signing(smb_conn);
728
729         smbsrv_tcon_init(smb_conn);
730
731         smb_conn->connection = conn;
732         smb_conn->config.security = lp_security();
733         smb_conn->config.nt_status_support = lp_nt_status_support();
734
735         conn->private = smb_conn;
736
737         irpc_add_name(conn->msg_ctx, "smb_server");
738
739         smbsrv_management_init(smb_conn);
740 }
741
742
743 static const struct stream_server_ops smb_stream_ops = {
744         .name                   = "smb",
745         .accept_connection      = smbsrv_accept,
746         .recv_handler           = smbsrv_recv,
747         .send_handler           = smbsrv_send,
748 };
749
750 /*
751   setup a listening socket on all the SMB ports for a particular address
752 */
753 static NTSTATUS smb_add_socket(struct event_context *event_context,
754                                const struct model_ops *model_ops,
755                                const char *address)
756 {
757         const char **ports = lp_smb_ports();
758         int i;
759         NTSTATUS status;
760
761         for (i=0;ports[i];i++) {
762                 uint16_t port = atoi(ports[i]);
763                 if (port == 0) continue;
764                 status = stream_setup_socket(event_context, model_ops, &smb_stream_ops, 
765                                              "ipv4", address, &port, NULL);
766                 NT_STATUS_NOT_OK_RETURN(status);
767         }
768
769         return NT_STATUS_OK;
770 }
771
772 /*
773   called on startup of the smb server service It's job is to start
774   listening on all configured SMB server sockets
775 */
776 static NTSTATUS smbsrv_init(struct event_context *event_context, const struct model_ops *model_ops)
777 {       
778         NTSTATUS status;
779
780         if (lp_interfaces() && lp_bind_interfaces_only()) {
781                 int num_interfaces = iface_count();
782                 int i;
783
784                 /* We have been given an interfaces line, and been 
785                    told to only bind to those interfaces. Create a
786                    socket per interface and bind to only these.
787                 */
788                 for(i = 0; i < num_interfaces; i++) {
789                         const char *address = iface_n_ip(i);
790                         status = smb_add_socket(event_context, model_ops, address);
791                         NT_STATUS_NOT_OK_RETURN(status);
792                 }
793         } else {
794                 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
795                 status = smb_add_socket(event_context, model_ops, lp_socket_address());
796                 NT_STATUS_NOT_OK_RETURN(status);
797         }
798
799         return NT_STATUS_OK;
800 }
801
802 /* called at smbd startup - register ourselves as a server service */
803 NTSTATUS server_service_smb_init(void)
804 {
805         return register_server_service("smb", smbsrv_init);
806 }