This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "smbd/service_stream.h"
#include "lib/stream/packet.h"
#include "ntvfs/ntvfs.h"
+#include "param/param.h"
static int smb2srv_request_destructor(struct smb2srv_request *req)
{
return -1;
}
-static struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
+struct smb2srv_request *smb2srv_init_request(struct smbsrv_connection *smb_conn)
{
struct smb2srv_request *req;
req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE+body_fixed_size;
req->out.allocated = req->out.size + body_dynamic_size;
- req->out.buffer = talloc_size(req, req->out.allocated);
+ req->out.buffer = talloc_array(req, uint8_t,
+ req->out.allocated);
NT_STATUS_HAVE_NO_MEMORY(req->out.buffer);
req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
req->out.body_size = body_fixed_size;
req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
- SIVAL(req->out.hdr, 0, SMB2_MAGIC);
- SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
- SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
- SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(req->status));
- SSVAL(req->out.hdr, SMB2_HDR_OPCODE, SVAL(req->in.hdr, SMB2_HDR_OPCODE));
- SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1,0x0001);
- SIVAL(req->out.hdr, SMB2_HDR_FLAGS, flags);
- SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN2,0);
- SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
- SIVAL(req->out.hdr, SMB2_HDR_PID, pid);
- SIVAL(req->out.hdr, SMB2_HDR_TID, tid);
- SBVAL(req->out.hdr, SMB2_HDR_UID, BVAL(req->in.hdr, SMB2_HDR_UID));
+ SIVAL(req->out.hdr, 0, SMB2_MAGIC);
+ SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
+ SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
+ SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(req->status));
+ SSVAL(req->out.hdr, SMB2_HDR_OPCODE, SVAL(req->in.hdr, SMB2_HDR_OPCODE));
+ SSVAL(req->out.hdr, SMB2_HDR_UNKNOWN1, 0x0001);
+ SIVAL(req->out.hdr, SMB2_HDR_FLAGS, flags);
+ SIVAL(req->out.hdr, SMB2_HDR_CHAIN_OFFSET, 0);
+ SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
+ SIVAL(req->out.hdr, SMB2_HDR_PID, pid);
+ SIVAL(req->out.hdr, SMB2_HDR_TID, tid);
+ SBVAL(req->out.hdr, SMB2_HDR_UID, BVAL(req->in.hdr, SMB2_HDR_UID));
memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
/* set the length of the fixed body part and +1 if there's a dynamic part also */
return NT_STATUS_OK;
}
+static NTSTATUS smb2srv_reply(struct smb2srv_request *req);
+
+static void smb2srv_chain_reply(struct smb2srv_request *p_req)
+{
+ NTSTATUS status;
+ struct smb2srv_request *req;
+ uint32_t chain_offset;
+ uint32_t protocol_version;
+ uint16_t buffer_code;
+ uint32_t dynamic_size;
+
+ chain_offset = p_req->chain_offset;
+ p_req->chain_offset = 0;
+
+ if (p_req->in.size < (NBT_HDR_SIZE + chain_offset + SMB2_MIN_SIZE)) {
+ DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X\n",
+ chain_offset));
+ smbsrv_terminate_connection(p_req->smb_conn, "Invalid SMB2 chained packet");
+ return;
+ }
+
+ protocol_version = IVAL(p_req->in.buffer, NBT_HDR_SIZE + chain_offset);
+ if (protocol_version != SMB2_MAGIC) {
+ DEBUG(2,("Invalid SMB chained packet: protocol prefix: 0x%08X\n",
+ protocol_version));
+ smbsrv_terminate_connection(p_req->smb_conn, "NON-SMB2 chained packet");
+ return;
+ }
+
+ req = smb2srv_init_request(p_req->smb_conn);
+ if (!req) {
+ smbsrv_terminate_connection(p_req->smb_conn, "SMB2 chained packet - no memory");
+ return;
+ }
+
+ req->in.buffer = talloc_steal(req, p_req->in.buffer);
+ req->in.size = p_req->in.size;
+ req->request_time = p_req->request_time;
+ req->in.allocated = req->in.size;
+
+ req->in.hdr = req->in.buffer+ NBT_HDR_SIZE + chain_offset;
+ req->in.body = req->in.hdr + SMB2_HDR_BODY;
+ req->in.body_size = req->in.size - (NBT_HDR_SIZE+ chain_offset + SMB2_HDR_BODY);
+ req->in.dynamic = NULL;
+
+ buffer_code = SVAL(req->in.body, 0);
+ req->in.body_fixed = (buffer_code & ~1);
+ dynamic_size = req->in.body_size - req->in.body_fixed;
+
+ if (dynamic_size != 0 && (buffer_code & 1)) {
+ req->in.dynamic = req->in.body + req->in.body_fixed;
+ if (smb2_oob(&req->in, req->in.dynamic, dynamic_size)) {
+ DEBUG(1,("SMB2 chained request invalid dynamic size 0x%x\n",
+ dynamic_size));
+ smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
+ return;
+ }
+ }
+
+ if (p_req->chained_file_handle) {
+ memcpy(req->_chained_file_handle,
+ p_req->_chained_file_handle,
+ sizeof(req->_chained_file_handle));
+ req->chained_file_handle = req->_chained_file_handle;
+ }
+
+ /*
+ * TODO: - make sure the length field is 64
+ * - make sure it's a request
+ */
+
+ status = smb2srv_reply(req);
+ if (!NT_STATUS_IS_OK(status)) {
+ smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
+ talloc_free(req);
+ return;
+ }
+}
+
void smb2srv_send_reply(struct smb2srv_request *req)
{
DATA_BLOB blob;
if (!NT_STATUS_IS_OK(status)) {
smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
}
+ if (req->chain_offset) {
+ smb2srv_chain_reply(req);
+ return;
+ }
talloc_free(req);
}
uint32_t tid;
uint64_t uid;
- opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
- req->seqnum = BVAL(req->in.hdr, SMB2_HDR_SEQNUM);
- tid = IVAL(req->in.hdr, SMB2_HDR_TID);
- uid = BVAL(req->in.hdr, SMB2_HDR_UID);
+ opcode = SVAL(req->in.hdr, SMB2_HDR_OPCODE);
+ req->chain_offset = IVAL(req->in.hdr, SMB2_HDR_CHAIN_OFFSET);
+ req->seqnum = BVAL(req->in.hdr, SMB2_HDR_SEQNUM);
+ tid = IVAL(req->in.hdr, SMB2_HDR_TID);
+ uid = BVAL(req->in.hdr, SMB2_HDR_UID);
req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time);
req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
}
protocol_version = IVAL(blob.data, NBT_HDR_SIZE);
-
if (protocol_version != SMB2_MAGIC) {
DEBUG(2,("Invalid SMB packet: protocol prefix: 0x%08X\n",
protocol_version));
/* this is the size that w2k uses, and it appears to be important for
good performance */
- smb_conn->negotiate.max_recv = lp_max_xmit();
+ smb_conn->negotiate.max_recv = lp_max_xmit(global_loadparm);
smb_conn->negotiate.zone_offset = get_time_zone(time(NULL));