s3:smb2_negprot: add support for PROTOCOL_SMB2_24
[mat/samba.git] / source3 / smbd / smb2_negprot.c
index 5b97c65d79c383b363094d83821dd1485d8f3f95..4cae143d75a5ba587e537e02ef39851f11b9050c 100644 (file)
 */
 
 #include "includes.h"
+#include "smbd/smbd.h"
 #include "smbd/globals.h"
 #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;
@@ -50,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;
@@ -68,28 +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 = 0;
        uint32_t capabilities;
-
-/* 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);
+       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();
+
+       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,36 +118,105 @@ 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 == SMB2_DIALECT_REVISION_224) {
+                       protocol = PROTOCOL_SMB2_24;
+                       break;
+               }
+       }
+
+       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;
+               }
+       }
+
+       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;
                }
        }
 
-       if (dialect != SMB2_DIALECT_REVISION_202) {
-               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_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);
        }
 
-       set_Protocol(PROTOCOL_SMB2);
+       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() == Required) {
+       if (lp_server_signing() == SMB_SIGNING_REQUIRED) {
                security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
        }
 
@@ -139,6 +225,16 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
                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
@@ -164,9 +260,9 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
               negprot_spnego_blob.data, 16);   /* server guid */
        SIVAL(outbody.data, 0x18,
              capabilities);                    /* 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, 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,
@@ -177,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);
 }