fixed mandatory signing
[kai/samba.git] / source4 / smb_server / smb2 / negprot.c
index 8e3f6156ea41f6ca8a693fc21c07a0d418c28a15..3e6e2e1a43c9b2a222f91062bc37bc605788ec72 100644 (file)
@@ -6,7 +6,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
    GNU General Public License for more details.
    
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
-#include "auth/auth.h"
+#include "auth/credentials/credentials.h"
+#include "auth/gensec/gensec.h"
+#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
 #include "libcli/smb2/smb2.h"
 #include "libcli/smb2/smb2_calls.h"
 #include "smb_server/smb_server.h"
 #include "smb_server/service_smb_proto.h"
 #include "smb_server/smb2/smb2_server.h"
 #include "smbd/service_stream.h"
+#include "param/param.h"
+#include "librpc/ndr/libndr.h"
 
 static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *_blob)
 {
@@ -38,6 +42,7 @@ static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *
 
        nt_status = gensec_server_start(req,
                                        req->smb_conn->connection->event.ctx,
+                                       req->smb_conn->lp_ctx,
                                        req->smb_conn->connection->msg_ctx,
                                        &gensec_security);
        if (!NT_STATUS_IS_OK(nt_status)) {
@@ -52,8 +57,8 @@ static NTSTATUS smb2srv_negprot_secblob(struct smb2srv_request *req, DATA_BLOB *
                return NT_STATUS_NO_MEMORY;
        }
 
-       cli_credentials_set_conf(server_credentials);
-       nt_status = cli_credentials_set_machine_account(server_credentials);
+       cli_credentials_set_conf(server_credentials, req->smb_conn->lp_ctx);
+       nt_status = cli_credentials_set_machine_account(server_credentials, req->smb_conn->lp_ctx);
        if (!NT_STATUS_IS_OK(nt_status)) {
                DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(nt_status)));
                talloc_free(server_credentials);
@@ -90,24 +95,49 @@ static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2
        struct timeval current_time;
        struct timeval boot_time;
 
+       /* we only do one dialect for now */
+       if (io->in.dialect_count < 1) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+       if (io->in.dialects[0] != 0 &&
+           io->in.dialects[0] != SMB2_DIALECT_REVISION) {
+               DEBUG(0,("Got unexpected SMB2 dialect %u\n", io->in.dialects[0]));
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
        req->smb_conn->negotiate.protocol = PROTOCOL_SMB2;
 
        current_time = timeval_current(); /* TODO: handle timezone?! */
        boot_time = timeval_current(); /* TODO: fix me */
 
-       io->out._pad            = 0;
-       io->out.unknown2        = 0x06;
-       ZERO_STRUCT(io->out.sessid);
-       io->out.unknown3        = 0x0d;
-       io->out.unknown4        = 0x00;
-       io->out.unknown5        = 0x01;
-       io->out.unknown6        = 0x01;
-       io->out.unknown7        = 0x01;
-       io->out.current_time    = timeval_to_nttime(&current_time);
-       io->out.boot_time       = timeval_to_nttime(&boot_time);
+       ZERO_STRUCT(io->out);
+       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, 
+                                                  "smb2", "max transaction size", 0x10000);
+       io->out.max_read_size      = lp_parm_ulong(req->smb_conn->lp_ctx, NULL, 
+                                                  "smb2", "max read size", 0x10000);
+       io->out.max_write_size     = lp_parm_ulong(req->smb_conn->lp_ctx, NULL, 
+                                                  "smb2", "max write size", 0x10000);
+       io->out.system_time        = timeval_to_nttime(&current_time);
+       io->out.server_start_time  = timeval_to_nttime(&boot_time);
+       io->out.reserved2          = 0;
        status = smb2srv_negprot_secblob(req, &io->out.secblob);
        NT_STATUS_NOT_OK_RETURN(status);
-       io->out.unknown9        = 0x204d4c20;
 
        return NT_STATUS_OK;
 }
