Beispiel #1
0
static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *_blob)
{
	struct gensec_security *gensec_security;
	DATA_BLOB null_data_blob = data_blob(NULL, 0);
	DATA_BLOB blob;
	NTSTATUS nt_status;
	struct cli_credentials *server_credentials;

	server_credentials = cli_credentials_init(req);
	if (!server_credentials) {
		smbsrv_terminate_connection(req->smb_conn, "Failed to init server credentials\n");
		return NT_STATUS_NO_MEMORY;
	}

	cli_credentials_set_conf(server_credentials, req->smb_conn->lp_ctx);
	nt_status = cli_credentials_set_machine_account(server_credentials, req->smb_conn->lp_ctx);
	if (!NT_STATUS_IS_OK(nt_status)) {
		DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status)));
		/*
		 * We keep the server_credentials as anonymous
		 * this is required for the spoolss.notify test
		 */
	}

	req->smb_conn->negotiate.server_credentials = talloc_steal(req->smb_conn, server_credentials);

	nt_status = samba_server_gensec_start(req,
					      req->smb_conn->connection->event.ctx,
					      req->smb_conn->connection->msg_ctx,
					      req->smb_conn->lp_ctx,
					      server_credentials,
					      "cifs",
					      &gensec_security);
	if (!NT_STATUS_IS_OK(nt_status)) {
		DEBUG(0, ("Failed to start GENSEC: %s\n", nt_errstr(nt_status)));
		smbsrv_terminate_connection(req->smb_conn, "Failed to start GENSEC\n");
		return nt_status;
	}

	gensec_set_target_service(gensec_security, "cifs");

	gensec_set_credentials(gensec_security, server_credentials);

	nt_status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_SPNEGO);
	if (!NT_STATUS_IS_OK(nt_status)) {
		DEBUG(0, ("Failed to start SPNEGO: %s\n", nt_errstr(nt_status)));
		smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO\n");
		return nt_status;
	}

	nt_status = gensec_update_ev(gensec_security, req, req->smb_conn->connection->event.ctx, null_data_blob, &blob);
	if (!NT_STATUS_IS_OK(nt_status) && !NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
		DEBUG(0, ("Failed to get SPNEGO to give us the first token: %s\n", nt_errstr(nt_status)));
		smbsrv_terminate_connection(req->smb_conn, "Failed to start SPNEGO - no first token\n");
		return nt_status;
	}

	*_blob = blob;
	return NT_STATUS_OK;
}
Beispiel #2
0
/*
  setup a chained reply in req->out with the given word count and initial data buffer size. 
*/
static void req_setup_chain_reply(struct smbsrv_request *req, unsigned int wct, unsigned int buflen)
{
	uint32_t chain_base_size = req->out.size;

	/* we need room for the wct value, the words, the buffer length and the buffer */
	req->out.size += 1 + VWV(wct) + 2 + buflen;

	/* over allocate by a small amount */
	req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 

	req->out.buffer = talloc_realloc(req, req->out.buffer, 
					 uint8_t, req->out.allocated);
	if (!req->out.buffer) {
		smbsrv_terminate_connection(req->smb_conn, "allocation failed");
		return;
	}

	req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
	req->out.vwv = req->out.buffer + chain_base_size + 1;
	req->out.wct = wct;
	req->out.data = req->out.vwv + VWV(wct) + 2;
	req->out.data_size = buflen;
	req->out.ptr = req->out.data;

	SCVAL(req->out.buffer, chain_base_size, wct);
	SSVAL(req->out.vwv, VWV(wct), buflen);
}
Beispiel #3
0
void smb2srv_send_error(struct smb2srv_request *req, NTSTATUS error)
{
	NTSTATUS status;

	if (req->smb_conn->connection->event.fde == NULL) {
		/* the socket has been destroyed - no point trying to send an error! */
		talloc_free(req);
		return;
	}

	status = smb2srv_setup_reply(req, 8, true, 0);
	if (!NT_STATUS_IS_OK(status)) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
		talloc_free(req);
		return;
	}

	SIVAL(req->out.hdr, SMB2_HDR_STATUS, NT_STATUS_V(error));

	SSVAL(req->out.body, 0x02, 0);
	SIVAL(req->out.body, 0x04, 0);

	req->chain_status = NT_STATUS_INVALID_PARAMETER;

	smb2srv_send_reply(req);
}
Beispiel #4
0
void smb2srv_negprot_recv(struct smb2srv_request *req)
{
	struct smb2_negprot *io;

	if (req->in.body_size < 0x26) {
		smb2srv_send_error(req,  NT_STATUS_FOOBAR);
		return;
	}

	io = talloc(req, struct smb2_negprot);
	if (!io) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
		talloc_free(req);
		return;
	}

	io->in.unknown1	= SVAL(req->in.body, 0x02);
	memcpy(io->in.unknown2, req->in.body + 0x04, 0x20);
	io->in.unknown3 = SVAL(req->in.body, 0x24);

	req->status = smb2srv_negprot_backend(req, io);

	if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
		talloc_free(req);
		return;
	}
	smb2srv_negprot_send(req, io);
}
Beispiel #5
0
void smb2srv_negprot_recv(struct smb2srv_request *req)
{
	struct smb2_negprot *io;
	int i;

	if (req->in.body_size < 0x26) {
		smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");
		return;
	}

	io = talloc(req, struct smb2_negprot);
	if (!io) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
		talloc_free(req);
		return;
	}

	io->in.dialect_count = SVAL(req->in.body, 0x02);
	io->in.security_mode = SVAL(req->in.body, 0x04);
	io->in.reserved      = SVAL(req->in.body, 0x06);
	io->in.capabilities  = IVAL(req->in.body, 0x08);
	req->status = smbcli_pull_guid(req->in.body, 0xC, &io->in.client_guid);
	if (!NT_STATUS_IS_OK(req->status)) {
		smbsrv_terminate_connection(req->smb_conn, "Bad GUID in SMB2 negprot");
		talloc_free(req);
		return;
	}
	io->in.start_time = smbcli_pull_nttime(req->in.body, 0x1C);

	io->in.dialects = talloc_array(req, uint16_t, io->in.dialect_count);
	if (io->in.dialects == NULL) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
		talloc_free(req);
		return;
	}
	for (i=0;i<io->in.dialect_count;i++) {
		io->in.dialects[i] = SVAL(req->in.body, 0x24+i*2);
	}

	req->status = smb2srv_negprot_backend(req, io);

	if (req->control_flags & SMB2SRV_REQ_CTRL_FLAG_NOT_REPLY) {
		talloc_free(req);
		return;
	}
	smb2srv_negprot_send(req, io);
}
Beispiel #6
0
static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negprot *io)
{
	NTSTATUS status;

	if (NT_STATUS_IS_ERR(req->status)) {
		smb2srv_send_error(req, req->status); /* TODO: is this correct? */
		return;
	}

	status = smb2srv_setup_reply(req, 0x40, true, io->out.secblob.length);
	if (!NT_STATUS_IS_OK(status)) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
		talloc_free(req);
		return;
	}

	SSVAL(req->out.body, 0x02, io->out.security_mode);
	SIVAL(req->out.body, 0x04, io->out.dialect_revision);
	SIVAL(req->out.body, 0x06, io->out.reserved);
	status = smbcli_push_guid(req->out.body, 0x08, &io->out.server_guid);
	if (!NT_STATUS_IS_OK(status)) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
		talloc_free(req);
		return;
	}
	SIVAL(req->out.body, 0x18, io->out.capabilities);
	SIVAL(req->out.body, 0x1C, io->out.max_transact_size);
	SIVAL(req->out.body, 0x20, io->out.max_read_size);
	SIVAL(req->out.body, 0x24, io->out.max_write_size);
	push_nttime(req->out.body, 0x28, io->out.system_time);
	push_nttime(req->out.body, 0x30, io->out.server_start_time);
	SIVAL(req->out.body, 0x3C, io->out.reserved2);
	status = smb2_push_o16s16_blob(&req->out, 0x38, io->out.secblob);
	if (!NT_STATUS_IS_OK(status)) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
		talloc_free(req);
		return;
	}

	smb2srv_send_reply(req);
}
Beispiel #7
0
void smb2srv_send_reply(struct smb2srv_request *req)
{
	DATA_BLOB blob;
	NTSTATUS status;

	if (req->smb_conn->connection->event.fde == NULL) {
		/* the socket has been destroyed - no point trying to send a reply! */
		talloc_free(req);
		return;
	}

	if (req->out.size > NBT_HDR_SIZE) {
		_smb_setlen_tcp(req->out.buffer, req->out.size - NBT_HDR_SIZE);
	}

	/* if signing is active on the session then sign the packet */
	if (req->is_signed) {
		status = smb2_sign_message(&req->out, 
					   req->session->session_info->session_key);
		if (!NT_STATUS_IS_OK(status)) {
			smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
			return;
		}		
	}


	blob = data_blob_const(req->out.buffer, req->out.size);
	status = packet_send(req->smb_conn->packet, blob);
	if (!NT_STATUS_IS_OK(status)) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
		return;
	}
	if (req->chain_offset) {
		smb2srv_chain_reply(req);
		return;
	}
	talloc_free(req);
}
Beispiel #8
0
/*
 * reply to a SMB negprot request with dialect "SMB 2.002"
 */
