smbd:smb2_negprot: implement connection passing based on client_guid
authorMichael Adam <obnox@samba.org>
Tue, 26 Jan 2016 09:12:46 +0000 (10:12 +0100)
committerMichael Adam <obnox@samba.org>
Tue, 26 Jan 2016 14:58:11 +0000 (15:58 +0100)
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Michael Adam <obnox@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
source3/smbd/smb2_negprot.c

index 158207225a032a4902f341ebcc134bb9981b3a8b..0bb13bcd63668353ed72f8f478eda96bad28bf07 100644 (file)
@@ -587,6 +587,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);
@@ -613,6 +615,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);