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