void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
{
	struct smb2srv_request *req;
	uint32_t body_fixed_size = 0x26;

	req = talloc_zero(smb_req->smb_conn, struct smb2srv_request);
	if (!req) goto nomem;
	req->smb_conn		= smb_req->smb_conn;
	req->request_time	= smb_req->request_time;
	talloc_steal(req, smb_req);

	req->in.size      = NBT_HDR_SIZE+SMB2_HDR_BODY+body_fixed_size;
	req->in.allocated = req->in.size;
	req->in.buffer    = talloc_array(req, uint8_t, req->in.allocated);
	if (!req->in.buffer) goto nomem;
	req->in.hdr       = req->in.buffer + NBT_HDR_SIZE;
	req->in.body      = req->in.hdr + SMB2_HDR_BODY;
	req->in.body_size = body_fixed_size;
	req->in.dynamic   = NULL;

	smb2srv_setup_bufinfo(req);

	SIVAL(req->in.hdr, 0,				SMB2_MAGIC);
	SSVAL(req->in.hdr, SMB2_HDR_LENGTH,		SMB2_HDR_BODY);
	SSVAL(req->in.hdr, SMB2_HDR_EPOCH,		0);
	SIVAL(req->in.hdr, SMB2_HDR_STATUS,		0);
	SSVAL(req->in.hdr, SMB2_HDR_OPCODE,		SMB2_OP_NEGPROT);
	SSVAL(req->in.hdr, SMB2_HDR_CREDIT,		0);
	SIVAL(req->in.hdr, SMB2_HDR_FLAGS,		0);
	SIVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND,	0);
	SBVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID,		0);
	SIVAL(req->in.hdr, SMB2_HDR_PID,		0);
	SIVAL(req->in.hdr, SMB2_HDR_TID,		0);
	SBVAL(req->in.hdr, SMB2_HDR_SESSION_ID,		0);
	memset(req->in.hdr+SMB2_HDR_SIGNATURE, 0, 16);

	/* this seems to be a bug, they use 0x24 but the length is 0x26 */
	SSVAL(req->in.body, 0x00, 0x24);

	SSVAL(req->in.body, 0x02, 1);
	memset(req->in.body+0x04, 0, 32);
	SSVAL(req->in.body, 0x24, SMB2_DIALECT_REVISION_202);

	smb2srv_negprot_recv(req);
	return;
