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