s3:smb2_negprot: add support for PROTOCOL_SMB2_24
[mat/samba.git] / source3 / smbd / smb2_negprot.c
index 38dfe6dab3a26c178262d2363329729dd1aafa83..4cae143d75a5ba587e537e02ef39851f11b9050c 100644 (file)
 */
 
 #include "includes.h"
+#include "smbd/smbd.h"
 #include "smbd/globals.h"
-#include "../source4/libcli/smb2/smb2_constants.h"
-
-extern enum protocol_types Protocol;
+#include "../libcli/smb/smb_common.h"
 
 /*
  * this is the entry point if SMB2 is selected via
- * the SMB negprot
+ * the SMB negprot and the given dialect.
  */
-void reply_smb2002(struct smb_request *req, uint16_t choice)
+static void reply_smb20xx(struct smb_request *req, uint16_t dialect)
 {
        uint8_t *smb2_inbuf;
        uint8_t *smb2_hdr;
@@ -52,16 +51,36 @@ void reply_smb2002(struct smb_request *req, uint16_t choice)
        SSVAL(smb2_body, 0x00, 0x0024); /* struct size */
        SSVAL(smb2_body, 0x02, 0x0001); /* dialect count */
 
-       SSVAL(smb2_dyn,  0x00, 0x0202); /* dialect 2.002 */
+       SSVAL(smb2_dyn,  0x00, dialect);
 
        req->outbuf = NULL;
 
-       smbd_smb2_first_negprot(smbd_server_conn, smb2_inbuf, len);
+       smbd_smb2_first_negprot(req->sconn, smb2_inbuf, len);
        return;
 }
 
+/*
+ * this is the entry point if SMB2 is selected via
+ * the SMB negprot and the "SMB 2.002" dialect.
+ */
+void reply_smb2002(struct smb_request *req, uint16_t choice)
+{
+       reply_smb20xx(req, SMB2_DIALECT_REVISION_202);
+}
+
+/*
+ * this is the entry point if SMB2 is selected via
+ * the SMB negprot and the "SMB 2.???" dialect.
+ */
+void reply_smb20ff(struct smb_request *req, uint16_t choice)
+{
+       req->sconn->smb2.negprot_2ff = true;
+       reply_smb20xx(req, SMB2_DIALECT_REVISION_2FF);
+}
+
 NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
 {
+       NTSTATUS status;
        const uint8_t *inbody;
        const uint8_t *indyn = NULL;
        int i = req->current_idx;
@@ -70,26 +89,24 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
        DATA_BLOB negprot_spnego_blob;
        uint16_t security_offset;
        DATA_BLOB security_buffer;
-       size_t expected_body_size = 0x24;
-       size_t body_size;
        size_t expected_dyn_size = 0;
        size_t c;
+       uint16_t security_mode;
        uint16_t dialect_count;
-       uint16_t dialect;
+       uint16_t dialect = 0;
+       uint32_t capabilities;
+       enum protocol_types protocol = PROTOCOL_NONE;
+       uint32_t max_limit;
+       uint32_t max_trans = lp_smb2_max_trans();
+       uint32_t max_read = lp_smb2_max_read();
+       uint32_t max_write = lp_smb2_max_write();
 
-/* TODO: drop the connection with INVALI_PARAMETER */
-
-       if (req->in.vector[i+1].iov_len != (expected_body_size & 0xFFFFFFFE)) {
-               return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+       status = smbd_smb2_request_verify_sizes(req, 0x24);
+       if (!NT_STATUS_IS_OK(status)) {
+               return smbd_smb2_request_error(req, status);
        }
-
        inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
 
-       body_size = SVAL(inbody, 0x00);
-       if (body_size != expected_body_size) {
-               return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
-       }
-
        dialect_count = SVAL(inbody, 0x02);
        if (dialect_count == 0) {
                return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
@@ -101,37 +118,133 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
        }
        indyn = (const uint8_t *)req->in.vector[i+2].iov_base;
 
-       for (c=0; c < dialect_count; c++) {
+       for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
+               if (lp_maxprotocol() < PROTOCOL_SMB2_24) {
+                       break;
+               }
+               if (lp_minprotocol() > PROTOCOL_SMB2_24) {
+                       break;
+               }
+
                dialect = SVAL(indyn, c*2);
-               if (dialect == 0x0202) {
+               if (dialect == SMB2_DIALECT_REVISION_224) {
+                       protocol = PROTOCOL_SMB2_24;
                        break;
                }
        }
 
-       if (dialect != 0x0202) {
-               return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
+       for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
+               if (lp_maxprotocol() < PROTOCOL_SMB2_22) {
+                       break;
+               }
+               if (lp_minprotocol() > PROTOCOL_SMB2_22) {
+                       break;
+               }
+
+               dialect = SVAL(indyn, c*2);
+               if (dialect == SMB2_DIALECT_REVISION_222) {
+                       protocol = PROTOCOL_SMB2_22;
+                       break;
+               }
        }
 
-       Protocol = PROTOCOL_SMB2;
+       for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
+               if (lp_maxprotocol() < PROTOCOL_SMB2_10) {
+                       break;
+               }
+               if (lp_minprotocol() > PROTOCOL_SMB2_10) {
+                       break;
+               }
+
+               dialect = SVAL(indyn, c*2);
+               if (dialect == SMB2_DIALECT_REVISION_210) {
+                       protocol = PROTOCOL_SMB2_10;
+                       break;
+               }
+       }
+
+       for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
+               if (lp_maxprotocol() < PROTOCOL_SMB2_02) {
+                       break;
+               }
+               if (lp_minprotocol() > PROTOCOL_SMB2_02) {
+                       break;
+               }
+
+               dialect = SVAL(indyn, c*2);
+               if (dialect == SMB2_DIALECT_REVISION_202) {
+                       protocol = PROTOCOL_SMB2_02;
+                       break;
+               }
+       }
+
+       for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
+               if (lp_maxprotocol() < PROTOCOL_SMB2_10) {
+                       break;
+               }
+
+               dialect = SVAL(indyn, c*2);
+               if (dialect == SMB2_DIALECT_REVISION_2FF) {
+                       if (req->sconn->smb2.negprot_2ff) {
+                               req->sconn->smb2.negprot_2ff = false;
+                               protocol = PROTOCOL_SMB2_10;
+                               break;
+                       }
+               }
+       }
+
+       if (protocol == PROTOCOL_NONE) {
+               return smbd_smb2_request_error(req, NT_STATUS_NOT_SUPPORTED);
+       }
+
+       if (dialect != SMB2_DIALECT_REVISION_2FF) {
+               set_Protocol(protocol);
+       }
 
        if (get_remote_arch() != RA_SAMBA) {
                set_remote_arch(RA_VISTA);
        }
 
        /* negprot_spnego() returns a the server guid in the first 16 bytes */
