CVE-2016-2114: s3:smbd: use the correct default values for "smb signing"
[samba.git] / source3 / smbd / smb2_negprot.c
index 18382a9dc1a54c0bbcd45123f6c4d871dad65936..9c03b2ca8b86158db1814aff4c7dc828dd253c8b 100644 (file)
@@ -25,6 +25,7 @@
 #include "../libcli/smb/smb2_negotiate_context.h"
 #include "../lib/tsocket/tsocket.h"
 #include "../librpc/ndr/libndr.h"
+#include "../libcli/smb/smb_signing.h"
 
 extern fstring remote_proto;
 
@@ -60,7 +61,7 @@ static void reply_smb20xx(struct smb_request *req, uint16_t dialect)
 
        req->outbuf = NULL;
 
-       smbd_smb2_first_negprot(req->xconn, smb2_inpdu, len);
+       smbd_smb2_process_negprot(req->xconn, 0, smb2_inpdu, len);
        return;
 }
 
@@ -160,6 +161,7 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
        uint32_t max_read = lp_smb2_max_read();
        uint32_t max_write = lp_smb2_max_write();
        NTTIME now = timeval_to_nttime(&req->request_time);
+       bool signing_required = true;
 
        status = smbd_smb2_request_verify_sizes(req, 0x24);
        if (!NT_STATUS_IS_OK(status)) {
@@ -258,8 +260,15 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
                }
        }
 
-       if (get_remote_arch() != RA_SAMBA) {
+       switch (get_remote_arch()) {
+       case RA_VISTA:
+       case RA_SAMBA:
+       case RA_CIFSFS:
+       case RA_OSX:
+               break;
+       default:
                set_remote_arch(RA_VISTA);
+               break;
        }
 
        fstr_sprintf(remote_proto, "SMB%X_%02X",
@@ -287,7 +296,13 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
        }
 
        security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
-       if (lp_server_signing() == SMB_SIGNING_REQUIRED) {
+       /*
+        * We use xconn->smb1.signing_state as that's already present
+        * and used lpcfg_server_signing_allowed() to get the correct
+        * defaults, e.g. signing_required for an ad_dc.
+        */
+       signing_required = smb_signing_is_mandatory(xconn->smb1.signing_state);
+       if (signing_required) {
                security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
        }
 
@@ -485,6 +500,14 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
                xconn->smb2.server.cipher = SMB2_ENCRYPTION_AES128_CCM;
        }
 
+       if (protocol >= PROTOCOL_SMB2_22 &&
+           xconn->client->server_multi_channel_enabled)
+       {
+               if (in_capabilities & SMB2_CAP_MULTI_CHANNEL) {
+                       capabilities |= SMB2_CAP_MULTI_CHANNEL;
+               }
+       }
+
        security_offset = SMB2_HDR_BODY + 0x40;
 
 #if 1
@@ -579,6 +602,8 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
        req->sconn->using_smb2 = true;
 
        if (dialect != SMB2_DIALECT_REVISION_2FF) {
+               struct smbXsrv_client_global0 *global0 = NULL;
+
                status = smbXsrv_connection_init_tables(xconn, protocol);
                if (!NT_STATUS_IS_OK(status)) {
                        return smbd_smb2_request_error(req, status);
@@ -605,6 +630,62 @@ NTSTATUS smbd_smb2_request_process_negprot(struct smbd_smb2_request *req)
                xconn->smb2.server.max_trans = max_trans;
                xconn->smb2.server.max_read  = max_read;
                xconn->smb2.server.max_write = max_write;
+
+               if (xconn->protocol < PROTOCOL_SMB2_10) {
+                       /*
+                        * SMB2_02 doesn't support client guids
+                        */
+                       return smbd_smb2_request_done(req, outbody, &outdyn);
+               }
+
+               if (!xconn->client->server_multi_channel_enabled) {
+                       /*
+                        * Only deal with the client guid database
+                        * if multi-channel is enabled.
+                        */
+                       return smbd_smb2_request_done(req, outbody, &outdyn);
+               }
+
+               if (xconn->smb2.client.guid_verified) {
+                       /*
+                        * The connection was passed from another
+                        * smbd process.
+                        */
+                       return smbd_smb2_request_done(req, outbody, &outdyn);
+               }
+
+               status = smb2srv_client_lookup_global(xconn->client,
+                                               xconn->smb2.client.guid,
+                                               req, &global0);
+               /*
+                * TODO: check for races...
+                */
+               if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECTID_NOT_FOUND)) {
+                       /*
+                        * This stores the new client information in
+                        * smbXsrv_client_global.tdb
+                        */
+                       xconn->client->global->client_guid =
+                                               xconn->smb2.client.guid;
+                       status = smbXsrv_client_update(xconn->client);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return status;
+                       }
+
+                       xconn->smb2.client.guid_verified = true;
+               } else if (NT_STATUS_IS_OK(status)) {
+                       status = smb2srv_client_connection_pass(req,
+                                                               global0);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               return smbd_smb2_request_error(req, status);
+                       }
+
+                       smbd_server_connection_terminate(xconn,
+                                                        "passed connection");
+                       return NT_STATUS_OBJECTID_EXISTS;
+               } else {
+                       return smbd_smb2_request_error(req, status);
+               }
        }
 
        return smbd_smb2_request_done(req, outbody, &outdyn);