From e97cf207fac5e4101376d2a10dd95a93a9a1e0fb Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Fri, 6 Jun 2008 22:10:30 -0700 Subject: added server side SMB2 signing (This used to be commit 8e919dcb0826a5b25d037ee6144af5f7cb21f3ae) --- source4/smb_server/smb2/negprot.c | 13 ++++++++++++- source4/smb_server/smb2/receive.c | 36 ++++++++++++++++++++++++++++++++++++ source4/smb_server/smb2/sesssetup.c | 9 +++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) (limited to 'source4/smb_server/smb2') diff --git a/source4/smb_server/smb2/negprot.c b/source4/smb_server/smb2/negprot.c index 4479ae2da1..2da39001ab 100644 --- a/source4/smb_server/smb2/negprot.c +++ b/source4/smb_server/smb2/negprot.c @@ -111,7 +111,18 @@ 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; + 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..3def8fe563 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,38 @@ 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; + } + } + /* TODO: check the seqnum */ switch (opcode) { diff --git a/source4/smb_server/smb2/sesssetup.c b/source4/smb_server/smb2/sesssetup.c index d386bfc72d..482dd181c2 100644 --- a/source4/smb_server/smb2/sesssetup.c +++ b/source4/smb_server/smb2/sesssetup.c @@ -177,6 +177,15 @@ 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) || + lp_server_signing(req->smb_conn->lp_ctx) == SMB_SIGNING_REQUIRED) { + req->smb_conn->doing_signing = true; + } + return; nomem: status = NT_STATUS_NO_MEMORY; -- cgit