-       negprot_spnego_blob = negprot_spnego();
+       negprot_spnego_blob = negprot_spnego(req, req->sconn);
        if (negprot_spnego_blob.data == NULL) {
                return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
        }
-       talloc_steal(req, negprot_spnego_blob.data);
 
        if (negprot_spnego_blob.length < 16) {
                return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
        }
 
+       security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
+       if (lp_server_signing() == SMB_SIGNING_REQUIRED) {
+               security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
+       }
+
+       capabilities = 0;
+       if (lp_host_msdfs()) {
+               capabilities |= SMB2_CAP_DFS;
+       }
+
+       /*
+        * Unless we implement SMB2_CAP_LARGE_MTU,
+        * 0x10000 (65536) is the maximum allowed message size
+        */
+       max_limit = 0x10000;
+
+       max_trans = MIN(max_limit, max_trans);
+       max_read  = MIN(max_limit, max_read);
+       max_write = MIN(max_limit, max_write);
+
        security_offset = SMB2_HDR_BODY + 0x40;
+
+#if 1
+       /* Try SPNEGO auth... */
        security_buffer = data_blob_const(negprot_spnego_blob.data + 16,
                                          negprot_spnego_blob.length - 16);
+#else
+       /* for now we want raw NTLMSSP */
+       security_buffer = data_blob_const(NULL, 0);
+#endif
 
        outbody = data_blob_talloc(req->out.vector, NULL, 0x40);
        if (outbody.data == NULL) {
@@ -139,16 +252,17 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
        }
 
        SSVAL(outbody.data, 0x00, 0x40 + 1);    /* struct size */
-/*TODO: indicate signing enabled */
-       SSVAL(outbody.data, 0x02, 0);           /* security mode */
+       SSVAL(outbody.data, 0x02,
+             security_mode);                   /* security mode */
        SSVAL(outbody.data, 0x04, dialect);     /* dialect revision */
        SSVAL(outbody.data, 0x06, 0);           /* reserved */
        memcpy(outbody.data + 0x08,
               negprot_spnego_blob.data, 16);   /* server guid */
-       SIVAL(outbody.data, 0x18, 0);           /* capabilities */
-       SIVAL(outbody.data, 0x1C, 0x00010000);  /* max transact size */
-       SIVAL(outbody.data, 0x20, 0x00010000);  /* max read size */
-       SIVAL(outbody.data, 0x24, 0x00010000);  /* max write size */
+       SIVAL(outbody.data, 0x18,
+             capabilities);                    /* capabilities */
+       SIVAL(outbody.data, 0x1C, max_trans);   /* max transact size */
+       SIVAL(outbody.data, 0x20, max_trans);   /* max read size */
+       SIVAL(outbody.data, 0x24, max_trans);   /* max write size */
        SBVAL(outbody.data, 0x28, 0);           /* system time */
        SBVAL(outbody.data, 0x30, 0);           /* server start time */
        SSVAL(outbody.data, 0x38,
@@ -159,5 +273,10 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
 
        outdyn = security_buffer;
 
+       req->sconn->using_smb2 = true;
+       req->sconn->smb2.max_trans = max_trans;
+       req->sconn->smb2.max_read  = max_read;
+       req->sconn->smb2.max_write = max_write;
+
        return smbd_smb2_request_done(req, outbody, &outdyn);
 }