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>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 send an oplock break request to a client
28 BOOL req_send_oplock_break(struct smbsrv_tcon *tcon, uint16_t fnum, uint8_t level)
30 struct smbsrv_request *req;
32 req = init_smb_request(tcon->smb_conn);
34 req_setup_reply(req, 8, 0);
36 SCVAL(req->out.hdr,HDR_COM,SMBlockingX);
37 SSVAL(req->out.hdr,HDR_TID,tcon->cnum);
38 SSVAL(req->out.hdr,HDR_PID,0xFFFF);
39 SSVAL(req->out.hdr,HDR_UID,0);
40 SSVAL(req->out.hdr,HDR_MID,0xFFFF);
41 SCVAL(req->out.hdr,HDR_FLG,0);
42 SSVAL(req->out.hdr,HDR_FLG2,0);
44 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
45 SSVAL(req->out.vwv, VWV(1), 0);
46 SSVAL(req->out.vwv, VWV(2), fnum);
47 SCVAL(req->out.vwv, VWV(3), LOCKING_ANDX_OPLOCK_RELEASE);
48 SCVAL(req->out.vwv, VWV(3)+1, level);
49 SIVAL(req->out.vwv, VWV(4), 0);
50 SSVAL(req->out.vwv, VWV(6), 0);
51 SSVAL(req->out.vwv, VWV(7), 0);
57 /****************************************************************************
58 receive a SMB request from the wire, forming a request_context from the result
59 ****************************************************************************/
60 static struct smbsrv_request *receive_smb_request(struct smbsrv_connection *smb_conn)
64 struct smbsrv_request *req;
66 len = read_data(smb_conn->connection->socket->fde->fd, header, 4);
71 len = smb_len(header);
73 req = init_smb_request(smb_conn);
75 GetTimeOfDay(&req->request_time);
76 req->chained_fnum = -1;
78 /* allocate the incoming buffer at the right size */
79 req->in.buffer = talloc(req->mem_ctx, len + NBT_HDR_SIZE);
81 /* fill in the already received header */
82 memcpy(req->in.buffer, header, 4);
84 len2 = read_data(smb_conn->connection->socket->fde->fd, req->in.buffer + NBT_HDR_SIZE, len);
89 /* fill in the rest of the req->in structure */
90 req->in.size = len + NBT_HDR_SIZE;
91 req->in.allocated = req->in.size;
92 req->in.hdr = req->in.buffer + NBT_HDR_SIZE;
93 req->in.vwv = req->in.hdr + HDR_VWV;
94 req->in.wct = CVAL(req->in.hdr, HDR_WCT);
95 if (req->in.vwv + VWV(req->in.wct) <= req->in.buffer + req->in.size) {
96 req->in.data = req->in.vwv + VWV(req->in.wct) + 2;
97 req->in.data_size = SVAL(req->in.vwv, VWV(req->in.wct));
99 /* the bcc length is only 16 bits, but some packets
100 (such as SMBwriteX) can be much larger than 64k. We
101 detect this by looking for a large non-chained NBT
102 packet (at least 64k bigger than what is
103 specified). If it is detected then the NBT size is
104 used instead of the bcc size */
105 if (req->in.data_size + 0x10000 <=
106 req->in.size - PTR_DIFF(req->in.data, req->in.buffer) &&
107 (req->in.wct < 1 || SVAL(req->in.vwv, VWV(0)) == SMB_CHAIN_NONE)) {
108 /* its an oversized packet! fun for all the family */
109 req->in.data_size = req->in.size - PTR_DIFF(req->in.data,req->in.buffer);
117 These flags determine some of the permissions required to do an operation
119 Note that I don't set NEED_WRITE on some write operations because they
120 are used by some brain-dead clients when printing, and I don't want to
121 force write permissions on print services.
123 #define AS_USER (1<<0)
124 #define NEED_WRITE (1<<1)
125 #define TIME_INIT (1<<2)
126 #define CAN_IPC (1<<3)
127 #define AS_GUEST (1<<5)
128 #define USE_MUTEX (1<<7)
131 define a list of possible SMB messages and their corresponding
132 functions. Any message that has a NULL function is unimplemented -
133 please feel free to contribute implementations!
135 static const struct smb_message_struct
138 void (*fn)(struct smbsrv_request *);
141 smb_messages[256] = {
142 /* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
143 /* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
144 /* 0x02 */ { "SMBopen",reply_open,AS_USER },
145 /* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
146 /* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
147 /* 0x05 */ { "SMBflush",reply_flush,AS_USER},
148 /* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
149 /* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
150 /* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
151 /* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
152 /* 0x0a */ { "SMBread",reply_read,AS_USER},
153 /* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
154 /* 0x0c */ { "SMBlock",reply_lock,AS_USER},
155 /* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
156 /* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
157 /* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
158 /* 0x10 */ { "SMBchkpth",reply_chkpth,AS_USER},
159 /* 0x11 */ { "SMBexit",reply_exit,0},
160 /* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
161 /* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
162 /* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
163 /* 0x15 */ { NULL, NULL, 0 },
164 /* 0x16 */ { NULL, NULL, 0 },
165 /* 0x17 */ { NULL, NULL, 0 },
166 /* 0x18 */ { NULL, NULL, 0 },
167 /* 0x19 */ { NULL, NULL, 0 },
168 /* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
169 /* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
170 /* 0x1c */ { "SMBreadBs",NULL,0 },
171 /* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
172 /* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
173 /* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
174 /* 0x20 */ { "SMBwritec",NULL,0},
175 /* 0x21 */ { NULL, NULL, 0 },
176 /* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
177 /* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
178 /* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
179 /* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
180 /* 0x26 */ { "SMBtranss",NULL,AS_USER | CAN_IPC},
181 /* 0x27 */ { "SMBioctl",reply_ioctl,0},
182 /* 0x28 */ { "SMBioctls",NULL,AS_USER},
183 /* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
184 /* 0x2a */ { "SMBmove",NULL,AS_USER | NEED_WRITE },
185 /* 0x2b */ { "SMBecho",reply_echo,0},
186 /* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
187 /* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
188 /* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
189 /* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
190 /* 0x30 */ { NULL, NULL, 0 },
191 /* 0x31 */ { NULL, NULL, 0 },
192 /* 0x32 */ { "SMBtrans2", reply_trans2, AS_USER | CAN_IPC },
193 /* 0x33 */ { "SMBtranss2", reply_transs2, AS_USER},
194 /* 0x34 */ { "SMBfindclose", reply_findclose,AS_USER},
195 /* 0x35 */ { "SMBfindnclose", reply_findnclose, AS_USER},
196 /* 0x36 */ { NULL, NULL, 0 },
197 /* 0x37 */ { NULL, NULL, 0 },
198 /* 0x38 */ { NULL, NULL, 0 },
199 /* 0x39 */ { NULL, NULL, 0 },
200 /* 0x3a */ { NULL, NULL, 0 },
201 /* 0x3b */ { NULL, NULL, 0 },
202 /* 0x3c */ { NULL, NULL, 0 },
203 /* 0x3d */ { NULL, NULL, 0 },
204 /* 0x3e */ { NULL, NULL, 0 },
205 /* 0x3f */ { NULL, NULL, 0 },
206 /* 0x40 */ { NULL, NULL, 0 },
207 /* 0x41 */ { NULL, NULL, 0 },
208 /* 0x42 */ { NULL, NULL, 0 },
209 /* 0x43 */ { NULL, NULL, 0 },
210 /* 0x44 */ { NULL, NULL, 0 },
211 /* 0x45 */ { NULL, NULL, 0 },
212 /* 0x46 */ { NULL, NULL, 0 },
213 /* 0x47 */ { NULL, NULL, 0 },
214 /* 0x48 */ { NULL, NULL, 0 },
215 /* 0x49 */ { NULL, NULL, 0 },
216 /* 0x4a */ { NULL, NULL, 0 },
217 /* 0x4b */ { NULL, NULL, 0 },
218 /* 0x4c */ { NULL, NULL, 0 },
219 /* 0x4d */ { NULL, NULL, 0 },
220 /* 0x4e */ { NULL, NULL, 0 },
221 /* 0x4f */ { NULL, NULL, 0 },
222 /* 0x50 */ { NULL, NULL, 0 },
223 /* 0x51 */ { NULL, NULL, 0 },
224 /* 0x52 */ { NULL, NULL, 0 },
225 /* 0x53 */ { NULL, NULL, 0 },
226 /* 0x54 */ { NULL, NULL, 0 },
227 /* 0x55 */ { NULL, NULL, 0 },
228 /* 0x56 */ { NULL, NULL, 0 },
229 /* 0x57 */ { NULL, NULL, 0 },
230 /* 0x58 */ { NULL, NULL, 0 },
231 /* 0x59 */ { NULL, NULL, 0 },
232 /* 0x5a */ { NULL, NULL, 0 },
233 /* 0x5b */ { NULL, NULL, 0 },
234 /* 0x5c */ { NULL, NULL, 0 },
235 /* 0x5d */ { NULL, NULL, 0 },
236 /* 0x5e */ { NULL, NULL, 0 },
237 /* 0x5f */ { NULL, NULL, 0 },
238 /* 0x60 */ { NULL, NULL, 0 },
239 /* 0x61 */ { NULL, NULL, 0 },
240 /* 0x62 */ { NULL, NULL, 0 },
241 /* 0x63 */ { NULL, NULL, 0 },
242 /* 0x64 */ { NULL, NULL, 0 },
243 /* 0x65 */ { NULL, NULL, 0 },
244 /* 0x66 */ { NULL, NULL, 0 },
245 /* 0x67 */ { NULL, NULL, 0 },
246 /* 0x68 */ { NULL, NULL, 0 },
247 /* 0x69 */ { NULL, NULL, 0 },
248 /* 0x6a */ { NULL, NULL, 0 },
249 /* 0x6b */ { NULL, NULL, 0 },
250 /* 0x6c */ { NULL, NULL, 0 },
251 /* 0x6d */ { NULL, NULL, 0 },
252 /* 0x6e */ { NULL, NULL, 0 },
253 /* 0x6f */ { NULL, NULL, 0 },
254 /* 0x70 */ { "SMBtcon",reply_tcon,USE_MUTEX},
255 /* 0x71 */ { "SMBtdis",reply_tdis,0},
256 /* 0x72 */ { "SMBnegprot",reply_negprot,USE_MUTEX},
257 /* 0x73 */ { "SMBsesssetupX",reply_sesssetup,USE_MUTEX},
258 /* 0x74 */ { "SMBulogoffX", reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
259 /* 0x75 */ { "SMBtconX",reply_tcon_and_X,USE_MUTEX},
260 /* 0x76 */ { NULL, NULL, 0 },
261 /* 0x77 */ { NULL, NULL, 0 },
262 /* 0x78 */ { NULL, NULL, 0 },
263 /* 0x79 */ { NULL, NULL, 0 },
264 /* 0x7a */ { NULL, NULL, 0 },
265 /* 0x7b */ { NULL, NULL, 0 },
266 /* 0x7c */ { NULL, NULL, 0 },
267 /* 0x7d */ { NULL, NULL, 0 },
268 /* 0x7e */ { NULL, NULL, 0 },
269 /* 0x7f */ { NULL, NULL, 0 },
270 /* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
271 /* 0x81 */ { "SMBsearch",reply_search,AS_USER},
272 /* 0x82 */ { "SMBffirst",reply_search,AS_USER},
273 /* 0x83 */ { "SMBfunique",reply_search,AS_USER},
274 /* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
275 /* 0x85 */ { NULL, NULL, 0 },
276 /* 0x86 */ { NULL, NULL, 0 },
277 /* 0x87 */ { NULL, NULL, 0 },
278 /* 0x88 */ { NULL, NULL, 0 },
279 /* 0x89 */ { NULL, NULL, 0 },
280 /* 0x8a */ { NULL, NULL, 0 },
281 /* 0x8b */ { NULL, NULL, 0 },
282 /* 0x8c */ { NULL, NULL, 0 },
283 /* 0x8d */ { NULL, NULL, 0 },
284 /* 0x8e */ { NULL, NULL, 0 },
285 /* 0x8f */ { NULL, NULL, 0 },
286 /* 0x90 */ { NULL, NULL, 0 },
287 /* 0x91 */ { NULL, NULL, 0 },
288 /* 0x92 */ { NULL, NULL, 0 },
289 /* 0x93 */ { NULL, NULL, 0 },
290 /* 0x94 */ { NULL, NULL, 0 },
291 /* 0x95 */ { NULL, NULL, 0 },
292 /* 0x96 */ { NULL, NULL, 0 },
293 /* 0x97 */ { NULL, NULL, 0 },
294 /* 0x98 */ { NULL, NULL, 0 },
295 /* 0x99 */ { NULL, NULL, 0 },
296 /* 0x9a */ { NULL, NULL, 0 },
297 /* 0x9b */ { NULL, NULL, 0 },
298 /* 0x9c */ { NULL, NULL, 0 },
299 /* 0x9d */ { NULL, NULL, 0 },
300 /* 0x9e */ { NULL, NULL, 0 },
301 /* 0x9f */ { NULL, NULL, 0 },
302 /* 0xa0 */ { "SMBnttrans", reply_nttrans, AS_USER | CAN_IPC },
303 /* 0xa1 */ { "SMBnttranss", reply_nttranss, AS_USER | CAN_IPC },
304 /* 0xa2 */ { "SMBntcreateX", reply_ntcreate_and_X, AS_USER | CAN_IPC },
305 /* 0xa3 */ { NULL, NULL, 0 },
306 /* 0xa4 */ { "SMBntcancel", reply_ntcancel, 0 },
307 /* 0xa5 */ { "SMBntrename", reply_ntrename, 0 },
308 /* 0xa6 */ { NULL, NULL, 0 },
309 /* 0xa7 */ { NULL, NULL, 0 },
310 /* 0xa8 */ { NULL, NULL, 0 },
311 /* 0xa9 */ { NULL, NULL, 0 },
312 /* 0xaa */ { NULL, NULL, 0 },
313 /* 0xab */ { NULL, NULL, 0 },
314 /* 0xac */ { NULL, NULL, 0 },
315 /* 0xad */ { NULL, NULL, 0 },
316 /* 0xae */ { NULL, NULL, 0 },
317 /* 0xaf */ { NULL, NULL, 0 },
318 /* 0xb0 */ { NULL, NULL, 0 },
319 /* 0xb1 */ { NULL, NULL, 0 },
320 /* 0xb2 */ { NULL, NULL, 0 },
321 /* 0xb3 */ { NULL, NULL, 0 },
322 /* 0xb4 */ { NULL, NULL, 0 },
323 /* 0xb5 */ { NULL, NULL, 0 },
324 /* 0xb6 */ { NULL, NULL, 0 },
325 /* 0xb7 */ { NULL, NULL, 0 },
326 /* 0xb8 */ { NULL, NULL, 0 },
327 /* 0xb9 */ { NULL, NULL, 0 },
328 /* 0xba */ { NULL, NULL, 0 },
329 /* 0xbb */ { NULL, NULL, 0 },
330 /* 0xbc */ { NULL, NULL, 0 },
331 /* 0xbd */ { NULL, NULL, 0 },
332 /* 0xbe */ { NULL, NULL, 0 },
333 /* 0xbf */ { NULL, NULL, 0 },
334 /* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER },
335 /* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
336 /* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
337 /* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
338 /* 0xc4 */ { NULL, NULL, 0 },
339 /* 0xc5 */ { NULL, NULL, 0 },
340 /* 0xc6 */ { NULL, NULL, 0 },
341 /* 0xc7 */ { NULL, NULL, 0 },
342 /* 0xc8 */ { NULL, NULL, 0 },
343 /* 0xc9 */ { NULL, NULL, 0 },
344 /* 0xca */ { NULL, NULL, 0 },
345 /* 0xcb */ { NULL, NULL, 0 },
346 /* 0xcc */ { NULL, NULL, 0 },
347 /* 0xcd */ { NULL, NULL, 0 },
348 /* 0xce */ { NULL, NULL, 0 },
349 /* 0xcf */ { NULL, NULL, 0 },
350 /* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
351 /* 0xd1 */ { "SMBsendb",NULL,AS_GUEST},
352 /* 0xd2 */ { "SMBfwdname",NULL,AS_GUEST},
353 /* 0xd3 */ { "SMBcancelf",NULL,AS_GUEST},
354 /* 0xd4 */ { "SMBgetmac",NULL,AS_GUEST},
355 /* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
356 /* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
357 /* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
358 /* 0xd8 */ { NULL, NULL, 0 },
359 /* 0xd9 */ { NULL, NULL, 0 },
360 /* 0xda */ { NULL, NULL, 0 },
361 /* 0xdb */ { NULL, NULL, 0 },
362 /* 0xdc */ { NULL, NULL, 0 },
363 /* 0xdd */ { NULL, NULL, 0 },
364 /* 0xde */ { NULL, NULL, 0 },
365 /* 0xdf */ { NULL, NULL, 0 },
366 /* 0xe0 */ { NULL, NULL, 0 },
367 /* 0xe1 */ { NULL, NULL, 0 },
368 /* 0xe2 */ { NULL, NULL, 0 },
369 /* 0xe3 */ { NULL, NULL, 0 },
370 /* 0xe4 */ { NULL, NULL, 0 },
371 /* 0xe5 */ { NULL, NULL, 0 },
372 /* 0xe6 */ { NULL, NULL, 0 },
373 /* 0xe7 */ { NULL, NULL, 0 },
374 /* 0xe8 */ { NULL, NULL, 0 },
375 /* 0xe9 */ { NULL, NULL, 0 },
376 /* 0xea */ { NULL, NULL, 0 },
377 /* 0xeb */ { NULL, NULL, 0 },
378 /* 0xec */ { NULL, NULL, 0 },
379 /* 0xed */ { NULL, NULL, 0 },
380 /* 0xee */ { NULL, NULL, 0 },
381 /* 0xef */ { NULL, NULL, 0 },
382 /* 0xf0 */ { NULL, NULL, 0 },
383 /* 0xf1 */ { NULL, NULL, 0 },
384 /* 0xf2 */ { NULL, NULL, 0 },
385 /* 0xf3 */ { NULL, NULL, 0 },
386 /* 0xf4 */ { NULL, NULL, 0 },
387 /* 0xf5 */ { NULL, NULL, 0 },
388 /* 0xf6 */ { NULL, NULL, 0 },
389 /* 0xf7 */ { NULL, NULL, 0 },
390 /* 0xf8 */ { NULL, NULL, 0 },
391 /* 0xf9 */ { NULL, NULL, 0 },
392 /* 0xfa */ { NULL, NULL, 0 },
393 /* 0xfb */ { NULL, NULL, 0 },
394 /* 0xfc */ { NULL, NULL, 0 },
395 /* 0xfd */ { NULL, NULL, 0 },
396 /* 0xfe */ { NULL, NULL, 0 },
397 /* 0xff */ { NULL, NULL, 0 }
400 /****************************************************************************
401 return a string containing the function name of a SMB command
402 ****************************************************************************/
403 static const char *smb_fn_name(uint8_t type)
405 const char *unknown_name = "SMBunknown";
407 if (smb_messages[type].name == NULL)
410 return smb_messages[type].name;
414 /****************************************************************************
415 Do a switch on the message type and call the specific reply function for this
416 message. Unlike earlier versions of Samba the reply functions are responsible
417 for sending the reply themselves, rather than returning a size to this function
418 The reply functions may also choose to delay the processing by pushing the message
419 onto the message queue
420 ****************************************************************************/
421 static void switch_message(int type, struct smbsrv_request *req)
424 struct smbsrv_connection *smb_conn = req->smb_conn;
425 uint16_t session_tag;
431 if (smb_messages[type].fn == NULL) {
432 DEBUG(0,("Unknown message type %d!\n",type));
437 flags = smb_messages[type].flags;
439 req->tcon = conn_find(smb_conn, SVAL(req->in.hdr,HDR_TID));
441 if (req->session == NULL) {
442 /* setup the user context for this request if it
443 hasn't already been initialised (to cope with SMB
446 /* In share mode security we must ignore the vuid. */
447 if (lp_security() == SEC_SHARE) {
448 session_tag = UID_FIELD_INVALID;
450 session_tag = SVAL(req->in.hdr,HDR_UID);
453 req->session = smbsrv_session_find(req->smb_conn, session_tag);
455 req->session->vuid = session_tag;
458 session_tag = req->session->vuid;
461 DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb_conn->connection->service->model_ops->get_id(req)));
463 /* does this protocol need to be run as root? */
464 if (!(flags & AS_USER)) {
465 change_to_root_user();
468 /* does this protocol need a valid tree connection? */
469 if ((flags & AS_USER) && !req->tcon) {
470 req_reply_error(req, NT_STATUS_NETWORK_NAME_DELETED);
474 /* see if the vuid is valid */
475 if ((flags & AS_USER) && !req->session) {
476 if (!(flags & AS_GUEST)) {
477 req_reply_error(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
482 /* does this protocol need to be run as the connected user? */
484 if ((flags & AS_USER) && !change_to_user(req->tcon,session_tag)) {
485 if (!(flags & AS_GUEST)) {
486 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
490 /* we'll run it as guest */
495 /* this code is to work around a bug is MS client 3 without
496 introducing a security hole - it needs to be able to do
497 print queue checks as guest if it isn't logged in properly */
498 if (flags & AS_USER) {
502 /* does it need write permission? */
503 if ((flags & NEED_WRITE) && !CAN_WRITE(req->tcon)) {
504 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
508 /* ipc services are limited */
509 if (req->tcon && req->tcon->type == NTVFS_IPC && (flags & AS_USER) && !(flags & CAN_IPC)) {
510 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
514 /* load service specific parameters */
515 if (req->tcon && !set_current_service(req->tcon,(flags & AS_USER)?True:False)) {
516 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
520 /* does this protocol need to be run as guest? */
522 if ((flags & AS_GUEST) &&
523 !change_to_guest()) {
524 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
528 /* THREAD TESTING: use mutex to serialize calls to critical functions with global state */
529 if (flags & USE_MUTEX) {
530 MUTEX_LOCK_BY_ID(MUTEX_SMBD);
532 smb_messages[type].fn(req);
533 if (flags & USE_MUTEX) {
534 MUTEX_UNLOCK_BY_ID(MUTEX_SMBD);
539 /****************************************************************************
540 Construct a reply to the incoming packet.
541 ****************************************************************************/
542 static void construct_reply(struct smbsrv_request *req)
544 uint8_t type = CVAL(req->in.hdr,HDR_COM);
546 /* see if its a special NBT packet */
547 if (CVAL(req->in.buffer,0) != 0) {
552 /* Make sure this is an SMB packet */
553 if (memcmp(req->in.hdr,"\377SMB",4) != 0) {
554 DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n",
556 smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet");
560 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) {
561 DEBUG(2,("Invalid SMB word count %d\n", req->in.wct));
562 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
566 if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) {
567 DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size));
568 smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet");
573 req->smbpid = SVAL(req->in.hdr,HDR_PID);
574 req->flags = CVAL(req->in.hdr, HDR_FLG);
575 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
577 if (!req_signing_check_incoming(req)) {
578 req_reply_error(req, NT_STATUS_ACCESS_DENIED);
582 switch_message(type, req);
587 we call this when first first part of a possibly chained request has been completed
588 and we need to call the 2nd part, if any
590 void chain_reply(struct smbsrv_request *req)
592 uint16_t chain_cmd, chain_offset;
597 if (req->in.wct < 2 || req->out.wct < 2) {
598 req_reply_dos_error(req, ERRSRV, ERRerror);
602 chain_cmd = CVAL(req->in.vwv, VWV(0));
603 chain_offset = SVAL(req->in.vwv, VWV(1));
605 if (chain_cmd == SMB_CHAIN_NONE) {
607 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
608 SSVAL(req->out.vwv, VWV(1), 0);
613 if (chain_offset + req->in.hdr >= req->in.buffer + req->in.size) {
617 wct = CVAL(req->in.hdr, chain_offset);
618 vwv = req->in.hdr + chain_offset + 1;
620 if (vwv + VWV(wct) + 2 > req->in.buffer + req->in.size) {
624 data_size = SVAL(vwv, VWV(wct));
625 data = vwv + VWV(wct) + 2;
627 if (data + data_size > req->in.buffer + req->in.size) {
631 /* all seems legit */
635 req->in.data_size = data_size;
640 SSVAL(req->out.vwv, VWV(0), chain_cmd);
641 SSVAL(req->out.vwv, VWV(1), req->out.size - NBT_HDR_SIZE);
643 /* the current request in the chain might have used an async reply,
644 but that doesn't mean the next element needs to */
645 ZERO_STRUCT(req->async);
646 req->control_flags &= ~REQ_CONTROL_ASYNC;
648 switch_message(chain_cmd, req);
652 SSVAL(req->out.vwv, VWV(0), SMB_CHAIN_NONE);
653 SSVAL(req->out.vwv, VWV(1), 0);
654 req_reply_dos_error(req, ERRSRV, ERRerror);
659 close the socket and shutdown a server_context
661 void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
663 server_terminate_connection(smb_conn->connection, reason);
667 called on a fatal error that should cause this server to terminate
669 static void smbsrv_exit(struct server_service *service, const char *reason)
671 DEBUG(1,("smbsrv_exit\n"));
676 add a socket address to the list of events, one event per port
678 static void add_socket(struct server_service *service,
679 const struct model_ops *model_ops,
680 struct socket_context *socket_ctx,
681 struct in_addr *ifip)
684 const char *delim = ", ";
686 for (tok=strtok_r(lp_smb_ports(), delim, &ptr);
688 tok=strtok_r(NULL, delim, &ptr)) {
689 uint16_t port = atoi(tok);
690 if (port == 0) continue;
691 service_setup_socket(service, model_ops, socket_ctx, ifip, &port);
695 /****************************************************************************
696 Open the socket communication.
697 ****************************************************************************/
698 static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops)
700 DEBUG(1,("smbsrv_init\n"));
702 if (lp_interfaces() && lp_bind_interfaces_only()) {
703 int num_interfaces = iface_count();
706 /* We have been given an interfaces line, and been
707 told to only bind to those interfaces. Create a
708 socket per interface and bind to only these.
710 for(i = 0; i < num_interfaces; i++) {
711 struct in_addr *ifip = iface_n_ip(i);
714 DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i));
718 add_socket(service, model_ops, NULL, ifip);
721 struct in_addr *ifip;
722 TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd");
725 smb_panic("No memory");
728 /* Just bind to lp_socket_address() (usually 0.0.0.0) */
729 ifip = interpret_addr2(mem_ctx, lp_socket_address());
730 add_socket(service, model_ops, NULL, ifip);
732 talloc_destroy(mem_ctx);
737 called when a SMB socket becomes readable
739 static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags)
741 struct smbsrv_request *req;
742 struct smbsrv_connection *smb_conn = conn->private_data;
744 DEBUG(10,("smbsrv_recv\n"));
746 req = receive_smb_request(smb_conn);
748 smbsrv_terminate_connection(smb_conn, "receive error");
752 construct_reply(req);
754 /* free up temporary memory */
760 called when a SMB socket becomes writable
762 static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags)
764 DEBUG(10,("smbsrv_send\n"));
769 called when connection is idle
771 static void smbsrv_idle(struct server_connection *conn, time_t t)
773 DEBUG(10,("smbsrv_idle: not implemented!\n"));
774 conn->event.idle->next_event = t + 5;
779 static void smbsrv_close(struct server_connection *conn, const char *reason)
781 struct smbsrv_connection *smb_conn = conn->private_data;
783 DEBUG(5,("smbsrv_close: %s\n",reason));
785 close(conn->event.fde->fd);
786 event_remove_fd_all(conn->event.ctx, conn->socket->fde->fd);
787 event_remove_timed(conn->event.ctx, conn->event.idle);
789 conn_close_all(smb_conn);
791 talloc_destroy(smb_conn->mem_ctx);
796 process a message from an SMB socket while still processing a
797 previous message this is used by backends who need to ensure that
798 new messages from clients are still processed while they are
799 performing long operations
801 void smbd_process_async(struct smbsrv_connection *smb_conn)
803 struct smbsrv_request *req;
805 req = receive_smb_request(smb_conn);
807 smbsrv_terminate_connection(smb_conn, "receive error");
811 construct_reply(req);
816 initialise a server_context from a open socket and register a event handler
817 for reading from that socket
819 void smbsrv_accept(struct server_connection *conn)
821 struct smbsrv_connection *smb_conn;
825 DEBUG(5,("smbsrv_accept\n"));
827 mem_ctx = talloc_init("smbsrv_context");
829 smb_conn = talloc_p(mem_ctx, struct smbsrv_connection);
830 if (!smb_conn) return;
832 ZERO_STRUCTP(smb_conn);
834 smb_conn->mem_ctx = mem_ctx;
835 smb_conn->pid = getpid();
837 sub_set_context(&smb_conn->substitute);
839 /* set an initial client name based on its IP address. This will be replaced with
840 the netbios name later if it gives us one */
841 socket_addr = get_socket_addr(smb_conn->mem_ctx, conn->socket->fde->fd);
842 sub_set_remote_machine(socket_addr);
844 /* now initialise a few default values associated with this smb socket */
845 smb_conn->negotiate.max_send = 0xFFFF;
847 /* this is the size that w2k uses, and it appears to be important for
849 smb_conn->negotiate.max_recv = lp_max_xmit();
851 smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));
853 smb_conn->sessions.next_vuid = VUID_OFFSET;
857 smb_conn->connection = conn;
859 conn->private_data = smb_conn;
861 /* setup the DCERPC server subsystem */
862 dcesrv_init_context(&smb_conn->dcesrv);
867 static const struct server_service_ops smb_server_ops = {
869 .service_init = smbsrv_init,
870 .accept_connection = smbsrv_accept,
871 .recv_handler = smbsrv_recv,
872 .send_handler = smbsrv_send,
873 .idle_handler = smbsrv_idle,
874 .close_connection = smbsrv_close,
875 .service_exit = smbsrv_exit,
878 const struct server_service_ops *smbsrv_get_ops(void)
880 return &smb_server_ops;
883 NTSTATUS server_service_smb_init(void)