@@ -115,29 +145,36 @@ static NTSTATUS smb2srv_negprot_backend(struct smb2srv_request *req, struct smb2
 static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negprot *io)
 {
        NTSTATUS status;
+       enum ndr_err_code ndr_err;
 
        if (NT_STATUS_IS_ERR(req->status)) {
                smb2srv_send_error(req, req->status); /* TODO: is this correct? */
                return;
        }
 
-       status = smb2srv_setup_reply(req, 0x40, True, io->out.secblob.length);
+       status = smb2srv_setup_reply(req, 0x40, true, io->out.secblob.length);
        if (!NT_STATUS_IS_OK(status)) {
                smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
                talloc_free(req);
                return;
        }
 
-       SSVAL(req->out.body, 0x02, io->out._pad);
-       SIVAL(req->out.body, 0x04, io->out.unknown2);
-       memcpy(req->out.body+0x08, io->out.sessid, 16);
-       SIVAL(req->out.body, 0x18, io->out.unknown3);
-       SSVAL(req->out.body, 0x1C, io->out.unknown4);
-       SIVAL(req->out.body, 0x1E, io->out.unknown5);
-       SIVAL(req->out.body, 0x22, io->out.unknown6);
-       SSVAL(req->out.body, 0x26, io->out.unknown7);
-       push_nttime(req->out.body, 0x28, io->out.current_time);
-       push_nttime(req->out.body, 0x30, io->out.boot_time);
+       SSVAL(req->out.body, 0x02, io->out.security_mode);
+       SIVAL(req->out.body, 0x04, io->out.dialect_revision);
+       SIVAL(req->out.body, 0x06, io->out.reserved);
+       ndr_err = smbcli_push_guid(req->out.body, 0x08, &io->out.server_guid);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
+               talloc_free(req);
+               return;
+       }
+       SIVAL(req->out.body, 0x18, io->out.capabilities);
+       SIVAL(req->out.body, 0x1C, io->out.max_transact_size);
+       SIVAL(req->out.body, 0x20, io->out.max_read_size);
+       SIVAL(req->out.body, 0x24, io->out.max_write_size);
+       push_nttime(req->out.body, 0x28, io->out.system_time);
+       push_nttime(req->out.body, 0x30, io->out.server_start_time);
+       SIVAL(req->out.body, 0x3C, io->out.reserved2);
        status = smb2_push_o16s16_blob(&req->out, 0x38, io->out.secblob);
        if (!NT_STATUS_IS_OK(status)) {
                smbsrv_terminate_connection(req->smb_conn, nt_errstr(status));
@@ -145,14 +182,14 @@ static void smb2srv_negprot_send(struct smb2srv_request *req, struct smb2_negpro
                return;
        }
 
-       SIVAL(req->out.body, 0x3C, io->out.unknown9);
-
        smb2srv_send_reply(req);
 }
 
 void smb2srv_negprot_recv(struct smb2srv_request *req)
 {
        struct smb2_negprot *io;
+       int i;
+       enum ndr_err_code ndr_err;
 
        if (req->in.body_size < 0x26) {
                smb2srv_send_error(req,  NT_STATUS_FOOBAR);
@@ -166,9 +203,27 @@ void smb2srv_negprot_recv(struct smb2srv_request *req)
                return;
        }
 
-       io->in.unknown1 = SVAL(req->in.body, 0x02);
-       memcpy(io->in.unknown2, req->in.body + 0x04, 0x20);
-       io->in.unknown3 = SVAL(req->in.body, 0x24);
+       io->in.dialect_count = SVAL(req->in.body, 0x02);
+       io->in.security_mode = SVAL(req->in.body, 0x04);
+       io->in.reserved      = SVAL(req->in.body, 0x06);
+       io->in.capabilities  = IVAL(req->in.body, 0x08);
+       ndr_err = smbcli_pull_guid(req->in.body, 0xC, &io->in.client_guid);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_FOOBAR));
+               talloc_free(req);
+               return;
+       }
+       io->in.start_time = smbcli_pull_nttime(req->in.body, 0x1C);
+
+       io->in.dialects = talloc_array(req, uint16_t, io->in.dialect_count);
+       if (io->in.dialects == NULL) {
+               smbsrv_terminate_connection(req->smb_conn, nt_errstr(NT_STATUS_NO_MEMORY));
+               talloc_free(req);
+               return;
+       }
+       for (i=0;i<io->in.dialect_count;i++) {
+               io->in.dialects[i] = SVAL(req->in.body, 0x24+i*2);
+       }
 
        req->status = smb2srv_negprot_backend(req, io);
 
