*/
#include "includes.h"
+#include "smbd/smbd.h"
#include "smbd/globals.h"
#include "../libcli/smb/smb_common.h"
#include "../lib/tsocket/tsocket.h"
+#include "smbprofile.h"
#define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
}
sconn->smb2.sessions.limit = 0x0000FFFE;
sconn->smb2.sessions.list = NULL;
+ sconn->smb2.seqnum_low = 0;
+ sconn->smb2.credits_granted = 0;
+ sconn->smb2.max_credits = lp_smb2_max_credits();
+ sconn->smb2.credits_bitmap = bitmap_talloc(sconn,
+ DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR*sconn->smb2.max_credits);
+ if (sconn->smb2.credits_bitmap == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
- ret = tstream_bsd_existing_socket(sconn, smbd_server_fd(),
+ ret = tstream_bsd_existing_socket(sconn, sconn->sock,
&sconn->smb2.stream);
if (ret == -1) {
status = map_nt_error_from_unix(errno);
}
/* Ensure child is set to non-blocking mode */
- set_blocking(smbd_server_fd(),false);
+ set_blocking(sconn->sock, false);
return NT_STATUS_OK;
}
return NT_STATUS_OK;
}
-static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req,
- uint16_t *p_creds_requested)
+static bool smb2_validate_message_id(struct smbd_server_connection *sconn,
+ const uint8_t *inhdr)
+{
+ uint64_t message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
+ struct bitmap *credits_bm = sconn->smb2.credits_bitmap;
+ uint16_t opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
+ unsigned int bitmap_offset;
+
+ if (opcode == SMB2_OP_CANCEL) {
+ /* SMB2_CANCEL requests by definition resend messageids. */
+ return true;
+ }
+
+ if (message_id < sconn->smb2.seqnum_low ||
+ message_id > (sconn->smb2.seqnum_low +
+ (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR))) {
+ DEBUG(0,("smb2_validate_message_id: bad message_id "
+ "%llu (low = %llu, max = %lu)\n",
+ (unsigned long long)message_id,
+ (unsigned long long)sconn->smb2.seqnum_low,
+ (unsigned long)sconn->smb2.max_credits ));
+ return false;
+ }
+
+ /* client just used a credit. */
+ SMB_ASSERT(sconn->smb2.credits_granted > 0);
+ sconn->smb2.credits_granted -= 1;
+
+ /* Mark the message_id as seen in the bitmap. */
+ bitmap_offset = (unsigned int)(message_id %
+ (uint64_t)(sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR));
+ if (bitmap_query(credits_bm, bitmap_offset)) {
+ DEBUG(0,("smb2_validate_message_id: duplicate message_id "
+ "%llu (bm offset %u)\n",
+ (unsigned long long)message_id,
+ bitmap_offset));
+ return false;
+ }
+ bitmap_set(credits_bm, bitmap_offset);
+
+ if (message_id == sconn->smb2.seqnum_low + 1) {
+ /* Move the window forward by all the message_id's
+ already seen. */
+ while (bitmap_query(credits_bm, bitmap_offset)) {
+ DEBUG(10,("smb2_validate_message_id: clearing "
+ "id %llu (position %u) from bitmap\n",
+ (unsigned long long)(sconn->smb2.seqnum_low + 1),
+ bitmap_offset ));
+ bitmap_clear(credits_bm, bitmap_offset);
+ sconn->smb2.seqnum_low += 1;
+ bitmap_offset = (bitmap_offset + 1) %
+ (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR);
+ }
+ }
+
+ return true;
+}
+
+static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
{
int count;
int idx;
bool compound_related = false;
- *p_creds_requested = 0;
count = req->in.vector_count;
if (count < 4) {
}
for (idx=1; idx < count; idx += 3) {
- uint16_t creds_requested = 0;
const uint8_t *inhdr = NULL;
uint32_t flags;
inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
- /* setup the SMB2 header */
+ /* Check the SMB2 header */
if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
return NT_STATUS_INVALID_PARAMETER;
}
- creds_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
- if (*p_creds_requested + creds_requested < creds_requested) {
- *p_creds_requested = 65535;
- } else {
- *p_creds_requested += creds_requested;
+ if (!smb2_validate_message_id(req->sconn, inhdr)) {
+ return NT_STATUS_INVALID_PARAMETER;
}
flags = IVAL(inhdr, SMB2_HDR_FLAGS);
return NT_STATUS_OK;
}
-static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req, uint16_t creds)
+static void smb2_set_operation_credit(struct smbd_server_connection *sconn,
+ const struct iovec *in_vector,
+ struct iovec *out_vector)
+{
+ uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
+ uint16_t credits_requested = 0;
+ uint16_t credits_granted = 0;
+
+ if (in_vector != NULL) {
+ const uint8_t *inhdr = (const uint8_t *)in_vector->iov_base;
+ credits_requested = SVAL(inhdr, SMB2_HDR_CREDIT);
+ }
+
+ SMB_ASSERT(sconn->smb2.max_credits >= sconn->smb2.credits_granted);
+
+ /* Remember what we gave out. */
+ credits_granted = MIN(credits_requested, (sconn->smb2.max_credits -
+ sconn->smb2.credits_granted));
+
+ if (credits_granted == 0 && sconn->smb2.credits_granted == 0) {
+ /* First negprot packet, or ensure the client credits can
+ never drop to zero. */
+ credits_granted = 1;
+ }
+
+ SSVAL(outhdr, SMB2_HDR_CREDIT, credits_granted);
+ sconn->smb2.credits_granted += credits_granted;
+
+ DEBUG(10,("smb2_set_operation_credit: requested %u, "
+ "granted %u, total granted %u\n",
+ (unsigned int)credits_requested,
+ (unsigned int)credits_granted,
+ (unsigned int)sconn->smb2.credits_granted ));
+}
+
+static void smb2_calculate_credits(const struct smbd_smb2_request *inreq,
+ struct smbd_smb2_request *outreq)
+{
+ int count, idx;
+
+ count = outreq->out.vector_count;
+
+ for (idx=1; idx < count; idx += 3) {
+ smb2_set_operation_credit(outreq->sconn,
+ &inreq->in.vector[idx],
+ &outreq->out.vector[idx]);
+ }
+}
+
+static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
{
struct iovec *vector;
int count;
NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
SSVAL(outhdr, SMB2_HDR_OPCODE,
SVAL(inhdr, SMB2_HDR_OPCODE));
- SSVAL(outhdr, SMB2_HDR_CREDIT, creds);
-
- /* Remember what we gave out. */
- req->sconn->smb2.credits_granted += creds;
-
SIVAL(outhdr, SMB2_HDR_FLAGS,
IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
exit_server_cleanly(reason);
}
-static bool dup_smb2_vec(struct iovec *dstvec,
- const struct iovec *srcvec,
- int offset)
+static bool dup_smb2_vec3(TALLOC_CTX *ctx,
+ struct iovec *outvec,
+ const struct iovec *srcvec)
{
+ /* vec[0] is always boilerplate and must
+ * be allocated with size OUTVEC_ALLOC_SIZE. */
- if (srcvec[offset].iov_len &&
- srcvec[offset].iov_base) {
- dstvec[offset].iov_base = talloc_memdup(dstvec,
- srcvec[offset].iov_base,
- srcvec[offset].iov_len);
- if (!dstvec[offset].iov_base) {
+ outvec[0].iov_base = talloc_memdup(ctx,
+ srcvec[0].iov_base,
+ OUTVEC_ALLOC_SIZE);
+ if (!outvec[0].iov_base) {
+ return false;
+ }
+ outvec[0].iov_len = SMB2_HDR_BODY;
+
+ /*
+ * If this is a "standard" vec[1] of length 8,
+ * pointing to srcvec[0].iov_base + SMB2_HDR_BODY,
+ * then duplicate this. Else use talloc_memdup().
+ */
+
+ if (srcvec[1].iov_len == 8 &&
+ srcvec[1].iov_base ==
+ ((uint8_t *)srcvec[0].iov_base) +
+ SMB2_HDR_BODY) {
+ outvec[1].iov_base = ((uint8_t *)outvec[1].iov_base) +
+ SMB2_HDR_BODY;
+ outvec[1].iov_len = 8;
+ } else {
+ outvec[1].iov_base = talloc_memdup(ctx,
+ srcvec[1].iov_base,
+ srcvec[1].iov_len);
+ if (!outvec[1].iov_base) {
return false;
}
- dstvec[offset].iov_len = srcvec[offset].iov_len;
+ outvec[1].iov_len = srcvec[1].iov_len;
+ }
+
+ /*
+ * If this is a "standard" vec[2] of length 1,
+ * pointing to srcvec[0].iov_base + (OUTVEC_ALLOC_SIZE - 1)
+ * then duplicate this. Else use talloc_memdup().
+ */
+
+ if (srcvec[2].iov_base &&
+ srcvec[2].iov_len) {
+ if (srcvec[2].iov_base ==
+ ((uint8_t *)srcvec[0].iov_base) +
+ (OUTVEC_ALLOC_SIZE - 1) &&
+ srcvec[2].iov_len == 1) {
+ /* Common SMB2 error packet case. */
+ outvec[2].iov_base = ((uint8_t *)outvec[0].iov_base) +
+ (OUTVEC_ALLOC_SIZE - 1);
+ } else {
+ outvec[2].iov_base = talloc_memdup(ctx,
+ srcvec[2].iov_base,
+ srcvec[2].iov_len);
+ if (!outvec[2].iov_base) {
+ return false;
+ }
+ }
+ outvec[2].iov_len = srcvec[2].iov_len;
} else {
- dstvec[offset].iov_base = NULL;
- dstvec[offset].iov_len = 0;
+ outvec[2].iov_base = NULL;
+ outvec[2].iov_len = 0;
}
return true;
}
outvec[0].iov_len = 4;
memcpy(newreq->out.nbt_hdr, req->out.nbt_hdr, 4);
+ /* Setup the vectors identically to the ones in req. */
for (i = 1; i < count; i += 3) {
- /* i + 0 and i + 1 are always
- * boilerplate. */
- outvec[i].iov_base = talloc_memdup(outvec,
- req->out.vector[i].iov_base,
- OUTVEC_ALLOC_SIZE);
- if (!outvec[i].iov_base) {
- break;
- }
- outvec[i].iov_len = SMB2_HDR_BODY;
-
- outvec[i+1].iov_base = ((uint8_t *)outvec[i].iov_base) +
- SMB2_HDR_BODY;
- outvec[i+1].iov_len = 8;
-
- if (req->out.vector[i+2].iov_base ==
- ((uint8_t *)req->out.vector[i].iov_base) +
- (OUTVEC_ALLOC_SIZE - 1) &&
- req->out.vector[i+2].iov_len == 1) {
- /* Common SMB2 error packet case. */
- outvec[i+2].iov_base = ((uint8_t *)outvec[i].iov_base) +
- (OUTVEC_ALLOC_SIZE - 1);
- outvec[i+2].iov_len = 1;
- } else if (!dup_smb2_vec(outvec,
- req->out.vector,
- i)) {
+ if (!dup_smb2_vec3(outvec, &outvec[i], &req->out.vector[i])) {
break;
}
}
/* And end the chain. */
SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, 0);
+ /* Calculate outgoing credits */
+ smb2_calculate_credits(req, nreq);
+
/* Re-sign if needed. */
if (nreq->do_signing) {
NTSTATUS status;
return NT_STATUS_OK;
}
+ req->subreq = subreq;
+ subreq = NULL;
+
if (req->async) {
/* We're already async. */
return NT_STATUS_OK;
* request chain. This is not allowed.
* Cancel the outstanding request.
*/
- tevent_req_cancel(subreq);
+ tevent_req_cancel(req->subreq);
return smbd_smb2_request_error(req,
NT_STATUS_INSUFFICIENT_RESOURCES);
}
- req->subreq = subreq;
- subreq = NULL;
-
if (DEBUGLEVEL >= 10) {
dbgtext("smbd_smb2_request_pending_queue: req->current_idx = %u\n",
(unsigned int)req->current_idx );
SSVAL(hdr, SMB2_HDR_EPOCH, 0);
SIVAL(hdr, SMB2_HDR_STATUS, NT_STATUS_V(STATUS_PENDING));
SSVAL(hdr, SMB2_HDR_OPCODE, SVAL(reqhdr, SMB2_HDR_OPCODE));
- SSVAL(hdr, SMB2_HDR_CREDIT, 5);
-
- req->sconn->smb2.credits_granted += 5;
SIVAL(hdr, SMB2_HDR_FLAGS, flags | SMB2_HDR_FLAG_ASYNC);
SIVAL(hdr, SMB2_HDR_NEXT_COMMAND, 0);
/* Match W2K8R2... */
SCVAL(body, 0x08, 0x21);
+ /* Ensure we correctly go through crediting. Grant
+ the credits now, and zero credits on the final
+ response. */
+ smb2_set_operation_credit(req->sconn,
+ &req->in.vector[i],
+ &state->vector[1]);
+
if (req->do_signing) {
status = smb2_signing_sign_pdu(req->session->session_key,
state->vector, 3);
if (!outvec) {
return NT_STATUS_NO_MEMORY;
}
+
+ /* 0 is always boilerplate and must
+ * be of size 4 for the length field. */
+
outvec[0].iov_base = req->out.nbt_hdr;
outvec[0].iov_len = 4;
SIVAL(req->out.nbt_hdr, 0, 0);
- outvec[1].iov_base = talloc_memdup(outvec,
- req->out.vector[i].iov_base,
- OUTVEC_ALLOC_SIZE);
- if (!outvec[1].iov_base) {
+ if (!dup_smb2_vec3(outvec, &outvec[1], &req->out.vector[i])) {
return NT_STATUS_NO_MEMORY;
}
- outvec[1].iov_len = SMB2_HDR_BODY;
-
- outvec[2].iov_base = ((uint8_t *)outvec[1].iov_base) +
- SMB2_HDR_BODY;
- outvec[2].iov_len = 8;
-
- if (req->out.vector[i+2].iov_base &&
- req->out.vector[i+2].iov_len) {
- if (req->out.vector[i+2].iov_base ==
- ((uint8_t *)req->out.vector[i].iov_base) +
- (OUTVEC_ALLOC_SIZE - 1) &&
- req->out.vector[i].iov_len == 1) {
- /* Common SMB2 error packet case. */
- outvec[3].iov_base = ((uint8_t *)outvec[1].iov_base) +
- (OUTVEC_ALLOC_SIZE - 1);
- } else {
- outvec[3].iov_base = talloc_memdup(outvec,
- req->out.vector[i+2].iov_base,
- req->out.vector[i+2].iov_len);
- if (!outvec[3].iov_base) {
- return NT_STATUS_NO_MEMORY;
- }
- }
- outvec[3].iov_len = req->out.vector[i+2].iov_len;
- } else {
- outvec[3].iov_base = NULL;
- outvec[3].iov_len = 0;
- }
TALLOC_FREE(req->out.vector);
* we don't need the request anymore
* cancel requests never have a response
*/
+ DLIST_REMOVE(req->sconn->smb2.requests, req);
TALLOC_FREE(req);
for (cur = sconn->smb2.requests; cur; cur = cur->next) {
NTSTATUS status;
NTSTATUS session_status;
uint32_t allowed_flags;
+ NTSTATUS return_value;
inhdr = (const uint8_t *)req->in.vector[i].iov_base;
switch (opcode) {
case SMB2_OP_NEGPROT:
- return smbd_smb2_request_process_negprot(req);
+ {
+ START_PROFILE(smb2_negprot);
+ return_value = smbd_smb2_request_process_negprot(req);
+ END_PROFILE(smb2_negprot);
+ }
+ break;
case SMB2_OP_SESSSETUP:
- return smbd_smb2_request_process_sesssetup(req);
+ {
+ START_PROFILE(smb2_sesssetup);
+ return_value = smbd_smb2_request_process_sesssetup(req);
+ END_PROFILE(smb2_sesssetup);
+ }
+ break;
case SMB2_OP_LOGOFF:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
+ }
+
+ {
+ START_PROFILE(smb2_logoff);
+ return_value = smbd_smb2_request_process_logoff(req);
+ END_PROFILE(smb2_logoff);
}
- return smbd_smb2_request_process_logoff(req);
+ break;
case SMB2_OP_TCON:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_session(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
}
- return smbd_smb2_request_process_tcon(req);
+
+ {
+ START_PROFILE(smb2_tcon);
+ return_value = smbd_smb2_request_process_tcon(req);
+ END_PROFILE(smb2_tcon);
+ }
+ break;
case SMB2_OP_TDIS:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
}
- return smbd_smb2_request_process_tdis(req);
+
+ {
+ START_PROFILE(smb2_tdis);
+ return_value = smbd_smb2_request_process_tdis(req);
+ END_PROFILE(smb2_tdis);
+ }
+ break;
case SMB2_OP_CREATE:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
+ }
+
+ {
+ START_PROFILE(smb2_create);
+ return_value = smbd_smb2_request_process_create(req);
+ END_PROFILE(smb2_create);
}
- return smbd_smb2_request_process_create(req);
+ break;
case SMB2_OP_CLOSE:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
+ }
+
+ {
+ START_PROFILE(smb2_close);
+ return_value = smbd_smb2_request_process_close(req);
+ END_PROFILE(smb2_close);
}
- return smbd_smb2_request_process_close(req);
+ break;
case SMB2_OP_FLUSH:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
}
- return smbd_smb2_request_process_flush(req);
+
+ {
+ START_PROFILE(smb2_flush);
+ return_value = smbd_smb2_request_process_flush(req);
+ END_PROFILE(smb2_flush);
+ }
+ break;
case SMB2_OP_READ:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
}
- return smbd_smb2_request_process_read(req);
+
+ {
+ START_PROFILE(smb2_read);
+ return_value = smbd_smb2_request_process_read(req);
+ END_PROFILE(smb2_read);
+ }
+ break;
case SMB2_OP_WRITE:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
}
- return smbd_smb2_request_process_write(req);
+
+ {
+ START_PROFILE(smb2_write);
+ return_value = smbd_smb2_request_process_write(req);
+ END_PROFILE(smb2_write);
+ }
+ break;
case SMB2_OP_LOCK:
if (!NT_STATUS_IS_OK(session_status)) {
if (NT_STATUS_EQUAL(session_status,NT_STATUS_USER_SESSION_DELETED)) {
session_status = NT_STATUS_FILE_CLOSED;
}
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
if (NT_STATUS_EQUAL(status,NT_STATUS_NETWORK_NAME_DELETED)) {
status = NT_STATUS_FILE_CLOSED;
}
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
+ }
+
+ {
+ START_PROFILE(smb2_lock);
+ return_value = smbd_smb2_request_process_lock(req);
+ END_PROFILE(smb2_lock);
}
- return smbd_smb2_request_process_lock(req);
+ break;
case SMB2_OP_IOCTL:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
+ }
+
+ {
+ START_PROFILE(smb2_ioctl);
+ return_value = smbd_smb2_request_process_ioctl(req);
+ END_PROFILE(smb2_ioctl);
}
- return smbd_smb2_request_process_ioctl(req);
+ break;
case SMB2_OP_CANCEL:
- return smbd_smb2_request_process_cancel(req);
+ {
+ START_PROFILE(smb2_cancel);
+ return_value = smbd_smb2_request_process_cancel(req);
+ END_PROFILE(smb2_cancel);
+ }
+ break;
case SMB2_OP_KEEPALIVE:
- return smbd_smb2_request_process_keepalive(req);
+ {START_PROFILE(smb2_keepalive);
+ return_value = smbd_smb2_request_process_keepalive(req);
+ END_PROFILE(smb2_keepalive);}
+ break;
case SMB2_OP_FIND:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
+ }
+
+ {
+ START_PROFILE(smb2_find);
+ return_value = smbd_smb2_request_process_find(req);
+ END_PROFILE(smb2_find);
}
- return smbd_smb2_request_process_find(req);
+ break;
case SMB2_OP_NOTIFY:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
+ }
+
+ {
+ START_PROFILE(smb2_notify);
+ return_value = smbd_smb2_request_process_notify(req);
+ END_PROFILE(smb2_notify);
}
- return smbd_smb2_request_process_notify(req);
+ break;
case SMB2_OP_GETINFO:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
+ }
+
+ {
+ START_PROFILE(smb2_getinfo);
+ return_value = smbd_smb2_request_process_getinfo(req);
+ END_PROFILE(smb2_getinfo);
}
- return smbd_smb2_request_process_getinfo(req);
+ break;
case SMB2_OP_SETINFO:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
+ }
+
+ {
+ START_PROFILE(smb2_setinfo);
+ return_value = smbd_smb2_request_process_setinfo(req);
+ END_PROFILE(smb2_setinfo);
}
- return smbd_smb2_request_process_setinfo(req);
+ break;
case SMB2_OP_BREAK:
if (!NT_STATUS_IS_OK(session_status)) {
- return smbd_smb2_request_error(req, session_status);
+ return_value = smbd_smb2_request_error(req, session_status);
+ break;
}
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
- return smbd_smb2_request_error(req, status);
+ return_value = smbd_smb2_request_error(req, status);
+ break;
}
- return smbd_smb2_request_process_break(req);
- }
- return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+ {
+ START_PROFILE(smb2_break);
+ return_value = smbd_smb2_request_process_break(req);
+ END_PROFILE(smb2_break);
+ }
+ break;
+
+ default:
+ return_value = smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+ break;
+ }
+ return return_value;
}
static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
{
struct tevent_req *subreq;
+ int i = req->current_idx;
req->subreq = NULL;
- smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
-
- if (req->do_signing) {
- int i = req->current_idx;
- NTSTATUS status;
- status = smb2_signing_sign_pdu(req->session->session_key,
- &req->out.vector[i], 3);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- }
-
req->current_idx += 3;
if (req->current_idx < req->out.vector_count) {
return NT_STATUS_OK;
}
+ smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
+
+ /* Set credit for this operation (zero credits if this
+ is a final reply for an async operation). */
+ smb2_set_operation_credit(req->sconn,
+ req->async ? NULL : &req->in.vector[i],
+ &req->out.vector[i]);
+
+ if (req->do_signing) {
+ NTSTATUS status;
+ status = smb2_signing_sign_pdu(req->session->session_key,
+ &req->out.vector[i], 3);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+ }
+
if (DEBUGLEVEL >= 10) {
dbgtext("smbd_smb2_request_reply: sending...\n");
print_req_vectors(req);
}
+ /* I am a sick, sick man... :-). Sendfile hack ... JRA. */
+ if (req->out.vector_count == 4 &&
+ req->out.vector[3].iov_base == NULL &&
+ req->out.vector[3].iov_len != 0) {
+ /* Dynamic part is NULL. Chop it off,
+ We're going to send it via sendfile. */
+ req->out.vector_count -= 1;
+ }
+
subreq = tstream_writev_queue_send(req,
req->sconn->smb2.event_ctx,
req->sconn->smb2.stream,
const uint8_t *inbuf, size_t size)
{
NTSTATUS status;
- struct smbd_smb2_request *req;
+ struct smbd_smb2_request *req = NULL;
struct tevent_req *subreq;
DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
return;
}
- status = smbd_smb2_request_setup_out(req, 1);
+ status = smbd_smb2_request_setup_out(req);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(sconn, nt_errstr(status));
return;
static void smbd_smb2_request_incoming(struct tevent_req *subreq)
{
- uint16_t creds_requested = 0;
struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
struct smbd_server_connection);
NTSTATUS status;
DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
req->current_idx, req->in.vector_count));
- status = smbd_smb2_request_validate(req, &creds_requested);
+ status = smbd_smb2_request_validate(req);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(sconn, nt_errstr(status));
return;
}
- status = smbd_smb2_request_setup_out(req, 5);
+ status = smbd_smb2_request_setup_out(req);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(sconn, nt_errstr(status));
return;