nomem:
	smbsrv_terminate_connection(smb_req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
	talloc_free(req);
	return;
}
Beispiel #9
0
static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negprot *io)
{
	NTSTATUS status;

	if (NT_STATUS_IS_ERR(req->status)) {
		smb2srv_send_error(req, req->status); /* TODO: is this correct? */
		return;
	}

	status = smb2srv_setup_reply(req, 0x40, True, io->out.secblob.length);
	if (!NT_STATUS_IS_OK(status)) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
		talloc_free(req);
		return;
	}

	SSVAL(req->out.body, 0x02, io->out._pad);
	SIVAL(req->out.body, 0x04, io->out.unknown2);
	memcpy(req->out.body+0x08, io->out.sessid, 16);
	SIVAL(req->out.body, 0x18, io->out.unknown3);
	SSVAL(req->out.body, 0x1C, io->out.unknown4);
	SIVAL(req->out.body, 0x1E, io->out.unknown5);
	SIVAL(req->out.body, 0x22, io->out.unknown6);
	SSVAL(req->out.body, 0x26, io->out.unknown7);
	push_nttime(req->out.body, 0x28, io->out.current_time);
	push_nttime(req->out.body, 0x30, io->out.boot_time);
	status = smb2_push_o16s16_blob(&req->out, 0x38, io->out.secblob);
	if (!NT_STATUS_IS_OK(status)) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
		talloc_free(req);
		return;
	}

	SIVAL(req->out.body, 0x3C, io->out.unknown9);

	smb2srv_send_reply(req);
}
Beispiel #10
0
/*
 * reply to a SMB negprot request with dialect "SMB 2.001"
 */
