#include "../librpc/gen_ndr/krb5pac.h"
#include "lib/util/iov_buf.h"
#include "auth.h"
-#include "lib/crypto/sha512.h"
+#include "libcli/smb/smbXcli_base.h"
+
+#include "lib/crypto/gnutls_helpers.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/crypto.h>
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_SMB2
*/
if (len < SMB2_HDR_BODY + 2) {
+
+ if ((len == 5) &&
+ (IVAL(hdr, 0) == SMB_SUICIDE_PACKET) &&
+ lp_parm_bool(-1, "smbd", "suicide mode", false)) {
+ uint8_t exitcode = CVAL(hdr, 4);
+ DBG_WARNING("SUICIDE: Exiting immediately "
+ "with code %"PRIu8"\n",
+ exitcode);
+ exit(exitcode);
+ }
+
DEBUG(10, ("%d bytes left, expected at least %d\n",
(int)len, SMB2_HDR_BODY));
goto inval;
* of requests and the used sequence number.
* Which means we would grant more credits
* for client which use multi credit requests.
+ *
+ * The above is what Windows Server < 2016 is doing,
+ * but new servers use all credits (8192 by default).
*/
- current_max_credits = xconn->smb2.credits.max / 16;
+ current_max_credits = xconn->smb2.credits.max;
current_max_credits = MAX(current_max_credits, 1);
if (xconn->smb2.credits.multicredit) {
* with a successful session setup
*/
if (NT_STATUS_IS_OK(out_status)) {
- additional_max = 32;
+ additional_max = xconn->smb2.credits.max;
}
break;
default:
/*
- * We match windows and only grant additional credits
- * in chunks of 32.
+ * Windows Server < 2016 and older Samba versions
+ * used to only grant additional credits in
+ * chunks of 32 credits.
+ *
+ * But we match Windows Server 2016 and grant
+ * all credits as requested.
*/
- additional_max = 32;
+ additional_max = xconn->smb2.credits.max;
break;
}
return NT_STATUS_OK;
}
+void smbXsrv_connection_disconnect_transport(struct smbXsrv_connection *xconn,
+ NTSTATUS status)
+{
+ if (!NT_STATUS_IS_OK(xconn->transport.status)) {
+ return;
+ }
+
+ xconn->transport.status = status;
+ TALLOC_FREE(xconn->transport.fde);
+ if (xconn->transport.sock != -1) {
+ xconn->transport.sock = -1;
+ }
+ DO_PROFILE_INC(disconnect);
+}
+
+static size_t smbXsrv_client_valid_connections(struct smbXsrv_client *client)
+{
+ struct smbXsrv_connection *xconn = NULL;
+ size_t num_ok = 0;
+
+ for (xconn = client->connections; xconn != NULL; xconn = xconn->next) {
+ if (NT_STATUS_IS_OK(xconn->transport.status)) {
+ num_ok++;
+ }
+ }
+
+ return num_ok;
+}
+
+struct smbXsrv_connection_shutdown_state {
+ struct tevent_queue *wait_queue;
+};
+
+static void smbXsrv_connection_shutdown_wait_done(struct tevent_req *subreq);
+
+static struct tevent_req *smbXsrv_connection_shutdown_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct smbXsrv_connection *xconn)
+{
+ struct tevent_req *req = NULL;
+ struct smbXsrv_connection_shutdown_state *state = NULL;
+ struct tevent_req *subreq = NULL;
+ size_t len = 0;
+ struct smbd_smb2_request *preq = NULL;
+ NTSTATUS status;
+
+ /*
+ * The caller should have called
+ * smbXsrv_connection_disconnect_transport() before.
+ */
+ SMB_ASSERT(!NT_STATUS_IS_OK(xconn->transport.status));
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct smbXsrv_connection_shutdown_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ status = smbXsrv_session_disconnect_xconn(xconn);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ state->wait_queue = tevent_queue_create(state, "smbXsrv_connection_shutdown_queue");
+ if (tevent_req_nomem(state->wait_queue, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
+ /*
+ * The connection is gone so we
+ * don't need to take care of
+ * any crypto
+ */
+ preq->session = NULL;
+ preq->do_signing = false;
+ preq->do_encryption = false;
+ preq->preauth = NULL;
+
+ if (preq->subreq != NULL) {
+ tevent_req_cancel(preq->subreq);
+ }
+
+ /*
+ * Now wait until the request is finished.
+ *
+ * We don't set a callback, as we just want to block the
+ * wait queue and the talloc_free() of the request will
+ * remove the item from the wait queue.
+ */
+ subreq = tevent_queue_wait_send(preq, ev, state->wait_queue);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ }
+
+ len = tevent_queue_length(state->wait_queue);
+ if (len == 0) {
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * Now we add our own waiter to the end of the queue,
+ * this way we get notified when all pending requests are finished
+ * and send to the socket.
+ */
+ subreq = tevent_queue_wait_send(state, ev, state->wait_queue);
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, smbXsrv_connection_shutdown_wait_done, req);
+
+ return req;
+}
+
+static void smbXsrv_connection_shutdown_wait_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq,
+ struct tevent_req);
+
+ tevent_queue_wait_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ tevent_req_done(req);
+}
+
+static NTSTATUS smbXsrv_connection_shutdown_recv(struct tevent_req *req)
+{
+ return tevent_req_simple_recv_ntstatus(req);
+}
+
+static void smbd_server_connection_terminate_done(struct tevent_req *subreq)
+{
+ struct smbXsrv_connection *xconn =
+ tevent_req_callback_data(subreq,
+ struct smbXsrv_connection);
+ struct smbXsrv_client *client = xconn->client;
+ NTSTATUS status;
+
+ status = smbXsrv_connection_shutdown_recv(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ exit_server("smbXsrv_connection_shutdown_recv failed");
+ }
+
+ DLIST_REMOVE(client->connections, xconn);
+ TALLOC_FREE(xconn);
+}
+
void smbd_server_connection_terminate_ex(struct smbXsrv_connection *xconn,
const char *reason,
const char *location)
{
struct smbXsrv_client *client = xconn->client;
+ size_t num_ok = 0;
+
+ /*
+ * Make sure that no new request will be able to use this session.
+ *
+ * smbXsrv_connection_disconnect_transport() might be called already,
+ * but calling it again is a no-op.
+ */
+ smbXsrv_connection_disconnect_transport(xconn,
+ NT_STATUS_CONNECTION_DISCONNECTED);
+
+ num_ok = smbXsrv_client_valid_connections(client);
- DEBUG(10,("smbd_server_connection_terminate_ex: conn[%s] reason[%s] at %s\n",
- smbXsrv_connection_dbg(xconn), reason, location));
+ DBG_DEBUG("conn[%s] num_ok[%zu] reason[%s] at %s\n",
+ smbXsrv_connection_dbg(xconn), num_ok,
+ reason, location);
- if (client->connections->next != NULL) {
- /* TODO: cancel pending requests */
- DLIST_REMOVE(client->connections, xconn);
- TALLOC_FREE(xconn);
- DO_PROFILE_INC(disconnect);
+ if (num_ok != 0) {
+ struct tevent_req *subreq = NULL;
+
+ subreq = smbXsrv_connection_shutdown_send(client,
+ client->raw_ev_ctx,
+ xconn);
+ if (subreq == NULL) {
+ exit_server("smbXsrv_connection_shutdown_send failed");
+ }
+ tevent_req_set_callback(subreq,
+ smbd_server_connection_terminate_done,
+ xconn);
return;
}
* we need to sign/encrypt here with the last/first key we remembered
*/
if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
- status = smb2_signing_encrypt_pdu(req->first_key,
+ struct smb2_signing_key key = {
+ .blob = req->first_key,
+ };
+ status = smb2_signing_encrypt_pdu(&key,
xconn->smb2.server.cipher,
firsttf,
nreq->out.vector_count - first_idx);
+ smb2_signing_key_destructor(&key);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
} else if (req->last_key.length > 0) {
- status = smb2_signing_sign_pdu(req->last_key,
+ struct smb2_signing_key key = {
+ .blob = req->last_key,
+ };
+
+ status = smb2_signing_sign_pdu(&key,
xconn->protocol,
outhdr_v,
SMBD_SMB2_NUM_IOV_PER_REQ - 1);
+ smb2_signing_key_destructor(&key);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
return NT_STATUS_OK;
}
- if (req->async_internal) {
+ if (req->async_internal || defer_time == 0) {
/*
* An SMB2 request implementation wants to handle the request
* asynchronously "internally" while keeping synchronous
return NT_STATUS_OK;
}
-static DATA_BLOB smbd_smb2_signing_key(struct smbXsrv_session *session,
- struct smbXsrv_connection *xconn)
+static
+struct smb2_signing_key *smbd_smb2_signing_key(struct smbXsrv_session *session,
+ struct smbXsrv_connection *xconn)
{
struct smbXsrv_channel_global0 *c = NULL;
NTSTATUS status;
- DATA_BLOB key = data_blob_null;
+ struct smb2_signing_key *key = NULL;
status = smbXsrv_session_find_channel(session, xconn, &c);
if (NT_STATUS_IS_OK(status)) {
key = c->signing_key;
}
- if (key.length == 0) {
+ if (!smb2_signing_key_valid(key)) {
key = session->global->signing_key;
}
uint8_t *outhdr = NULL;
const uint8_t *inhdr = NULL;
uint8_t *tf = NULL;
- size_t tf_len = 0;
uint8_t *hdr = NULL;
uint8_t *body = NULL;
uint8_t *dyn = NULL;
uint32_t flags = 0;
- uint64_t session_id = 0;
uint64_t message_id = 0;
- uint64_t nonce_high = 0;
- uint64_t nonce_low = 0;
uint64_t async_id = 0;
NTSTATUS status;
bool ok;
outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
flags = IVAL(outhdr, SMB2_HDR_FLAGS);
message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
- session_id = BVAL(outhdr, SMB2_HDR_SESSION_ID);
async_id = message_id; /* keep it simple for now... */
}
tf = state->buf + NBT_HDR_SIZE;
- tf_len = SMB2_TF_HDR_SIZE;
hdr = tf + SMB2_TF_HDR_SIZE;
body = hdr + SMB2_HDR_BODY;
dyn = body + 8;
if (req->do_encryption) {
+ uint64_t nonce_high = 0;
+ uint64_t nonce_low = 0;
+ uint64_t session_id = req->session->global->session_wire_id;
+
status = smb2_get_new_nonce(req->session,
&nonce_high,
&nonce_low);
nt_errstr(status));
return;
}
- }
- SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
- SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
- SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
- SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
+ SIVAL(tf, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC);
+ SBVAL(tf, SMB2_TF_NONCE+0, nonce_low);
+ SBVAL(tf, SMB2_TF_NONCE+8, nonce_high);
+ SBVAL(tf, SMB2_TF_SESSION_ID, session_id);
+ }
SIVAL(hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC);
SSVAL(hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
if (req->do_encryption) {
state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = tf;
- state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = tf_len;
+ state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len =
+ SMB2_TF_HDR_SIZE;
} else {
state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_base = NULL;
state->vector[1+SMBD_SMB2_TF_IOV_OFS].iov_len = 0;
if (req->do_encryption) {
struct smbXsrv_session *x = req->session;
- DATA_BLOB encryption_key = x->global->encryption_key;
+ struct smb2_signing_key *encryption_key = x->global->encryption_key;
status = smb2_signing_encrypt_pdu(encryption_key,
xconn->smb2.server.cipher,
}
} else if (req->do_signing) {
struct smbXsrv_session *x = req->session;
- DATA_BLOB signing_key = smbd_smb2_signing_key(x, xconn);
+ struct smb2_signing_key *signing_key =
+ smbd_smb2_signing_key(x, xconn);
status = smb2_signing_sign_pdu(signing_key,
xconn->protocol,
return status;
}
- if (!change_to_user(tcon->compat, req->session->compat->vuid)) {
+ if (!change_to_user_and_service(
+ tcon->compat,
+ req->session->global->session_wire_id))
+ {
return NT_STATUS_ACCESS_DENIED;
}
switch (opcode) {
case SMB2_OP_IOCTL:
case SMB2_OP_GETINFO:
- min_dyn_size = 0;
- break;
case SMB2_OP_WRITE:
- if (req->smb1req != NULL && req->smb1req->unread_bytes > 0) {
- if (req->smb1req->unread_bytes < min_dyn_size) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- min_dyn_size = 0;
- }
+ min_dyn_size = 0;
break;
}
req->async_internal = false;
req->do_signing = false;
- req->do_encryption = false;
+ if (opcode != SMB2_OP_SESSSETUP) {
+ req->do_encryption = encryption_desired;
+ } else {
+ req->do_encryption = false;
+ }
req->was_encrypted = false;
if (intf_v->iov_len == SMB2_TF_HDR_SIZE) {
const uint8_t *intf = SMBD_SMB2_IN_TF_PTR(req);
}
req->was_encrypted = true;
+ req->do_encryption = true;
}
if (encryption_required && !req->was_encrypted) {
+ req->do_encryption = true;
return smbd_smb2_request_error(req,
NT_STATUS_ACCESS_DENIED);
}
if (req->was_encrypted) {
signing_required = false;
} else if (signing_required || (flags & SMB2_HDR_FLAG_SIGNED)) {
- DATA_BLOB signing_key = data_blob_null;
+ struct smb2_signing_key *signing_key = NULL;
if (x == NULL) {
/*
* If we have a signing key, we should
* sign the response
*/
- if (signing_key.length > 0) {
+ if (smb2_signing_key_valid(signing_key)) {
req->do_signing = true;
}
encryption_required = true;
}
if (encryption_required && !req->was_encrypted) {
+ req->do_encryption = true;
return smbd_smb2_request_error(req,
NT_STATUS_ACCESS_DENIED);
+ } else if (encryption_desired) {
+ req->do_encryption = true;
}
} else if (call->need_session) {
struct auth_session_info *session_info = NULL;
session_info->info->domain_name);
}
- if (req->was_encrypted || encryption_desired) {
- req->do_encryption = true;
- }
-
if (req->session) {
bool update_session_global = false;
bool update_tcon_global = false;
SMB_ASSERT(call->fileid_ofs == 0);
/* This call needs to be run as root */
change_to_root_user();
- req->ev_ctx = req->sconn->root_ev_ctx;
} else {
SMB_ASSERT(call->need_tcon);
- req->ev_ctx = req->tcon->compat->user_ev_ctx;
}
#define _INBYTES(_r) \
(firsttf->iov_len == 0) &&
(req->first_key.length == 0) &&
(req->session != NULL) &&
- (req->session->global->encryption_key.length != 0))
+ smb2_signing_key_valid(req->session->global->encryption_key))
{
- DATA_BLOB encryption_key = req->session->global->encryption_key;
+ struct smb2_signing_key *encryption_key =
+ req->session->global->encryption_key;
uint8_t *tf;
uint64_t session_id = req->session->global->session_wire_id;
uint64_t nonce_high;
* we are sure that we do not change
* the header again.
*/
- req->first_key = data_blob_dup_talloc(req, encryption_key);
+ req->first_key = data_blob_dup_talloc(req,
+ encryption_key->blob);
if (req->first_key.data == NULL) {
return NT_STATUS_NO_MEMORY;
}
{
int last_idx = req->current_idx - SMBD_SMB2_NUM_IOV_PER_REQ;
struct iovec *lasthdr = SMBD_SMB2_IDX_HDR_IOV(req,out,last_idx);
+ struct smb2_signing_key key = {
+ .blob = req->last_key,
+ };
/*
* As we are sure the header of the last request in the
* compound chain will not change, we can to sign here
* with the last signing key we remembered.
*/
- status = smb2_signing_sign_pdu(req->last_key,
+ status = smb2_signing_sign_pdu(&key,
xconn->protocol,
lasthdr,
SMBD_SMB2_NUM_IOV_PER_REQ - 1);
+ smb2_signing_key_destructor(&key);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (req->do_signing && firsttf->iov_len == 0) {
struct smbXsrv_session *x = req->session;
- DATA_BLOB signing_key = smbd_smb2_signing_key(x, xconn);
+ struct smb2_signing_key *signing_key =
+ smbd_smb2_signing_key(x, xconn);
/*
* we need to remember the signing key
* we are sure that we do not change
* the header again.
*/
- req->last_key = data_blob_dup_talloc(req, signing_key);
+ req->last_key = data_blob_dup_talloc(req,
+ signing_key->blob);
if (req->last_key.data == NULL) {
return NT_STATUS_NO_MEMORY;
}
* now check if we need to sign the current response
*/
if (firsttf->iov_len == SMB2_TF_HDR_SIZE) {
- status = smb2_signing_encrypt_pdu(req->first_key,
+ struct smb2_signing_key key = {
+ .blob = req->first_key,
+ };
+ status = smb2_signing_encrypt_pdu(&key,
xconn->smb2.server.cipher,
firsttf,
req->out.vector_count - first_idx);
+ smb2_signing_key_destructor(&key);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
} else if (req->do_signing) {
struct smbXsrv_session *x = req->session;
- DATA_BLOB signing_key = smbd_smb2_signing_key(x, xconn);
+ struct smb2_signing_key *signing_key =
+ smbd_smb2_signing_key(x, xconn);
status = smb2_signing_sign_pdu(signing_key,
xconn->protocol,
}
if (req->preauth != NULL) {
- struct hc_sha512state sctx;
- int i;
+ gnutls_hash_hd_t hash_hnd = NULL;
+ size_t i;
+ int rc;
- samba_SHA512_Init(&sctx);
- samba_SHA512_Update(&sctx, req->preauth->sha512_value,
- sizeof(req->preauth->sha512_value));
+ rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_SHA512);
+ if (rc < 0) {
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ rc = gnutls_hash(hash_hnd,
+ req->preauth->sha512_value,
+ sizeof(req->preauth->sha512_value));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
for (i = 1; i < req->in.vector_count; i++) {
- samba_SHA512_Update(&sctx,
- req->in.vector[i].iov_base,
- req->in.vector[i].iov_len);
+ rc = gnutls_hash(hash_hnd,
+ req->in.vector[i].iov_base,
+ req->in.vector[i].iov_len);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ }
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
+ gnutls_hash_output(hash_hnd, req->preauth->sha512_value);
+
+ rc = gnutls_hash(hash_hnd,
+ req->preauth->sha512_value,
+ sizeof(req->preauth->sha512_value));
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
}
- samba_SHA512_Final(req->preauth->sha512_value, &sctx);
-
- samba_SHA512_Init(&sctx);
- samba_SHA512_Update(&sctx, req->preauth->sha512_value,
- sizeof(req->preauth->sha512_value));
for (i = 1; i < req->out.vector_count; i++) {
- samba_SHA512_Update(&sctx,
- req->out.vector[i].iov_base,
- req->out.vector[i].iov_len);
+ rc = gnutls_hash(hash_hnd,
+ req->out.vector[i].iov_base,
+ req->out.vector[i].iov_len);
+ if (rc < 0) {
+ gnutls_hash_deinit(hash_hnd, NULL);
+ return gnutls_error_to_ntstatus(rc, NT_STATUS_HASH_NOT_SUPPORTED);
+ }
}
- samba_SHA512_Final(req->preauth->sha512_value, &sctx);
+
+ gnutls_hash_deinit(hash_hnd, req->preauth->sha512_value);
req->preauth = NULL;
}
struct iovec *outbody_v;
struct iovec *outdyn_v;
uint32_t next_command_ofs;
+ uint64_t mid;
- DEBUG(10,("smbd_smb2_request_done_ex: "
- "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
- req->current_idx, nt_errstr(status), (unsigned int)body.length,
- dyn ? "yes": "no",
+ outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
+ mid = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
+
+ DBG_DEBUG("mid [%"PRIu64"] idx[%d] status[%s] "
+ "body[%u] dyn[%s:%u] at %s\n",
+ mid,
+ req->current_idx,
+ nt_errstr(status),
+ (unsigned int)body.length,
+ dyn ? "yes" : "no",
(unsigned int)(dyn ? dyn->length : 0),
- location));
+ location);
if (body.length < 2) {
return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
}
- outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
outbody_v = SMBD_SMB2_OUT_BODY_IOV(req);
outdyn_v = SMBD_SMB2_OUT_DYN_IOV(req);
}
if (do_encryption) {
- DATA_BLOB encryption_key = session->global->encryption_key;
+ struct smb2_signing_key *encryption_key =
+ session->global->encryption_key;
status = smb2_signing_encrypt_pdu(encryption_key,
xconn->smb2.server.cipher,
if (IS_PRINT(fsp->conn)) {
return false;
}
+ if (fsp->base_fsp != NULL) {
+ return false;
+ }
DEBUG(10,("Doing recvfile write len = %u\n",
(unsigned int)(state->pktfull - state->pktlen)));
return NT_STATUS_OK;
}
-void smbd_smb2_process_negprot(struct smbXsrv_connection *xconn,
+NTSTATUS smbd_smb2_process_negprot(struct smbXsrv_connection *xconn,
uint64_t expected_seq_low,
const uint8_t *inpdu, size_t size)
{
status = smbd_initialize_smb2(xconn, expected_seq_low);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(xconn, nt_errstr(status));
- return;
+ return status;
}
status = smbd_smb2_request_create(xconn, inpdu, size, &req);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(xconn, nt_errstr(status));
- return;
+ return status;
}
status = smbd_smb2_request_validate(req);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(xconn, nt_errstr(status));
- return;
+ return status;
}
status = smbd_smb2_request_setup_out(req);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(xconn, nt_errstr(status));
- return;
+ return status;
}
#ifdef WITH_PROFILE
status = smbd_smb2_request_dispatch(req);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(xconn, nt_errstr(status));
- return;
+ return status;
}
status = smbd_smb2_request_next_incoming(xconn);
if (!NT_STATUS_IS_OK(status)) {
smbd_server_connection_terminate(xconn, nt_errstr(status));
- return;
+ return status;
}
sconn->num_requests++;
+ return NT_STATUS_OK;
}
static int socket_error_from_errno(int ret,
while (xconn->smb2.send_queue != NULL) {
struct smbd_smb2_send_queue *e = xconn->smb2.send_queue;
bool ok;
+ struct msghdr msg;
if (e->sendfile_header != NULL) {
size_t size = 0;
talloc_free(e->mem_ctx);
if (!NT_STATUS_IS_OK(status)) {
+ smbXsrv_connection_disconnect_transport(xconn,
+ status);
return status;
}
continue;
}
- ret = writev(xconn->transport.sock, e->vector, e->count);
+ msg = (struct msghdr) {
+ .msg_iov = e->vector,
+ .msg_iovlen = e->count,
+ };
+
+ ret = sendmsg(xconn->transport.sock, &msg, 0);
if (ret == 0) {
/* propagate end of file */
return NT_STATUS_INTERNAL_ERROR;
return NT_STATUS_OK;
}
if (err != 0) {
- return map_nt_error_from_unix_common(err);
+ status = map_nt_error_from_unix_common(err);
+ smbXsrv_connection_disconnect_transport(xconn,
+ status);
+ return status;
}
ok = iov_advance(&e->vector, &e->count, ret);
bool retry;
NTSTATUS status;
NTTIME now;
+ struct msghdr msg;
if (!NT_STATUS_IS_OK(xconn->transport.status)) {
/*
state->vector.iov_len = NBT_HDR_SIZE;
}
- ret = readv(xconn->transport.sock, &state->vector, 1);
+ msg = (struct msghdr) {
+ .msg_iov = &state->vector,
+ .msg_iovlen = 1,
+ };
+
+ ret = recvmsg(xconn->transport.sock, &msg, 0);
if (ret == 0) {
/* propagate end of file */
- return NT_STATUS_END_OF_FILE;
+ status = NT_STATUS_END_OF_FILE;
+ smbXsrv_connection_disconnect_transport(xconn,
+ status);
+ return status;
}
err = socket_error_from_errno(ret, errno, &retry);
if (retry) {
return NT_STATUS_OK;
}
if (err != 0) {
- return map_nt_error_from_unix_common(err);
+ status = map_nt_error_from_unix_common(err);
+ smbXsrv_connection_disconnect_transport(xconn,
+ status);
+ return status;
}
if (ret < state->vector.iov_len) {