s3:smb2_negprot: announce support for SMB2.1 leases.
[kamenim/samba-autobuild/.git] / source3 / smbd / smb2_negprot.c
index feb5a4d6272ad87e3ac733848f87defa4b2ec6b2..9a1ca9c22e33e2885ad2587705f14a50747de011 100644 (file)
@@ -33,19 +33,19 @@ extern fstring remote_proto;
  */
 static void reply_smb20xx(struct smb_request *req, uint16_t dialect)
 {
-       uint8_t *smb2_inbuf;
+       uint8_t *smb2_inpdu;
        uint8_t *smb2_hdr;
        uint8_t *smb2_body;
        uint8_t *smb2_dyn;
-       size_t len = 4 + SMB2_HDR_BODY + 0x24 + 2;
+       size_t len = SMB2_HDR_BODY + 0x24 + 2;
 
-       smb2_inbuf = talloc_zero_array(talloc_tos(), uint8_t, len);
-       if (smb2_inbuf == NULL) {
+       smb2_inpdu = talloc_zero_array(talloc_tos(), uint8_t, len);
+       if (smb2_inpdu == NULL) {
                DEBUG(0, ("Could not push spnego blob\n"));
                reply_nterror(req, NT_STATUS_NO_MEMORY);
                return;
        }
-       smb2_hdr = smb2_inbuf + 4;
+       smb2_hdr = smb2_inpdu;
        smb2_body = smb2_hdr + SMB2_HDR_BODY;
        smb2_dyn = smb2_body + 0x24;
 
@@ -59,7 +59,7 @@ static void reply_smb20xx(struct smb_request *req, uint16_t dialect)
 
        req->outbuf = NULL;
 
-       smbd_smb2_first_negprot(req->xconn, smb2_inbuf, len);
+       smbd_smb2_first_negprot(req->xconn, smb2_inpdu, len);
        return;
 }
 
@@ -87,85 +87,37 @@ enum protocol_types smbd_smb2_protocol_dialect_match(const uint8_t *indyn,
                                const int dialect_count,
                                uint16_t *dialect)
 {
-       size_t c = 0;
-       enum protocol_types protocol = PROTOCOL_NONE;
-
-       for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
-               if (lp_server_max_protocol() < PROTOCOL_SMB3_00) {
-                       break;
-               }
-               if (lp_server_min_protocol() > PROTOCOL_SMB3_00) {
-                       break;
-               }
-
-               *dialect = SVAL(indyn, c*2);
-               if (*dialect == SMB3_DIALECT_REVISION_300) {
-                       protocol = PROTOCOL_SMB3_00;
-                       break;
-               }
-       }
-
-       for (c=0; protocol == PROTOCOL_NONE && c < dialect_count; c++) {
-               if (lp_server_max_protocol() < PROTOCOL_SMB2_24) {
-                       break;
-               }
-               if (lp_server_min_protocol() > 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_server_max_protocol() < PROTOCOL_SMB2_22) {
-                       break;
-               }
-               if (lp_server_min_protocol() > PROTOCOL_SMB2_22) {
-                       break;
+       struct {
+               enum protocol_types proto;
+               uint16_t dialect;
+       } pd[] = {
+               { PROTOCOL_SMB3_00, SMB3_DIALECT_REVISION_300 },
+               { PROTOCOL_SMB2_24, SMB2_DIALECT_REVISION_224 },
+               { PROTOCOL_SMB2_22, SMB2_DIALECT_REVISION_222 },
+               { PROTOCOL_SMB2_10, SMB2_DIALECT_REVISION_210 },
+               { PROTOCOL_SMB2_02, SMB2_DIALECT_REVISION_202 },
+       };
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(pd); i ++) {
+               size_t c = 0;
+
+               if (lp_server_max_protocol() < pd[i].proto) {
+                       continue;
                }
-
-               *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_server_max_protocol() < PROTOCOL_SMB2_10) {
-                       break;
-               }
-               if (lp_server_min_protocol() > 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_server_max_protocol() < PROTOCOL_SMB2_02) {
-                       break;
-               }
-               if (lp_server_min_protocol() > PROTOCOL_SMB2_02) {
-                       break;
+               if (lp_server_min_protocol() > pd[i].proto) {
+                       continue;
                }
 
-               *dialect = SVAL(indyn, c*2);
-               if (*dialect == SMB2_DIALECT_REVISION_202) {
-                       protocol = PROTOCOL_SMB2_02;
-                       break;
+               for (c = 0; c < dialect_count; c++) {
+                       *dialect = SVAL(indyn, c*2);
+                       if (*dialect == pd[i].dialect) {
+                               return pd[i].proto;
+                       }
                }
        }
 
-       return protocol;
+       return PROTOCOL_NONE;
 }
 
 NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
@@ -259,7 +211,7 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
        DEBUG(3,("Selected protocol %s\n", remote_proto));
 
        /* negprot_spnego() returns a the server guid in the first 16 bytes */
-       negprot_spnego_blob = negprot_spnego(req, req->sconn);
+       negprot_spnego_blob = negprot_spnego(req, xconn);
        if (negprot_spnego_blob.data == NULL) {
                return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
        }
@@ -278,6 +230,14 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
                capabilities |= SMB2_CAP_DFS;
        }
 
+       if (protocol >= PROTOCOL_SMB2_10 &&
+           lp_smb2_leases() &&
+           lp_oplocks(GLOBAL_SECTION_SNUM) &&
+           !lp_kernel_oplocks(GLOBAL_SECTION_SNUM))
+       {
+               capabilities |= SMB2_CAP_LEASING;
+       }
+
        if ((protocol >= PROTOCOL_SMB2_24) &&
            (lp_smb_encrypt(-1) != SMB_SIGNING_OFF) &&
            (in_capabilities & SMB2_CAP_ENCRYPTION)) {
@@ -302,8 +262,13 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
                        capabilities |= SMB2_CAP_LARGE_MTU;
                        xconn->smb2.credits.multicredit = true;
 
-                       /* Windows 2012R2 allows up to 8 MB */
-                       max_limit = 0x800000; /* 8MB */
+                       /*
+                        * We allow up to allmost 16MB.
+                        *
+                        * The maximum PDU size is 0xFFFFFF (16776960)
+                        * and we need some space for the header.
+                        */
+                       max_limit = 0xFFFF00;
                }
        }
 
@@ -319,6 +284,10 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
        max_read = MIN(max_limit, lp_smb2_max_read());
        max_write = MIN(max_limit, lp_smb2_max_write());
 
+       if (capabilities & SMB2_CAP_ENCRYPTION) {
+               xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM;
+       }
+
        security_offset = SMB2_HDR_BODY + 0x40;
 
 #if 1