r14647: be a bit less verbose on common stuff
[samba.git] / source4 / smb_server / smb / receive.c
1 /* 
2    Unix SMB/CIFS implementation.
3    process incoming packets - main loop
4    Copyright (C) Andrew Tridgell 1992-2005
5    Copyright (C) James J Myers 2003 <myersjj@samba.org>
6    Copyright (C) Stefan Metzmacher 2004-2005
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 "smbd/service_stream.h"
26 #include "smb_server/smb_server.h"
27 #include "ntvfs/ntvfs.h"
28
29
30 /*
31   send an oplock break request to a client
32 */
33 NTSTATUS smbsrv_send_oplock_break(void *p, uint16_t fnum, uint8_t level)
34 {
35         struct smbsrv_tcon *tcon = talloc_get_type(p, struct smbsrv_tcon);
36         struct smbsrv_request *req;
37
38         req = smbsrv_init_request(tcon->smb_conn);
39         NT_STATUS_HAVE_NO_MEMORY(req);
40
41         smbsrv_setup_reply(req, 8, 0);
42
43         SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
44         SSVAL(req->out.hdr,HDR_TID,tcon->tid);
45         SSVAL(req->out.hdr,HDR_PID,0xFFFF);
46         SSVAL(req->out.hdr,HDR_UID,0);
47         SSVAL(req->out.hdr,HDR_MID,0xFFFF);
48         SCVAL(req->out.hdr,HDR_FLG,0);
49         SSVAL(req->out.hdr,HDR_FLG2,0);
50
51         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
52         SSVAL(req->out.vwv, VWV(1), 0);
53         SSVAL(req->out.vwv, VWV(2), fnum);
54         SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
55         SCVAL(req->out.vwv, VWV(3)+1, level);
56         SIVAL(req->out.vwv, VWV(4), 0);
57         SSVAL(req->out.vwv, VWV(6), 0);
58         SSVAL(req->out.vwv, VWV(7), 0);
59
60         smbsrv_send_reply(req);
61         return NT_STATUS_OK;
62 }
63
64 static void switch_message(int type, struct smbsrv_request *req);
65
66 /****************************************************************************
67 receive a SMB request header from the wire, forming a request_context
68 from the result
69 ****************************************************************************/
70 NTSTATUS smbsrv_recv_smb_request(void *private, DATA_BLOB blob)
71 {
72         struct smbsrv_connection *smb_conn = talloc_get_type(private, struct smbsrv_connection);
73         struct smbsrv_request *req;
74         uint8_t command;
75
76         /* see if its a special NBT packet */
77         if (CVAL(blob.data, 0) != 0) {
78                 req = smbsrv_init_request(smb_conn);
79                 NT_STATUS_HAVE_NO_MEMORY(req);
80
81                 ZERO_STRUCT(req->in);
82
83                 req->in.buffer = talloc_steal(req, blob.data);
84                 req->in.size = blob.length;
85                 req->request_time = timeval_current();
86
87                 smbsrv_reply_special(req);
88                 return NT_STATUS_OK;
89         }
90
91         if ((NBT_HDR_SIZE + MIN_SMB_SIZE) > blob.length) {
92                 DEBUG(2,("Invalid SMB packet: length %ld\n", (long)blob.length));
93                 smbsrv_terminate_connection(smb_conn, "Invalid SMB packet");
94                 return NT_STATUS_OK;
95         }
96
97         /* Make sure this is an SMB packet */
98         if (IVAL(blob.data, NBT_HDR_SIZE) != SMB_MAGIC) {
99                 DEBUG(2,("Non-SMB packet of length %ld. Terminating connection\n",
100                          (long)blob.length));
101                 smbsrv_terminate_connection(smb_conn, "Non-SMB packet");
102                 return NT_STATUS_OK;
103         }
104
105         req = smbsrv_init_request(smb_conn);
106         NT_STATUS_HAVE_NO_MEMORY(req);
107
108         req->in.buffer = talloc_steal(req, blob.data);
109         req->in.size = blob.length;
110         req->request_time = timeval_current();
111         req->chained_fnum = -1;
112         req->in.allocated = req->in.size;
113         req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
114         req->in.vwv = req->in.hdr + HDR_VWV;
115         req->in.wct = CVAL(req->in.hdr, HDR_WCT);
116         if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
117                 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
118                 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
119
120                 /* the bcc length is only 16 bits, but some packets
121                    (such as SMBwriteX) can be much larger than 64k. We
122                    detect this by looking for a large non-chained NBT
123                    packet (at least 64k bigger than what is
124                    specified). If it is detected then the NBT size is
125                    used instead of the bcc size */
126                 if (req->in.data_size + 0x10000 <= 
127                     req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
128                     (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
129                         /* its an oversized packet! fun for all the family */
130                         req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
131                 }
132         }
133
134         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
135                 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
136                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
137                 return NT_STATUS_OK;
138         }
139  
140         if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
141                 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
142                 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
143                 return NT_STATUS_OK;
144         }
145
146         req->flags2     = SVAL(req->in.hdr, HDR_FLG2);
147
148         if (!smbsrv_signing_check_incoming(req)) {
149                 smbsrv_send_error(req, NT_STATUS_ACCESS_DENIED);
150                 return NT_STATUS_OK;
151         }
152
153         command = CVAL(req->in.hdr, HDR_COM);
154         switch_message(command, req);
155         return NT_STATUS_OK;
156 }
157
158 /*
159   These flags determine some of the permissions required to do an operation 
160 */
161 #define NEED_SESS               (1<<0)
162 #define NEED_TCON               (1<<1)
163 #define SIGNING_NO_REPLY        (1<<2)
164
165 /* 
166    define a list of possible SMB messages and their corresponding
167    functions. Any message that has a NULL function is unimplemented -
168    please feel free to contribute implementations!
169 */
170 static const struct smb_message_struct
171 {
172         const char *name;
173         void (*fn)(struct smbsrv_request *);
174         int flags;
175 }
176  smb_messages[256] = {
177 /* 0x00 */ { "SMBmkdir",        smbsrv_reply_mkdir,             NEED_SESS|NEED_TCON },
178 /* 0x01 */ { "SMBrmdir",        smbsrv_reply_rmdir,             NEED_SESS|NEED_TCON },
179 /* 0x02 */ { "SMBopen",         smbsrv_reply_open,              NEED_SESS|NEED_TCON },
180 /* 0x03 */ { "SMBcreate",       smbsrv_reply_mknew,             NEED_SESS|NEED_TCON },
181 /* 0x04 */ { "SMBclose",        smbsrv_reply_close,             NEED_SESS|NEED_TCON },
182 /* 0x05 */ { "SMBflush",        smbsrv_reply_flush,             NEED_SESS|NEED_TCON },
183 /* 0x06 */ { "SMBunlink",       smbsrv_reply_unlink,            NEED_SESS|NEED_TCON },
184 /* 0x07 */ { "SMBmv",           smbsrv_reply_mv,                NEED_SESS|NEED_TCON },
185 /* 0x08 */ { "SMBgetatr",       smbsrv_reply_getatr,            NEED_SESS|NEED_TCON },
186 /* 0x09 */ { "SMBsetatr",       smbsrv_reply_setatr,            NEED_SESS|NEED_TCON },
187 /* 0x0a */ { "SMBread",         smbsrv_reply_read,              NEED_SESS|NEED_TCON },
188 /* 0x0b */ { "SMBwrite",        smbsrv_reply_write,             NEED_SESS|NEED_TCON },
189 /* 0x0c */ { "SMBlock",         smbsrv_reply_lock,              NEED_SESS|NEED_TCON },
190 /* 0x0d */ { "SMBunlock",       smbsrv_reply_unlock,            NEED_SESS|NEED_TCON },
191 /* 0x0e */ { "SMBctemp",        smbsrv_reply_ctemp,             NEED_SESS|NEED_TCON },
192 /* 0x0f */ { "SMBmknew",        smbsrv_reply_mknew,             NEED_SESS|NEED_TCON }, 
193 /* 0x10 */ { "SMBchkpth",       smbsrv_reply_chkpth,            NEED_SESS|NEED_TCON },
194 /* 0x11 */ { "SMBexit",         smbsrv_reply_exit,              NEED_SESS },
195 /* 0x12 */ { "SMBlseek",        smbsrv_reply_lseek,             NEED_SESS|NEED_TCON },
196 /* 0x13 */ { "SMBlockread",     smbsrv_reply_lockread,          NEED_SESS|NEED_TCON },
197 /* 0x14 */ { "SMBwriteunlock",  smbsrv_reply_writeunlock,       NEED_SESS|NEED_TCON },
198 /* 0x15 */ { NULL, NULL, 0 },
199 /* 0x16 */ { NULL, NULL, 0 },
200 /* 0x17 */ { NULL, NULL, 0 },
201 /* 0x18 */ { NULL, NULL, 0 },
202 /* 0x19 */ { NULL, NULL, 0 },
203 /* 0x1a */ { "SMBreadbraw",     smbsrv_reply_readbraw,          NEED_SESS|NEED_TCON },
204 /* 0x1b */ { "SMBreadBmpx",     smbsrv_reply_readbmpx,          NEED_SESS|NEED_TCON },
205 /* 0x1c */ { "SMBreadBs",       NULL,                           0 },
206 /* 0x1d */ { "SMBwritebraw",    smbsrv_reply_writebraw,         NEED_SESS|NEED_TCON },
207 /* 0x1e */ { "SMBwriteBmpx",    smbsrv_reply_writebmpx,         NEED_SESS|NEED_TCON },
208 /* 0x1f */ { "SMBwriteBs",      smbsrv_reply_writebs,           NEED_SESS|NEED_TCON },
209 /* 0x20 */ { "SMBwritec",       NULL,                           0 },
210 /* 0x21 */ { NULL, NULL, 0 },
211 /* 0x22 */ { "SMBsetattrE",     smbsrv_reply_setattrE,          NEED_SESS|NEED_TCON },
212 /* 0x23 */ { "SMBgetattrE",     smbsrv_reply_getattrE,          NEED_SESS|NEED_TCON },
213 /* 0x24 */ { "SMBlockingX",     smbsrv_reply_lockingX,          NEED_SESS|NEED_TCON },
214 /* 0x25 */ { "SMBtrans",        smbsrv_reply_trans,             NEED_SESS|NEED_TCON },
215 /* 0x26 */ { "SMBtranss",       smbsrv_reply_transs,            NEED_SESS|NEED_TCON },
216 /* 0x27 */ { "SMBioctl",        smbsrv_reply_ioctl,             NEED_SESS|NEED_TCON },
217 /* 0x28 */ { "SMBioctls",       NULL,                           NEED_SESS|NEED_TCON },
218 /* 0x29 */ { "SMBcopy",         smbsrv_reply_copy,              NEED_SESS|NEED_TCON },
219 /* 0x2a */ { "SMBmove",         NULL,                           NEED_SESS|NEED_TCON },
220 /* 0x2b */ { "SMBecho",         smbsrv_reply_echo,              0 },
221 /* 0x2c */ { "SMBwriteclose",   smbsrv_reply_writeclose,        NEED_SESS|NEED_TCON },
222 /* 0x2d */ { "SMBopenX",        smbsrv_reply_open_and_X,        NEED_SESS|NEED_TCON },
223 /* 0x2e */ { "SMBreadX",        smbsrv_reply_read_and_X,        NEED_SESS|NEED_TCON },
224 /* 0x2f */ { "SMBwriteX",       smbsrv_reply_write_and_X,       NEED_SESS|NEED_TCON},
225 /* 0x30 */ { NULL, NULL, 0 },
226 /* 0x31 */ { NULL, NULL, 0 },
227 /* 0x32 */ { "SMBtrans2",       smbsrv_reply_trans2,            NEED_SESS|NEED_TCON },
228 /* 0x33 */ { "SMBtranss2",      smbsrv_reply_transs2,           NEED_SESS|NEED_TCON },
229 /* 0x34 */ { "SMBfindclose",    smbsrv_reply_findclose,         NEED_SESS|NEED_TCON },
230 /* 0x35 */ { "SMBfindnclose",   smbsrv_reply_findnclose,        NEED_SESS|NEED_TCON },
231 /* 0x36 */ { NULL, NULL, 0 },
232 /* 0x37 */ { NULL, NULL, 0 },
233 /* 0x38 */ { NULL, NULL, 0 },
234 /* 0x39 */ { NULL, NULL, 0 },
235 /* 0x3a */ { NULL, NULL, 0 },
236 /* 0x3b */ { NULL, NULL, 0 },
237 /* 0x3c */ { NULL, NULL, 0 },
238 /* 0x3d */ { NULL, NULL, 0 },
239 /* 0x3e */ { NULL, NULL, 0 },
240 /* 0x3f */ { NULL, NULL, 0 },
241 /* 0x40 */ { NULL, NULL, 0 },
242 /* 0x41 */ { NULL, NULL, 0 },
243 /* 0x42 */ { NULL, NULL, 0 },
244 /* 0x43 */ { NULL, NULL, 0 },
245 /* 0x44 */ { NULL, NULL, 0 },
246 /* 0x45 */ { NULL, NULL, 0 },
247 /* 0x46 */ { NULL, NULL, 0 },
248 /* 0x47 */ { NULL, NULL, 0 },
249 /* 0x48 */ { NULL, NULL, 0 },
250 /* 0x49 */ { NULL, NULL, 0 },
251 /* 0x4a */ { NULL, NULL, 0 },
252 /* 0x4b */ { NULL, NULL, 0 },
253 /* 0x4c */ { NULL, NULL, 0 },
254 /* 0x4d */ { NULL, NULL, 0 },
255 /* 0x4e */ { NULL, NULL, 0 },
256 /* 0x4f */ { NULL, NULL, 0 },
257 /* 0x50 */ { NULL, NULL, 0 },
258 /* 0x51 */ { NULL, NULL, 0 },
259 /* 0x52 */ { NULL, NULL, 0 },
260 /* 0x53 */ { NULL, NULL, 0 },
261 /* 0x54 */ { NULL, NULL, 0 },
262 /* 0x55 */ { NULL, NULL, 0 },
263 /* 0x56 */ { NULL, NULL, 0 },
264 /* 0x57 */ { NULL, NULL, 0 },
265 /* 0x58 */ { NULL, NULL, 0 },
266 /* 0x59 */ { NULL, NULL, 0 },
267 /* 0x5a */ { NULL, NULL, 0 },
268 /* 0x5b */ { NULL, NULL, 0 },
269 /* 0x5c */ { NULL, NULL, 0 },
270 /* 0x5d */ { NULL, NULL, 0 },
271 /* 0x5e */ { NULL, NULL, 0 },
272 /* 0x5f */ { NULL, NULL, 0 },
273 /* 0x60 */ { NULL, NULL, 0 },
274 /* 0x61 */ { NULL, NULL, 0 },
275 /* 0x62 */ { NULL, NULL, 0 },
276 /* 0x63 */ { NULL, NULL, 0 },
277 /* 0x64 */ { NULL, NULL, 0 },
278 /* 0x65 */ { NULL, NULL, 0 },
279 /* 0x66 */ { NULL, NULL, 0 },
280 /* 0x67 */ { NULL, NULL, 0 },
281 /* 0x68 */ { NULL, NULL, 0 },
282 /* 0x69 */ { NULL, NULL, 0 },
283 /* 0x6a */ { NULL, NULL, 0 },
284 /* 0x6b */ { NULL, NULL, 0 },
285 /* 0x6c */ { NULL, NULL, 0 },
286 /* 0x6d */ { NULL, NULL, 0 },
287 /* 0x6e */ { NULL, NULL, 0 },
288 /* 0x6f */ { NULL, NULL, 0 },
289 /* 0x70 */ { "SMBtcon",         smbsrv_reply_tcon,              NEED_SESS },
290 /* 0x71 */ { "SMBtdis",         smbsrv_reply_tdis,              NEED_SESS },
291 /* 0x72 */ { "SMBnegprot",      smbsrv_reply_negprot,           0 },
292 /* 0x73 */ { "SMBsesssetupX",   smbsrv_reply_sesssetup,         0 },
293 /* 0x74 */ { "SMBulogoffX",     smbsrv_reply_ulogoffX,          NEED_SESS }, /* ulogoff doesn't give a valid TID */
294 /* 0x75 */ { "SMBtconX",        smbsrv_reply_tcon_and_X,        NEED_SESS },
295 /* 0x76 */ { NULL, NULL, 0 },
296 /* 0x77 */ { NULL, NULL, 0 },
297 /* 0x78 */ { NULL, NULL, 0 },
298 /* 0x79 */ { NULL, NULL, 0 },
299 /* 0x7a */ { NULL, NULL, 0 },
300 /* 0x7b */ { NULL, NULL, 0 },
301 /* 0x7c */ { NULL, NULL, 0 },
302 /* 0x7d */ { NULL, NULL, 0 },
303 /* 0x7e */ { NULL, NULL, 0 },
304 /* 0x7f */ { NULL, NULL, 0 },
305 /* 0x80 */ { "SMBdskattr",      smbsrv_reply_dskattr,           NEED_SESS|NEED_TCON },
306 /* 0x81 */ { "SMBsearch",       smbsrv_reply_search,            NEED_SESS|NEED_TCON },
307 /* 0x82 */ { "SMBffirst",       smbsrv_reply_search,            NEED_SESS|NEED_TCON },
308 /* 0x83 */ { "SMBfunique",      smbsrv_reply_search,            NEED_SESS|NEED_TCON },
309 /* 0x84 */ { "SMBfclose",       smbsrv_reply_fclose,            NEED_SESS|NEED_TCON },
310 /* 0x85 */ { NULL, NULL, 0 },
311 /* 0x86 */ { NULL, NULL, 0 },
312 /* 0x87 */ { NULL, NULL, 0 },
313 /* 0x88 */ { NULL, NULL, 0 },
314 /* 0x89 */ { NULL, NULL, 0 },
315 /* 0x8a */ { NULL, NULL, 0 },
316 /* 0x8b */ { NULL, NULL, 0 },
317 /* 0x8c */ { NULL, NULL, 0 },
318 /* 0x8d */ { NULL, NULL, 0 },
319 /* 0x8e */ { NULL, NULL, 0 },
320 /* 0x8f */ { NULL, NULL, 0 },
321 /* 0x90 */ { NULL, NULL, 0 },
322 /* 0x91 */ { NULL, NULL, 0 },
323 /* 0x92 */ { NULL, NULL, 0 },
324 /* 0x93 */ { NULL, NULL, 0 },
325 /* 0x94 */ { NULL, NULL, 0 },
326 /* 0x95 */ { NULL, NULL, 0 },
327 /* 0x96 */ { NULL, NULL, 0 },
328 /* 0x97 */ { NULL, NULL, 0 },
329 /* 0x98 */ { NULL, NULL, 0 },
330 /* 0x99 */ { NULL, NULL, 0 },
331 /* 0x9a */ { NULL, NULL, 0 },
332 /* 0x9b */ { NULL, NULL, 0 },
333 /* 0x9c */ { NULL, NULL, 0 },
334 /* 0x9d */ { NULL, NULL, 0 },
335 /* 0x9e */ { NULL, NULL, 0 },
336 /* 0x9f */ { NULL, NULL, 0 },
337 /* 0xa0 */ { "SMBnttrans",      smbsrv_reply_nttrans,           NEED_SESS|NEED_TCON },
338 /* 0xa1 */ { "SMBnttranss",     smbsrv_reply_nttranss,          NEED_SESS|NEED_TCON },
339 /* 0xa2 */ { "SMBntcreateX",    smbsrv_reply_ntcreate_and_X,    NEED_SESS|NEED_TCON },
340 /* 0xa3 */ { NULL, NULL, 0 },
341 /* 0xa4 */ { "SMBntcancel",     smbsrv_reply_ntcancel,          NEED_SESS|NEED_TCON|SIGNING_NO_REPLY },
342 /* 0xa5 */ { "SMBntrename",     smbsrv_reply_ntrename,          NEED_SESS|NEED_TCON },
343 /* 0xa6 */ { NULL, NULL, 0 },
344 /* 0xa7 */ { NULL, NULL, 0 },
345 /* 0xa8 */ { NULL, NULL, 0 },
346 /* 0xa9 */ { NULL, NULL, 0 },
347 /* 0xaa */ { NULL, NULL, 0 },
348 /* 0xab */ { NULL, NULL, 0 },
349 /* 0xac */ { NULL, NULL, 0 },
350 /* 0xad */ { NULL, NULL, 0 },
351 /* 0xae */ { NULL, NULL, 0 },
352 /* 0xaf */ { NULL, NULL, 0 },
353 /* 0xb0 */ { NULL, NULL, 0 },
354 /* 0xb1 */ { NULL, NULL, 0 },
355 /* 0xb2 */ { NULL, NULL, 0 },
356 /* 0xb3 */ { NULL, NULL, 0 },
357 /* 0xb4 */ { NULL, NULL, 0 },
358 /* 0xb5 */ { NULL, NULL, 0 },
359 /* 0xb6 */ { NULL, NULL, 0 },
360 /* 0xb7 */ { NULL, NULL, 0 },
361 /* 0xb8 */ { NULL, NULL, 0 },
362 /* 0xb9 */ { NULL, NULL, 0 },
363 /* 0xba */ { NULL, NULL, 0 },
364 /* 0xbb */ { NULL, NULL, 0 },
365 /* 0xbc */ { NULL, NULL, 0 },
366 /* 0xbd */ { NULL, NULL, 0 },
367 /* 0xbe */ { NULL, NULL, 0 },
368 /* 0xbf */ { NULL, NULL, 0 },
369 /* 0xc0 */ { "SMBsplopen",      smbsrv_reply_printopen,         NEED_SESS|NEED_TCON },
370 /* 0xc1 */ { "SMBsplwr",        smbsrv_reply_printwrite,        NEED_SESS|NEED_TCON },
371 /* 0xc2 */ { "SMBsplclose",     smbsrv_reply_printclose,        NEED_SESS|NEED_TCON },
372 /* 0xc3 */ { "SMBsplretq",      smbsrv_reply_printqueue,        NEED_SESS|NEED_TCON },
373 /* 0xc4 */ { NULL, NULL, 0 },
374 /* 0xc5 */ { NULL, NULL, 0 },
375 /* 0xc6 */ { NULL, NULL, 0 },
376 /* 0xc7 */ { NULL, NULL, 0 },
377 /* 0xc8 */ { NULL, NULL, 0 },
378 /* 0xc9 */ { NULL, NULL, 0 },
379 /* 0xca */ { NULL, NULL, 0 },
380 /* 0xcb */ { NULL, NULL, 0 },
381 /* 0xcc */ { NULL, NULL, 0 },
382 /* 0xcd */ { NULL, NULL, 0 },
383 /* 0xce */ { NULL, NULL, 0 },
384 /* 0xcf */ { NULL, NULL, 0 },
385 /* 0xd0 */ { "SMBsends",        NULL,                           0 },
386 /* 0xd1 */ { "SMBsendb",        NULL,                           0 },
387 /* 0xd2 */ { "SMBfwdname",      NULL,                           0 },
388 /* 0xd3 */ { "SMBcancelf",      NULL,                           0 },
389 /* 0xd4 */ { "SMBgetmac",       NULL,                           0 },
390 /* 0xd5 */ { "SMBsendstrt",     NULL,                           0 },
391 /* 0xd6 */ { "SMBsendend",      NULL,                           0 },
392 /* 0xd7 */ { "SMBsendtxt",      NULL,                           0 },
393 /* 0xd8 */ { NULL, NULL, 0 },
394 /* 0xd9 */ { NULL, NULL, 0 },
395 /* 0xda */ { NULL, NULL, 0 },
396 /* 0xdb */ { NULL, NULL, 0 },
397 /* 0xdc */ { NULL, NULL, 0 },
398 /* 0xdd */ { NULL, NULL, 0 },
399 /* 0xde */ { NULL, NULL, 0 },
400 /* 0xdf */ { NULL, NULL, 0 },
401 /* 0xe0 */ { NULL, NULL, 0 },
402 /* 0xe1 */ { NULL, NULL, 0 },
403 /* 0xe2 */ { NULL, NULL, 0 },
404 /* 0xe3 */ { NULL, NULL, 0 },
405 /* 0xe4 */ { NULL, NULL, 0 },
406 /* 0xe5 */ { NULL, NULL, 0 },
407 /* 0xe6 */ { NULL, NULL, 0 },
408 /* 0xe7 */ { NULL, NULL, 0 },
409 /* 0xe8 */ { NULL, NULL, 0 },
410 /* 0xe9 */ { NULL, NULL, 0 },
411 /* 0xea */ { NULL, NULL, 0 },
412 /* 0xeb */ { NULL, NULL, 0 },
413 /* 0xec */ { NULL, NULL, 0 },
414 /* 0xed */ { NULL, NULL, 0 },
415 /* 0xee */ { NULL, NULL, 0 },
416 /* 0xef */ { NULL, NULL, 0 },
417 /* 0xf0 */ { NULL, NULL, 0 },
418 /* 0xf1 */ { NULL, NULL, 0 },
419 /* 0xf2 */ { NULL, NULL, 0 },
420 /* 0xf3 */ { NULL, NULL, 0 },
421 /* 0xf4 */ { NULL, NULL, 0 },
422 /* 0xf5 */ { NULL, NULL, 0 },
423 /* 0xf6 */ { NULL, NULL, 0 },
424 /* 0xf7 */ { NULL, NULL, 0 },
425 /* 0xf8 */ { NULL, NULL, 0 },
426 /* 0xf9 */ { NULL, NULL, 0 },
427 /* 0xfa */ { NULL, NULL, 0 },
428 /* 0xfb */ { NULL, NULL, 0 },
429 /* 0xfc */ { NULL, NULL, 0 },
430 /* 0xfd */ { NULL, NULL, 0 },
431 /* 0xfe */ { NULL, NULL, 0 },
432 /* 0xff */ { NULL, NULL, 0 }
433 };
434
435 /****************************************************************************
436 return a string containing the function name of a SMB command
437 ****************************************************************************/
438 static const char *smb_fn_name(uint8_t type)
439 {
440         const char *unknown_name = "SMBunknown";
441
442         if (smb_messages[type].name == NULL)
443                 return unknown_name;
444
445         return smb_messages[type].name;
446 }
447
448
449 /****************************************************************************
450  Do a switch on the message type and call the specific reply function for this 
451 message. Unlike earlier versions of Samba the reply functions are responsible
452 for sending the reply themselves, rather than returning a size to this function
453 The reply functions may also choose to delay the processing by pushing the message
454 onto the message queue
455 ****************************************************************************/
456 static void switch_message(int type, struct smbsrv_request *req)
457 {
458         int flags;
459         struct smbsrv_connection *smb_conn = req->smb_conn;
460         NTSTATUS status;
461
462         type &= 0xff;
463
464         errno = 0;
465
466         if (smb_messages[type].fn == NULL) {
467                 DEBUG(0,("Unknown message type %d!\n",type));
468                 smbsrv_reply_unknown(req);
469                 return;
470         }
471
472         flags = smb_messages[type].flags;
473
474         req->tcon = smbsrv_smb_tcon_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
475
476         if (!req->session) {
477                 /* setup the user context for this request if it
478                    hasn't already been initialised (to cope with SMB
479                    chaining) */
480
481                 /* In share mode security we must ignore the vuid. */
482                 if (smb_conn->config.security == SEC_SHARE) {
483                         if (req->tcon) {
484                                 req->session = req->tcon->sec_share.session;
485                         }
486                 } else {
487                         req->session = smbsrv_session_find(req->smb_conn, SVAL(req->in.hdr,HDR_UID));
488                 }
489         }
490
491         DEBUG(5,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id));
492
493         /* this must be called before we do any reply */
494         if (flags & SIGNING_NO_REPLY) {
495                 smbsrv_signing_no_reply(req);
496         }
497
498         /* see if the vuid is valid */
499         if ((flags & NEED_SESS) && !req->session) {
500                 /* amazingly, the error code depends on the command */
501                 switch (type) {
502                         case SMBntcreateX:
503                         case SMBntcancel:
504                         case SMBulogoffX:
505                                 status = NT_STATUS_DOS(ERRSRV, ERRbaduid);
506                                 break;
507                         default:
508                                 status = NT_STATUS_INVALID_HANDLE;
509                                 break;
510                 }
511                 /* 
512                  * TODO:
513                  * don't know how to handle smb signing for this case 
514                  * so just skip the reply
515                  */
516                 if ((flags & SIGNING_NO_REPLY) &&
517                     (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
518                         DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
519                                 smb_fn_name(type), nt_errstr(status)));
520                         talloc_free(req);
521                         return;
522                 }
523                 smbsrv_send_error(req, status);
524                 return;
525         }
526
527         /* does this protocol need a valid tree connection? */
528         if ((flags & NEED_TCON) && !req->tcon) {
529                 /* amazingly, the error code depends on the command */
530                 switch (type) {
531                         case SMBntcreateX:
532                         case SMBntcancel:
533                                 status = NT_STATUS_DOS(ERRSRV, ERRinvnid);
534                                 break;
535                         default:
536                                 status = NT_STATUS_INVALID_HANDLE;
537                                 break;
538                 }
539                 /* 
540                  * TODO:
541                  * don't know how to handle smb signing for this case 
542                  * so just skip the reply
543                  */
544                 if ((flags & SIGNING_NO_REPLY) &&
545                     (req->smb_conn->signing.signing_state != SMB_SIGNING_ENGINE_OFF)) {
546                         DEBUG(1,("SKIP ERROR REPLY: %s %s because of unknown smb signing case\n",
547                                 smb_fn_name(type), nt_errstr(status)));
548                         talloc_free(req);
549                         return;
550                 }
551                 smbsrv_send_error(req, status);
552                 return;
553         }
554
555         smb_messages[type].fn(req);
556 }
557
558 /*
559   we call this when first first part of a possibly chained request has been completed
560   and we need to call the 2nd part, if any
561 */
562 void smbsrv_chain_reply(struct smbsrv_request *req)
563 {
564         uint16_t chain_cmd, chain_offset;
565         uint8_t *vwv, *data;
566         uint16_t wct;
567         uint16_t data_size;
568
569         if (req->in.wct < 2 || req->out.wct < 2) {
570                 smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
571                 return;
572         }
573
574         chain_cmd    = CVAL(req->in.vwv, VWV(0));
575         chain_offset = SVAL(req->in.vwv, VWV(1));
576
577         if (chain_cmd == SMB_CHAIN_NONE) {
578                 /* end of chain */
579                 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
580                 SSVAL(req->out.vwv, VWV(1), 0);
581                 smbsrv_send_reply(req);
582                 return;
583         }
584
585         if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
586                 goto error;
587         }
588
589         wct = CVAL(req->in.hdr, chain_offset);
590         vwv = req->in.hdr + chain_offset + 1;
591
592         if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
593                 goto error;
594         }
595
596         data_size = SVAL(vwv, VWV(wct));
597         data = vwv + VWV(wct) + 2;
598
599         if (data + data_size > req->in.buffer + req->in.size) {
600                 goto error;
601         }
602
603         /* all seems legit */
604         req->in.vwv = vwv;
605         req->in.wct = wct;
606         req->in.data = data;
607         req->in.data_size = data_size;
608         req->in.ptr = data;
609
610         req->chain_count++;
611
612         SSVAL(req->out.vwv, VWV(0), chain_cmd);
613         SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
614
615         /* cleanup somestuff for the next request */
616         talloc_free(req->ntvfs);
617         req->ntvfs = NULL;
618         talloc_free(req->io_ptr);
619         req->io_ptr = NULL;
620
621         switch_message(chain_cmd, req);
622         return;
623
624 error:
625         SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
626         SSVAL(req->out.vwv, VWV(1), 0);
627         smbsrv_send_error(req, NT_STATUS_DOS(ERRSRV, ERRerror));
628 }
629
630 /*
631  * init the SMB protocol related stuff
632  */
633 NTSTATUS smbsrv_init_smb_connection(struct smbsrv_connection *smb_conn)
634 {
635         NTSTATUS status;
636
637         /* now initialise a few default values associated with this smb socket */
638         smb_conn->negotiate.max_send = 0xFFFF;
639
640         /* this is the size that w2k uses, and it appears to be important for
641            good performance */
642         smb_conn->negotiate.max_recv = lp_max_xmit();
643
644         smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
645
646         smb_conn->config.security = lp_security();
647         smb_conn->config.nt_status_support = lp_nt_status_support();
648
649         status = smbsrv_init_sessions(smb_conn, UINT16_MAX);
650         NT_STATUS_NOT_OK_RETURN(status);
651
652         status = smbsrv_smb_init_tcons(smb_conn);
653         NT_STATUS_NOT_OK_RETURN(status);
654
655         smbsrv_init_signing(smb_conn);
656
657         return NT_STATUS_OK;
658 }