void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
{
	struct smb2srv_request *req;
	uint32_t body_fixed_size = 0x26;

	/* create a fake SMB2 negprot request */
	req = talloc_zero(smb_req->smb_conn, struct smb2srv_request);
	if (!req) goto nomem;
	req->smb_conn		= smb_req->smb_conn;
	req->request_time	= smb_req->request_time;
	talloc_steal(req, smb_req);

	req->in.size      = NBT_HDR_SIZE+SMB2_HDR_BODY+body_fixed_size;
	req->in.allocated = req->in.size;
	req->in.buffer    = talloc_size(req, req->in.allocated);
	if (!req->in.buffer) goto nomem;
	req->in.hdr       = req->in.buffer + NBT_HDR_SIZE;
	req->in.body      = req->in.hdr + SMB2_HDR_BODY;
	req->in.body_size = body_fixed_size;
	req->in.dynamic   = NULL;

	SIVAL(req->in.hdr, 0,				SMB2_MAGIC);
	SSVAL(req->in.hdr, SMB2_HDR_LENGTH,		SMB2_HDR_BODY);
	SSVAL(req->in.hdr, SMB2_HDR_PAD1,		0);
	SIVAL(req->in.hdr, SMB2_HDR_STATUS,		0);
	SSVAL(req->in.hdr, SMB2_HDR_OPCODE,		SMB2_OP_NEGPROT);
	SSVAL(req->in.hdr, SMB2_HDR_UNKNOWN1,		0);
	SIVAL(req->in.hdr, SMB2_HDR_FLAGS,		0);
	SIVAL(req->in.hdr, SMB2_HDR_CHAIN_OFFSET,	0);
	SBVAL(req->in.hdr, SMB2_HDR_SEQNUM,		0);
	SIVAL(req->in.hdr, SMB2_HDR_PID,		0);
	SIVAL(req->in.hdr, SMB2_HDR_TID,		0);
	SBVAL(req->in.hdr, SMB2_HDR_UID,		0);
	memset(req->in.hdr+SMB2_HDR_SIG, 0, 16);

	/* this seems to be a bug, they use 0x24 but the length is 0x26 */
	SSVAL(req->in.body, 0x00, 0x24);

	SSVAL(req->in.body, 0x02, 1);
	memset(req->in.body+0x04, 0, 32);
	SSVAL(req->in.body, 0x24, 0);

	smb2srv_negprot_recv(req);
	return;
nomem:
	smbsrv_terminate_connection(smb_req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
	talloc_free(req);
	return;
}
Beispiel #11
0
static void smb2srv_keepalive_send(struct smb2srv_request *req)
{
	NTSTATUS status;

	if (NT_STATUS_IS_ERR(req->status)) {
		smb2srv_send_error(req, req->status);
		return;
	}

	status = smb2srv_setup_reply(req, 0x04, false, 0);
	if (!NT_STATUS_IS_OK(status)) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
		talloc_free(req);
		return;
	}

	SSVAL(req->out.body, 0x02, 0);

	smb2srv_send_reply(req);
}
Beispiel #12
0
/*
  send a reply and destroy the request buffer

  note that this only looks at req->out.buffer and req->out.size, allowing manually 
  constructed packets to be sent
*/
void smbsrv_send_reply_nosign(struct smbsrv_request *req)
{
	DATA_BLOB blob;
	NTSTATUS status;

	if (req->smb_conn->connection->event.fde == NULL) {
		/* we are in the process of shutting down this connection */
		talloc_free(req);
		return;
	}

	if (req->out.size > NBT_HDR_SIZE) {
		_smb_setlen_nbt(req->out.buffer, req->out.size - NBT_HDR_SIZE);
	}

	blob = data_blob_const(req->out.buffer, req->out.size);
	status = packet_send(req->smb_conn->packet, blob);
	if (!NT_STATUS_IS_OK(status)) {
		smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
	}
	talloc_free(req);
}
Beispiel #13
0
NTSTATUS smbsrv_recv_smb2_request(void *private_data, DATA_BLOB blob)
{
	struct smbsrv_connection *smb_conn = talloc_get_type(private_data, struct smbsrv_connection);
	struct smb2srv_request *req;
	struct timeval cur_time = timeval_current();
	uint32_t protocol_version;
	uint16_t buffer_code;
	uint32_t dynamic_size;
	uint32_t flags;

	smb_conn->statistics.last_request_time = cur_time;

	/* see if its a special NBT packet */
	if (CVAL(blob.data,0) != 0) {
		DEBUG(2,("Special NBT packet on SMB2 connection"));
		smbsrv_terminate_connection(smb_conn, "Special NBT packet on SMB2 connection");
		return NT_STATUS_OK;
	}

	if (blob.length < (NBT_HDR_SIZE + SMB2_MIN_SIZE_NO_BODY)) {
		DEBUG(2,("Invalid SMB2 packet length count %ld\n", (long)blob.length));
		smbsrv_terminate_connection(smb_conn, "Invalid SMB2 packet");
		return NT_STATUS_OK;
	}

	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));
		smbsrv_terminate_connection(smb_conn, "NON-SMB2 packet");
		return NT_STATUS_OK;
	}

	req = smb2srv_init_request(smb_conn);
	NT_STATUS_HAVE_NO_MEMORY(req);

	req->in.buffer		= talloc_steal(req, blob.data);
	req->in.size		= blob.length;
	req->request_time	= cur_time;
	req->in.allocated	= req->in.size;

	req->in.hdr		= req->in.buffer+ NBT_HDR_SIZE;
	req->in.body		= req->in.hdr	+ SMB2_HDR_BODY;
	req->in.body_size	= req->in.size	- (SMB2_HDR_BODY+NBT_HDR_SIZE);
	req->in.dynamic 	= NULL;

	req->seqnum		= BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);

	if (req->in.body_size < 2) {
		/* error handling for this is different for negprot to 
		   other packet types */
		uint16_t opcode	= SVAL(req->in.hdr, SMB2_HDR_OPCODE);
		if (opcode == SMB2_OP_NEGPROT) {
			smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");			
			return NT_STATUS_OK;
		} else {
			smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
			return NT_STATUS_OK;
		}
	}

	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 request invalid dynamic size 0x%x\n", 
				 dynamic_size));
			smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
			return NT_STATUS_OK;
		}
	}

	smb2srv_setup_bufinfo(req);

	/* 
	 * TODO: - make sure the length field is 64
	 *       - make sure it's a request
	 */

	flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
	/* the first request should never have the related flag set */
	if (flags & SMB2_HDR_FLAG_CHAINED) {
		req->chain_status = NT_STATUS_INVALID_PARAMETER;
	}

	return smb2srv_reply(req);
}
Beispiel #14
0
static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
{
	uint16_t opcode;
	uint32_t tid;
	uint64_t uid;
	uint32_t flags;

	if (SVAL(req->in.hdr, SMB2_HDR_LENGTH) != SMB2_HDR_BODY) {
		smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 header length");
		return NT_STATUS_INVALID_PARAMETER;
	}
	opcode			= SVAL(req->in.hdr, SMB2_HDR_OPCODE);
	req->chain_offset	= IVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND);
	req->seqnum		= BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);
	tid			= IVAL(req->in.hdr, SMB2_HDR_TID);
	uid			= BVAL(req->in.hdr, SMB2_HDR_SESSION_ID);
	flags			= IVAL(req->in.hdr, SMB2_HDR_FLAGS);

	if (opcode != SMB2_OP_CANCEL &&
	    req->smb_conn->highest_smb2_seqnum != 0 &&
	    req->seqnum <= req->smb_conn->highest_smb2_seqnum) {
		smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 sequence number");
		return NT_STATUS_INVALID_PARAMETER;
	}
	if (opcode != SMB2_OP_CANCEL) {
		req->smb_conn->highest_smb2_seqnum = req->seqnum;
	}

	if (flags & SMB2_HDR_FLAG_CHAINED) {
		uid = req->chained_session_id;
		tid = req->chained_tree_id;
	}

	req->session	= smbsrv_session_find(req->smb_conn, uid, req->request_time);
	req->tcon	= smbsrv_smb2_tcon_find(req->session, tid, req->request_time);

	req->chained_session_id = uid;
	req->chained_tree_id = tid;

	errno = 0;

	/* supporting signing is mandatory in SMB2, and is per-packet. So we 
	   should check the signature on any incoming packet that is signed, and 
	   should give a signed reply to any signed request */
	if (flags & SMB2_HDR_FLAG_SIGNED) {
		NTSTATUS status;

		if (!req->session) goto nosession;

		req->is_signed = true;
		status = smb2_check_signature(&req->in, 
					      req->session->session_info->session_key);
		if (!NT_STATUS_IS_OK(status)) {
			smb2srv_send_error(req, status);
			return NT_STATUS_OK;			
		}
	} else if (req->session && req->session->smb2_signing.active) {
		/* we require signing and this request was not signed */
		smb2srv_send_error(req, NT_STATUS_ACCESS_DENIED);
		return NT_STATUS_OK;					
	}

	if (!NT_STATUS_IS_OK(req->chain_status)) {
		smb2srv_send_error(req, req->chain_status);
		return NT_STATUS_OK;
	}

	switch (opcode) {
	case SMB2_OP_NEGPROT:
		smb2srv_negprot_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_SESSSETUP:
		smb2srv_sesssetup_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_LOGOFF:
		if (!req->session) goto nosession;
		smb2srv_logoff_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_TCON:
		if (!req->session) goto nosession;
		smb2srv_tcon_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_TDIS:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_tdis_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_CREATE:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_create_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_CLOSE:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_close_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_FLUSH:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_flush_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_READ:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_read_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_WRITE:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_write_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_LOCK:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_lock_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_IOCTL:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_ioctl_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_CANCEL:
		smb2srv_cancel_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_KEEPALIVE:
		smb2srv_keepalive_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_FIND:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_find_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_NOTIFY:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_notify_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_GETINFO:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_getinfo_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_SETINFO:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_setinfo_recv(req);
		return NT_STATUS_OK;
	case SMB2_OP_BREAK:
		if (!req->session) goto nosession;
		if (!req->tcon)	goto notcon;
		smb2srv_break_recv(req);
		return NT_STATUS_OK;
	}

	DEBUG(1,("Invalid SMB2 opcode: 0x%04X\n", opcode));
	smbsrv_terminate_connection(req->smb_conn, "Invalid SMB2 opcode");
	return NT_STATUS_OK;

