TODO anon? s3:smb3_sesssetup: close the previous SMB2 session if requested and allowed
[metze/samba/wip.git] / source3 / smbd / smb2_sesssetup.c
index 4d35399876f33f5a8fcc827626b2334b0fa3052a..bf7001938a57abe3c004d32f50511a1537092985 100644 (file)
@@ -304,6 +304,44 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
        session->global->auth_session_info_seqnum += 1;
        session->global->channels[0].auth_session_info_seqnum =
                session->global->auth_session_info_seqnum;
+       session->global->expiration_time = gensec_expire_time(session->gensec);
+
+       if ((in_previous_session_id != 0) &&
+            (session->global->session_wire_id !=
+             in_previous_session_id))
+       {
+               struct tevent_context *ev;
+               struct tevent_req *subreq;
+               bool ok;
+
+               ev = event_context_init(talloc_tos());
+               if (ev == NULL) {
+                       TALLOC_FREE(session);
+                       return NT_STATUS_LOGON_FAILURE;
+               }
+
+               subreq = smb2srv_session_close_previous_send(smb2req, ev,
+                                                            session,
+                                                            in_previous_session_id);
+               if (subreq == NULL) {
+                       TALLOC_FREE(session);
+                       return NT_STATUS_LOGON_FAILURE;
+               }
+
+               ok = tevent_req_poll_ntstatus(subreq, ev, &status);
+               if (!ok) {
+                       TALLOC_FREE(subreq);
+                       TALLOC_FREE(session);
+                       return status;
+               }
+
+               status = smb2srv_session_close_previous_recv(subreq);
+               TALLOC_FREE(subreq);
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(session);
+                       return status;
+               }
+       }
 
        status = smbXsrv_session_update(session);
        if (!NT_STATUS_IS_OK(status)) {
@@ -329,6 +367,76 @@ static NTSTATUS smbd_smb2_auth_generic_return(struct smbXsrv_session *session,
        return NT_STATUS_OK;
 }
 
+static NTSTATUS smbd_smb2_reauth_generic_return(struct smbXsrv_session *session,
+                                       struct smbd_smb2_request *smb2req,
+                                       uint16_t *out_session_flags,
+                                       uint64_t *out_session_id)
+{
+       NTSTATUS status;
+       struct smbXsrv_session *x = session;
+       struct auth_session_info *session_info;
+       struct smbXsrv_connection *conn = session->connection;
+
+       status = gensec_session_info(session->gensec,
+                                    session->global,
+                                    &session_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(session);
+               return status;
+       }
+
+       data_blob_clear_free(&session_info->session_key);
+       session_info->session_key = data_blob_dup_talloc(session_info,
+                                               x->global->application_key);
+       if (session_info->session_key.data == NULL) {
+               TALLOC_FREE(session);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       session->compat->session_info = session_info;
+       session->compat->vuid = session->global->session_wire_id;
+
+       session->compat->homes_snum =
+                       register_homes_share(session_info->unix_info->unix_name);
+
+       set_current_user_info(session_info->unix_info->sanitized_username,
+                             session_info->unix_info->unix_name,
+                             session_info->info->domain_name);
+
+       reload_services(smb2req->sconn, conn_snum_used, true);
+
+       session->status = NT_STATUS_OK;
+       TALLOC_FREE(session->global->auth_session_info);
+       session->global->auth_session_info = session->session_info;
+       session->global->auth_session_info_seqnum += 1;
+       session->global->channels[0].auth_session_info_seqnum =
+               session->global->auth_session_info_seqnum;
+       session->global->expiration_time = gensec_expire_time(session->gensec);
+
+       status = smbXsrv_session_update(session);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("smb2: Failed to update session for vuid=%d - %s\n",
+                       session->compat->vuid, nt_errstr(status)));
+               TALLOC_FREE(session);
+               return NT_STATUS_LOGON_FAILURE;
+       }
+
+       conn_clear_vuid_caches(conn->sconn, session->compat->vuid);
+
+       /*
+        * we attach the session to the request
+        * so that the response can be signed
+        */
+       smb2req->session = session;
+       smb2req->do_signing = true;
+
+       global_client_caps |= (CAP_LEVEL_II_OPLOCKS|CAP_STATUS32);
+
+       *out_session_id = session->global->session_wire_id;
+
+       return NT_STATUS_OK;
+}
+
 static NTSTATUS smbd_smb2_auth_generic(struct smbXsrv_session *session,
                                       struct smbd_smb2_request *smb2req,
                                       uint8_t in_security_mode,
@@ -379,6 +487,13 @@ static NTSTATUS smbd_smb2_auth_generic(struct smbXsrv_session *session,
                return status;
        }
 
+       if (session->global->auth_session_info != NULL) {
+               return smbd_smb2_reauth_generic_return(session,
+                                                      smb2req,
+                                                      out_session_flags,
+                                                      out_session_id);
+       }
+
        return smbd_smb2_auth_generic_return(session,
                                             smb2req,
                                             in_security_mode,
@@ -416,8 +531,13 @@ static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
                status = smb2srv_session_lookup(smb2req->sconn->conn,
                                                in_session_id, now,
                                                &session);
+               if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
+                       status = NT_STATUS_OK;
+               }
                if (NT_STATUS_IS_OK(status)) {
-                       return NT_STATUS_REQUEST_NOT_ACCEPTED;
+                       session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+                       status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+                       TALLOC_FREE(session->gensec);
                }
                if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
                        return status;