@@ -180,14 +235,13 @@ void smb2srv_negprot_recv(struct smb2srv_request *req)
 }
 
 /*
- * reply to a SMB negprot request with dialect "SMB 2.001"
+ * reply to a SMB negprot request with dialect "SMB 2.002"
  */
 void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
 {
        struct smb2srv_request *req;
        uint32_t body_fixed_size = 0x26;
 
-       /* create a fake SMB2 negprot request */
        req = talloc_zero(smb_req->smb_conn, struct smb2srv_request);
        if (!req) goto nomem;
        req->smb_conn           = smb_req->smb_conn;
@@ -196,26 +250,28 @@ void smb2srv_reply_smb_negprot(struct smbsrv_request *smb_req)
 
        req->in.size      = NBT_HDR_SIZE+SMB2_HDR_BODY+body_fixed_size;
        req->in.allocated = req->in.size;
-       req->in.buffer    = talloc_size(req, req->in.allocated);
+       req->in.buffer    = talloc_array(req, uint8_t, req->in.allocated);
        if (!req->in.buffer) goto nomem;
        req->in.hdr       = req->in.buffer + NBT_HDR_SIZE;
        req->in.body      = req->in.hdr + SMB2_HDR_BODY;
        req->in.body_size = body_fixed_size;
        req->in.dynamic   = NULL;
 
-       SIVAL(req->in.hdr, 0,                SMB2_MAGIC);
-       SSVAL(req->in.hdr, SMB2_HDR_LENGTH,  SMB2_HDR_BODY);
-       SSVAL(req->in.hdr, SMB2_HDR_PAD1,    0);
-       SIVAL(req->in.hdr, SMB2_HDR_STATUS,  0);
-       SSVAL(req->in.hdr, SMB2_HDR_OPCODE,  SMB2_OP_NEGPROT);
-       SSVAL(req->in.hdr, SMB2_HDR_UNKNOWN1,0);
-       SIVAL(req->in.hdr, SMB2_HDR_FLAGS,   0);
-       SIVAL(req->in.hdr, SMB2_HDR_UNKNOWN2,0);
-       SBVAL(req->in.hdr, SMB2_HDR_SEQNUM,  0);
-       SIVAL(req->in.hdr, SMB2_HDR_PID,     0);
-       SIVAL(req->in.hdr, SMB2_HDR_TID,     0);
-       SBVAL(req->in.hdr, SMB2_HDR_UID,     0);
-       memset(req->in.hdr+SMB2_HDR_SIG, 0, 16);
+       smb2srv_setup_bufinfo(req);
+
+       SIVAL(req->in.hdr, 0,                           SMB2_MAGIC);
+       SSVAL(req->in.hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
+       SSVAL(req->in.hdr, SMB2_HDR_EPOCH,              0);
+       SIVAL(req->in.hdr, SMB2_HDR_STATUS,             0);
+       SSVAL(req->in.hdr, SMB2_HDR_OPCODE,             SMB2_OP_NEGPROT);
+       SSVAL(req->in.hdr, SMB2_HDR_CREDIT,             0);
+       SIVAL(req->in.hdr, SMB2_HDR_FLAGS,              0);
+       SIVAL(req->in.hdr, SMB2_HDR_NEXT_COMMAND,       0);
+       SBVAL(req->in.hdr, SMB2_HDR_MESSAGE_ID,         0);
+       SIVAL(req->in.hdr, SMB2_HDR_PID,                0);
+       SIVAL(req->in.hdr, SMB2_HDR_TID,                0);
+       SBVAL(req->in.hdr, SMB2_HDR_SESSION_ID,         0);
+       memset(req->in.hdr+SMB2_HDR_SIGNATURE, 0, 16);
 
        /* this seems to be a bug, they use 0x24 but the length is 0x26 */
        SSVAL(req->in.body, 0x00, 0x24);