summaryrefslogtreecommitdiff
path: root/source4/smb_server
diff options
context:
space:
mode:
Diffstat (limited to 'source4/smb_server')
-rw-r--r--source4/smb_server/smb2/negprot.c15
-rw-r--r--source4/smb_server/smb2/receive.c40
-rw-r--r--source4/smb_server/smb2/sesssetup.c8
-rw-r--r--source4/smb_server/smb_server.h2
4 files changed, 64 insertions, 1 deletions
diff --git a/source4/smb_server/smb2/negprot.c b/source4/smb_server/smb2/negprot.c
index 4479ae2da1..3e6e2e1a43 100644
--- a/source4/smb_server/smb2/negprot.c
+++ b/source4/smb_server/smb2/negprot.c
@@ -111,7 +111,20 @@ static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2
boot_time = timeval_current(); /* TODO: fix me */
ZERO_STRUCT(io->out);
- io->out.security_mode = 0; /* no signing yet */
+ switch (lp_server_signing(req->smb_conn->lp_ctx)) {
+ case SMB_SIGNING_OFF:
+ io->out.security_mode = 0;
+ break;
+ case SMB_SIGNING_SUPPORTED:
+ case SMB_SIGNING_AUTO:
+ io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+ break;
+ case SMB_SIGNING_REQUIRED:
+ io->out.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED | SMB2_NEGOTIATE_SIGNING_REQUIRED;
+ /* force signing on immediately */
+ req->smb_conn->doing_signing = true;
+ break;
+ }
io->out.dialect_revision = SMB2_DIALECT_REVISION;
io->out.capabilities = 0;
io->out.max_transact_size = lp_parm_ulong(req->smb_conn->lp_ctx, NULL,
diff --git a/source4/smb_server/smb2/receive.c b/source4/smb_server/smb2/receive.c
index dea7c9e79e..2f4e9df2b6 100644
--- a/source4/smb_server/smb2/receive.c
+++ b/source4/smb_server/smb2/receive.c
@@ -29,6 +29,8 @@
#include "lib/stream/packet.h"
#include "ntvfs/ntvfs.h"
#include "param/param.h"
+#include "auth/gensec/gensec.h"
+#include "auth/auth.h"
/* fill in the bufinfo */
@@ -233,6 +235,20 @@ void smb2srv_send_reply(struct smb2srv_request *req)
_smb2_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
}
+ /* if the request was signed or doing_signing is true, then we
+ must sign the reply */
+ if (req->session &&
+ (req->smb_conn->doing_signing ||
+ (IVAL(req->in.hdr, SMB2_HDR_FLAGS) & SMB2_HDR_FLAG_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)) {
@@ -275,18 +291,42 @@ static NTSTATUS smb2srv_reply(struct smb2srv_request *req)
uint16_t opcode;
uint32_t tid;
uint64_t uid;
+ uint32_t flags;
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);
req->session = smbsrv_session_find(req->smb_conn, uid, req->request_time);
req->tcon = smbsrv_smb2_tcon_find(req->session, tid, req->request_time);
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 == NULL) {
+ /* we can't check signing with no session */
+ smb2srv_send_error(req, NT_STATUS_ACCESS_DENIED);
+ return NT_STATUS_OK;
+ }
+ 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->smb_conn->doing_signing && req->session != NULL) {
+ /* we require signing and this request was not signed */
+ smb2srv_send_error(req, NT_STATUS_ACCESS_DENIED);
+ return NT_STATUS_OK;
+ }
+
/* TODO: check the seqnum */
switch (opcode) {
diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c
index d386bfc72d..9fb3220005 100644
--- a/source4/smb_server/smb2/sesssetup.c
+++ b/source4/smb_server/smb2/sesssetup.c
@@ -177,6 +177,14 @@ static void smb2srv_sesssetup_backend(struct smb2srv_request *req, union smb_ses
gensec_update_send(smb_sess->gensec_ctx, io->smb2.in.secblob,
smb2srv_sesssetup_callback, callback_ctx);
+
+ /* note that we ignore SMB2_NEGOTIATE_SIGNING_ENABLED from the client.
+ This is deliberate as windows does not set it even when it does
+ set SMB2_NEGOTIATE_SIGNING_REQUIRED */
+ if (io->smb2.in.security_mode & SMB2_NEGOTIATE_SIGNING_REQUIRED) {
+ req->smb_conn->doing_signing = true;
+ }
+
return;
nomem:
status = NT_STATUS_NO_MEMORY;
diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h
index 776fe1b71b..ac3e0f3bd3 100644
--- a/source4/smb_server/smb_server.h
+++ b/source4/smb_server/smb_server.h
@@ -376,6 +376,8 @@ struct smbsrv_connection {
struct share_context *share_context;
struct loadparm_context *lp_ctx;
+
+ bool doing_signing;
};
struct model_ops;