nosession:
	smb2srv_send_error(req, NT_STATUS_USER_SESSION_DELETED);
	return NT_STATUS_OK;
notcon:
	smb2srv_send_error(req, NT_STATUS_NETWORK_NAME_DELETED);
	return NT_STATUS_OK;
}
Beispiel #15
0
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;
	uint32_t flags;
	uint32_t last_hdr_offset;

	last_hdr_offset = p_req->in.hdr - p_req->in.buffer;

	chain_offset = p_req->chain_offset;
	p_req->chain_offset = 0;

	if (p_req->in.size < (last_hdr_offset + chain_offset + SMB2_MIN_SIZE_NO_BODY)) {
		DEBUG(2,("Invalid SMB2 chained packet at offset 0x%X from last hdr 0x%X\n",
			chain_offset, last_hdr_offset));
		smbsrv_terminate_connection(p_req->smb_conn, "Invalid SMB2 chained packet");
		return;
	}

	protocol_version = IVAL(p_req->in.buffer, last_hdr_offset + 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+ last_hdr_offset + chain_offset;
	req->in.body		= req->in.hdr	+ SMB2_HDR_BODY;
	req->in.body_size	= req->in.size	- (last_hdr_offset+ chain_offset + SMB2_HDR_BODY);
	req->in.dynamic 	= NULL;

	req->seqnum		= BVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID);

	if (req->in.body_size < 2) {
		/* error handling for this is different for negprot to 
		   other packet types */
		uint16_t opcode	= SVAL(req->in.hdr, SMB2_HDR_OPCODE);
		if (opcode == SMB2_OP_NEGPROT) {
			smbsrv_terminate_connection(req->smb_conn, "Bad body size in SMB2 negprot");			
		} else {
			smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER);
		}
	}

	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;
		}
	}

	smb2srv_setup_bufinfo(req);

	flags = IVAL(req->in.hdr, SMB2_HDR_FLAGS);
	if (flags & SMB2_HDR_FLAG_CHAINED) {
		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;
		}
		req->chained_session_id = p_req->chained_session_id;
		req->chained_tree_id = p_req->chained_tree_id;
		req->chain_status = p_req->chain_status;
	}

	/* 
	 * 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;
	}
}
Beispiel #16
0
/*
  setup a reply in req->out with the given word count and initial data buffer size. 
  the caller will then fill in the command words and data before calling req_send_reply() to 
  send the reply on its way
*/
void smbsrv_setup_reply(struct smbsrv_request *req, unsigned int wct, size_t buflen)
{
	uint16_t flags2;

	if (req->chain_count != 0) {
		req_setup_chain_reply(req, wct, buflen);
		return;
	}

	req->out.size = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + buflen;

	/* over allocate by a small amount */
	req->out.allocated = req->out.size + REQ_OVER_ALLOCATION; 

	req->out.buffer = talloc_size(req, req->out.allocated);
	if (!req->out.buffer) {
		smbsrv_terminate_connection(req->smb_conn, "allocation failed");
		return;
	}

	flags2 = FLAGS2_LONG_PATH_COMPONENTS | 
		FLAGS2_EXTENDED_ATTRIBUTES | 
		FLAGS2_IS_LONG_NAME;
#define _SMB_FLAGS2_ECHOED_FLAGS ( \
	FLAGS2_UNICODE_STRINGS | \
	FLAGS2_EXTENDED_SECURITY | \
	FLAGS2_SMB_SECURITY_SIGNATURES \
)
	flags2 |= (req->flags2 & _SMB_FLAGS2_ECHOED_FLAGS);
	if (req->smb_conn->negotiate.client_caps & CAP_STATUS32) {
		flags2 |= FLAGS2_32_BIT_ERROR_CODES;
	}

	req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
	req->out.vwv = req->out.hdr + HDR_VWV;
	req->out.wct = wct;
	req->out.data = req->out.vwv + VWV(wct) + 2;
	req->out.data_size = buflen;
	req->out.ptr = req->out.data;

	SIVAL(req->out.hdr, HDR_RCLS, 0);

	SCVAL(req->out.hdr, HDR_WCT, wct);
	SSVAL(req->out.vwv, VWV(wct), buflen);

	memcpy(req->out.hdr, "\377SMB", 4);
	SCVAL(req->out.hdr,HDR_FLG, FLAG_REPLY | FLAG_CASELESS_PATHNAMES); 
	SSVAL(req->out.hdr,HDR_FLG2, flags2);
	SSVAL(req->out.hdr,HDR_PIDHIGH,0);
	memset(req->out.hdr + HDR_SS_FIELD, 0, 10);

	if (req->in.hdr) {
		/* copy the cmd, tid, pid, uid and mid from the request */
		SCVAL(req->out.hdr,HDR_COM,CVAL(req->in.hdr,HDR_COM));	
		SSVAL(req->out.hdr,HDR_TID,SVAL(req->in.hdr,HDR_TID));
		SSVAL(req->out.hdr,HDR_PID,SVAL(req->in.hdr,HDR_PID));
		SSVAL(req->out.hdr,HDR_UID,SVAL(req->in.hdr,HDR_UID));
		SSVAL(req->out.hdr,HDR_MID,SVAL(req->in.hdr,HDR_MID));
	} else {
		SCVAL(req->out.hdr,HDR_COM,0);
		SSVAL(req->out.hdr,HDR_TID,0);
		SSVAL(req->out.hdr,HDR_PID,0);
		SSVAL(req->out.hdr,HDR_UID,0);
		SSVAL(req->out.hdr,HDR_MID,0);
	}
}