*/
#include "includes.h"
+#include "smbd/smbd.h"
#include "smbd/globals.h"
#include "../libcli/smb/smb_common.h"
#include "../lib/tsocket/tsocket.h"
+#include "../lib/util/tevent_ntstatus.h"
+#include "smbprofile.h"
+#include "../lib/util/bitmap.h"
+#include "../librpc/gen_ndr/krb5pac.h"
+#include "auth.h"
#define OUTVEC_ALLOC_SIZE (SMB2_HDR_BODY + 9)
TALLOC_FREE(sconn->smb1.fde);
- sconn->smb2.event_ctx = smbd_event_context();
+ sconn->smb2.event_ctx = server_event_context();
sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
if (sconn->smb2.recv_queue == 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, 2*sconn->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;
}
memcpy(req->in.nbt_hdr, inbuf, 4);
ofs = 0;
- req->in.vector[0].iov_base = (void *)req->in.nbt_hdr;
+ req->in.vector[0].iov_base = discard_const_p(void, req->in.nbt_hdr);
req->in.vector[0].iov_len = 4;
ofs += req->in.vector[0].iov_len;
- req->in.vector[1].iov_base = (void *)(inbuf + ofs);
+ req->in.vector[1].iov_base = discard_const_p(void, (inbuf + ofs));
req->in.vector[1].iov_len = SMB2_HDR_BODY;
ofs += req->in.vector[1].iov_len;
- req->in.vector[2].iov_base = (void *)(inbuf + ofs);
+ req->in.vector[2].iov_base = discard_const_p(void, (inbuf + ofs));
req->in.vector[2].iov_len = SVAL(inbuf, ofs) & 0xFFFE;
ofs += req->in.vector[2].iov_len;
return NT_STATUS_INVALID_PARAMETER;
}
- req->in.vector[3].iov_base = (void *)(inbuf + ofs);
+ req->in.vector[3].iov_base = discard_const_p(void, (inbuf + ofs));
req->in.vector[3].iov_len = size - ofs;
ofs += req->in.vector[3].iov_len;
if (message_id < sconn->smb2.seqnum_low ||
message_id > (sconn->smb2.seqnum_low +
- (2*sconn->smb2.credits_granted))) {
+ (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR))) {
DEBUG(0,("smb2_validate_message_id: bad message_id "
- "%llu (low = %llu, granted = %lu)\n",
+ "%llu (low = %llu, max = %lu)\n",
(unsigned long long)message_id,
(unsigned long long)sconn->smb2.seqnum_low,
- (unsigned long)sconn->smb2.credits_granted ));
+ (unsigned long)sconn->smb2.max_credits ));
return false;
}
/* Mark the message_id as seen in the bitmap. */
bitmap_offset = (unsigned int)(message_id %
- (uint64_t)(sconn->smb2.max_credits * 2));
+ (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",
bitmap_clear(credits_bm, bitmap_offset);
sconn->smb2.seqnum_low += 1;
bitmap_offset = (bitmap_offset + 1) %
- (sconn->smb2.max_credits * 2);
+ (sconn->smb2.max_credits * DEFAULT_SMB2_MAX_CREDIT_BITMAP_FACTOR);
}
}
const struct iovec *in_vector,
struct iovec *out_vector)
{
- uint8_t *outhdr = out_vector->iov_base;
+ uint8_t *outhdr = (uint8_t *)out_vector->iov_base;
uint16_t credits_requested = 0;
uint16_t credits_granted = 0;
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_requested) {
+ uint16_t modified_credits_requested;
+ uint32_t multiplier;
+
+ /*
+ * Split up max_credits into 1/16ths, and then scale
+ * the requested credits by how many 16ths have been
+ * currently granted. Less than 1/16th == grant all
+ * requested (100%), scale down as more have been
+ * granted. Never ask for less than 1 as the client
+ * asked for at least 1. JRA.
+ */
+
+ multiplier = 16 - (((sconn->smb2.credits_granted * 16) / sconn->smb2.max_credits) % 16);
+
+ modified_credits_requested = (multiplier * credits_requested) / 16;
+ if (modified_credits_requested == 0) {
+ modified_credits_requested = 1;
+ }
+
+ /* Remember what we gave out. */
+ credits_granted = MIN(modified_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
srcvec[1].iov_base ==
((uint8_t *)srcvec[0].iov_base) +
SMB2_HDR_BODY) {
- outvec[1].iov_base = ((uint8_t *)outvec[1].iov_base) +
+ outvec[1].iov_base = ((uint8_t *)outvec[0].iov_base) +
SMB2_HDR_BODY;
outvec[1].iov_len = 8;
} else {
}
newreq->sconn = req->sconn;
+ newreq->session = req->session;
newreq->do_signing = req->do_signing;
newreq->current_idx = req->current_idx;
newreq->async = false;
newreq->cancelled = false;
+ /* Note we are leaving:
+ ->tcon
+ ->smb1req
+ ->compat_chain_fsp
+ uninitialized as NULL here as
+ they're not used in the interim
+ response code. JRA. */
outvec = talloc_zero_array(newreq, struct iovec, count);
if (!outvec) {
if (req->do_signing) {
status = smb2_signing_sign_pdu(req->session->session_key,
- state->vector, 3);
+ &state->vector[1], 2);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return NT_STATUS_OK;
}
+/*************************************************************
+ Ensure an incoming tid is a valid one for us to access.
+ Change to the associated uid credentials and chdir to the
+ valid tid directory.
+*************************************************************/
+
+static NTSTATUS smbd_smb2_request_check_tcon(struct smbd_smb2_request *req)
+{
+ const uint8_t *inhdr;
+ const uint8_t *outhdr;
+ int i = req->current_idx;
+ uint32_t in_tid;
+ void *p;
+ struct smbd_smb2_tcon *tcon;
+ bool chained_fixup = false;
+
+ inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
+
+ in_tid = IVAL(inhdr, SMB2_HDR_TID);
+
+ if (in_tid == (0xFFFFFFFF)) {
+ if (req->async) {
+ /*
+ * async request - fill in tid from
+ * already setup out.vector[].iov_base.
+ */
+ outhdr = (const uint8_t *)req->out.vector[i].iov_base;
+ in_tid = IVAL(outhdr, SMB2_HDR_TID);
+ } else if (i > 2) {
+ /*
+ * Chained request - fill in tid from
+ * the previous request out.vector[].iov_base.
+ */
+ outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
+ in_tid = IVAL(outhdr, SMB2_HDR_TID);
+ chained_fixup = true;
+ }
+ }
+
+ /* lookup an existing session */
+ p = idr_find(req->session->tcons.idtree, in_tid);
+ if (p == NULL) {
+ return NT_STATUS_NETWORK_NAME_DELETED;
+ }
+ tcon = talloc_get_type_abort(p, struct smbd_smb2_tcon);
+
+ if (!change_to_user(tcon->compat_conn,req->session->vuid)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ /* should we pass FLAG_CASELESS_PATHNAMES here? */
+ if (!set_current_service(tcon->compat_conn, 0, true)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ req->tcon = tcon;
+
+ if (chained_fixup) {
+ /* Fix up our own outhdr. */
+ outhdr = (const uint8_t *)req->out.vector[i].iov_base;
+ SIVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_TID, in_tid);
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*************************************************************
+ Ensure an incoming session_id is a valid one for us to access.
+*************************************************************/
+
+static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
+{
+ const uint8_t *inhdr;
+ const uint8_t *outhdr;
+ int i = req->current_idx;
+ uint64_t in_session_id;
+ void *p;
+ struct smbd_smb2_session *session;
+ bool chained_fixup = false;
+
+ inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
+
+ in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
+
+ if (in_session_id == (0xFFFFFFFFFFFFFFFFLL)) {
+ if (req->async) {
+ /*
+ * async request - fill in session_id from
+ * already setup request out.vector[].iov_base.
+ */
+ outhdr = (const uint8_t *)req->out.vector[i].iov_base;
+ in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
+ } else if (i > 2) {
+ /*
+ * Chained request - fill in session_id from
+ * the previous request out.vector[].iov_base.
+ */
+ outhdr = (const uint8_t *)req->out.vector[i-3].iov_base;
+ in_session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
+ chained_fixup = true;
+ }
+ }
+
+ /* lookup an existing session */
+ p = idr_find(req->sconn->smb2.sessions.idtree, in_session_id);
+ if (p == NULL) {
+ return NT_STATUS_USER_SESSION_DELETED;
+ }
+ session = talloc_get_type_abort(p, struct smbd_smb2_session);
+
+ if (!NT_STATUS_IS_OK(session->status)) {
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ set_current_user_info(session->session_info->unix_info->sanitized_username,
+ session->session_info->unix_info->unix_name,
+ session->session_info->info->domain_name);
+
+ req->session = session;
+
+ if (chained_fixup) {
+ /* Fix up our own outhdr. */
+ outhdr = (const uint8_t *)req->out.vector[i].iov_base;
+ SBVAL(discard_const_p(uint8_t, outhdr), SMB2_HDR_SESSION_ID, in_session_id);
+ }
+ return NT_STATUS_OK;
+}
+
NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
{
const uint8_t *inhdr;
return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
}
+ /*
+ * Check if the client provided a valid session id,
+ * if so smbd_smb2_request_check_session() calls
+ * set_current_user_info().
+ *
+ * As some command don't require a valid session id
+ * we defer the check of the session_status
+ */
session_status = smbd_smb2_request_check_session(req);
req->do_signing = false;
switch (opcode) {
case SMB2_OP_NEGPROT:
+ /* This call needs to be run as root */
+ change_to_root_user();
+
{
START_PROFILE(smb2_negprot);
return_value = smbd_smb2_request_process_negprot(req);
break;
case SMB2_OP_SESSSETUP:
+ /* This call needs to be run as root */
+ change_to_root_user();
+
{
START_PROFILE(smb2_sesssetup);
return_value = smbd_smb2_request_process_sesssetup(req);
break;
}
+ /* This call needs to be run as root */
+ change_to_root_user();
+
{
START_PROFILE(smb2_logoff);
return_value = smbd_smb2_request_process_logoff(req);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
- status = smbd_smb2_request_check_session(req);
- if (!NT_STATUS_IS_OK(status)) {
- return_value = smbd_smb2_request_error(req, status);
- break;
- }
+
+ /*
+ * This call needs to be run as root.
+ *
+ * smbd_smb2_request_process_tcon()
+ * calls make_connection_snum(), which will call
+ * change_to_user(), when needed.
+ */
+ change_to_root_user();
{
START_PROFILE(smb2_tcon);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
break;
}
+ /* This call needs to be run as root */
+ change_to_root_user();
+
{
START_PROFILE(smb2_tdis);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
/* Too ugly to live ? JRA. */
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
break;
case SMB2_OP_CANCEL:
+ /*
+ * This call needs to be run as root
+ *
+ * That is what we also do in the SMB1 case.
+ */
+ change_to_root_user();
+
{
START_PROFILE(smb2_cancel);
return_value = smbd_smb2_request_process_cancel(req);
break;
case SMB2_OP_KEEPALIVE:
- {START_PROFILE(smb2_keepalive);
- return_value = smbd_smb2_request_process_keepalive(req);
- END_PROFILE(smb2_keepalive);}
+ /* This call needs to be run as root */
+ change_to_root_user();
+
+ {
+ START_PROFILE(smb2_keepalive);
+ return_value = smbd_smb2_request_process_keepalive(req);
+ END_PROFILE(smb2_keepalive);
+ }
break;
case SMB2_OP_FIND:
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
return_value = smbd_smb2_request_error(req, session_status);
break;
}
+ /*
+ * This call needs to be run as user.
+ *
+ * smbd_smb2_request_check_tcon()
+ * calls change_to_user() on success.
+ */
status = smbd_smb2_request_check_tcon(req);
if (!NT_STATUS_IS_OK(status)) {
return_value = smbd_smb2_request_error(req, status);
req->subreq = NULL;
- 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;
- }
- }
-
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);
}
}
+static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn);
+
static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
{
struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
struct smbd_server_connection *sconn = req->sconn;
int ret;
int sys_errno;
+ NTSTATUS status;
ret = tstream_writev_queue_recv(subreq, &sys_errno);
TALLOC_FREE(subreq);
TALLOC_FREE(req);
if (ret == -1) {
- NTSTATUS status = map_nt_error_from_unix(sys_errno);
+ status = map_nt_error_from_unix(sys_errno);
DEBUG(2,("smbd_smb2_request_writev_done: client write error %s\n",
nt_errstr(status)));
smbd_server_connection_terminate(sconn, nt_errstr(status));
return;
}
+
+ status = smbd_smb2_request_next_incoming(sconn);
+ if (!NT_STATUS_IS_OK(status)) {
+ smbd_server_connection_terminate(sconn, nt_errstr(status));
+ return;
+ }
}
NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
invalid = true;
}
- if ((body_size % 2) != 0) {
- body_size -= 1;
- }
+ /*
+ * Mask out the lowest bit, the "dynamic" part
+ * of body_size.
+ */
+ body_size &= ~1;
if (body_size > (full_size - SMB2_HDR_BODY)) {
/*
static void smbd_smb2_request_incoming(struct tevent_req *subreq);
+static NTSTATUS smbd_smb2_request_next_incoming(struct smbd_server_connection *sconn)
+{
+ size_t max_send_queue_len;
+ size_t cur_send_queue_len;
+ struct tevent_req *subreq;
+
+ if (tevent_queue_length(sconn->smb2.recv_queue) > 0) {
+ /*
+ * if there is already a smbd_smb2_request_read
+ * pending, we are done.
+ */
+ return NT_STATUS_OK;
+ }
+
+ max_send_queue_len = MAX(1, sconn->smb2.max_credits/16);
+ cur_send_queue_len = tevent_queue_length(sconn->smb2.send_queue);
+
+ if (cur_send_queue_len > max_send_queue_len) {
+ /*
+ * if we have a lot of requests to send,
+ * we wait until they are on the wire until we
+ * ask for the next request.
+ */
+ return NT_STATUS_OK;
+ }
+
+ /* ask for the next request */
+ subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
+ if (subreq == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
+
+ return NT_STATUS_OK;
+}
+
void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
const uint8_t *inbuf, size_t size)
{
NTSTATUS status;
struct smbd_smb2_request *req = NULL;
- struct tevent_req *subreq;
-
- if (lp_security() == SEC_SHARE) {
- DEBUG(2,("WARNING!!: \"security = share\" is deprecated for "
- "SMB2 servers. Mapping to \"security = user\" and "
- "\"map to guest = Bad User\"\n" ));
- lp_do_parameter(-1, "security", "user");
- lp_do_parameter(-1, "map to guest", "Bad User");
- }
DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
(unsigned int)size));
return;
}
- /* ask for the next request */
- subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
- if (subreq == NULL) {
- smbd_server_connection_terminate(sconn, "no memory for reading");
+ status = smbd_smb2_request_next_incoming(sconn);
+ if (!NT_STATUS_IS_OK(status)) {
+ smbd_server_connection_terminate(sconn, nt_errstr(status));
return;
}
- tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
+
+ sconn->num_requests++;
}
static void smbd_smb2_request_incoming(struct tevent_req *subreq)
}
next:
- /* ask for the next request (this constructs the main loop) */
- subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
- if (subreq == NULL) {
- smbd_server_connection_terminate(sconn, "no memory for reading");
+ status = smbd_smb2_request_next_incoming(sconn);
+ if (!NT_STATUS_IS_OK(status)) {
+ smbd_server_connection_terminate(sconn, nt_errstr(status));
return;
}
- tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
+
+ sconn->num_requests++;
+
+ /* The timeout_processing function isn't run nearly
+ often enough to implement 'max log size' without
+ overrunning the size of the file by many megabytes.
+ This is especially true if we are running at debug
+ level 10. Checking every 50 SMB2s is a nice
+ tradeoff of performance vs log file size overrun. */
+
+ if ((sconn->num_requests % 50) == 0 &&
+ need_to_check_log_size()) {
+ change_to_root_user();
+ check_log_size();
+ }
}