s3:smb2_sesssetup: implement dynamic re-authentication and expire sessions
authorStefan Metzmacher <metze@samba.org>
Mon, 14 May 2012 12:24:08 +0000 (14:24 +0200)
committerStefan Metzmacher <metze@samba.org>
Mon, 25 Jun 2012 18:55:06 +0000 (20:55 +0200)
metze

source3/smbd/smb2_server.c
source3/smbd/smb2_sesssetup.c

index a3d7c2c506967d155ef54ea0a0b9b3d096a555e3..de43bcfa38e53cfc74b31d971cfcf5869266dd93 100644 (file)
@@ -1247,8 +1247,9 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
        const uint8_t *inhdr;
        int i = req->current_idx;
        uint32_t in_flags;
+       uint16_t in_opcode;
        uint64_t in_session_id;
-       struct smbXsrv_session *session;
+       struct smbXsrv_session *session = NULL;
        struct auth_session_info *session_info;
        NTSTATUS status;
        NTTIME now = timeval_to_nttime(&req->request_time);
@@ -1259,6 +1260,7 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
        inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
 
        in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
+       in_opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
        in_session_id = BVAL(inhdr, SMB2_HDR_SESSION_ID);
 
        if (in_flags & SMB2_HDR_FLAG_CHAINED) {
@@ -1269,6 +1271,36 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
        status = smb2srv_session_lookup(req->sconn->conn,
                                        in_session_id, now,
                                        &session);
+       if (session) {
+               req->session = session;
+               req->last_session_id = in_session_id;
+       }
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
+               switch (in_opcode) {
+               case SMB2_OP_SESSSETUP:
+                       status = NT_STATUS_OK;
+                       break;
+               default:
+                       break;
+               }
+       }
+       if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+               switch (in_opcode) {
+               case SMB2_OP_TCON:
+               case SMB2_OP_CREATE:
+               case SMB2_OP_GETINFO:
+               case SMB2_OP_SETINFO:
+                       return NT_STATUS_INVALID_HANDLE;
+               default:
+                       /*
+                        * Notice the check for
+                        * (session_info == NULL)
+                        * below.
+                        */
+                       status = NT_STATUS_OK;
+                       break;
+               }
+       }
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -1282,9 +1314,6 @@ static NTSTATUS smbd_smb2_request_check_session(struct smbd_smb2_request *req)
                              session_info->unix_info->unix_name,
                              session_info->info->domain_name);
 
-       req->session = session;
-       req->last_session_id = in_session_id;
-
        return NT_STATUS_OK;
 }
 
@@ -1394,6 +1423,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
        uint32_t allowed_flags;
        NTSTATUS return_value;
        struct smbXsrv_session *x = NULL;
+       bool signing_required = false;
 
        inhdr = (const uint8_t *)req->in.vector[i].iov_base;
 
@@ -1447,6 +1477,15 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
        session_status = smbd_smb2_request_check_session(req);
        x = req->session;
 
+       if (x != NULL) {
+               signing_required = x->global->signing_required;
+
+               if (opcode == SMB2_OP_SESSSETUP &&
+                   x->global->channels[0].signing_key.length) {
+                       signing_required = true;
+               }
+       }
+
        req->do_signing = false;
        if (flags & SMB2_HDR_FLAG_SIGNED) {
                struct smbXsrv_connection *conn = x->connection;
@@ -1465,7 +1504,7 @@ NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
                }
        } else if (opcode == SMB2_OP_CANCEL) {
                /* Cancel requests are allowed to skip the signing */
-       } else if (x && x->global->signing_required) {
+       } else if (signing_required) {
                return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
        }
 
index dc01fc38bd87b3472db9ac5eadd16347be2cd42d..5188838a1697e9508114ac17160f5d146338139c 100644 (file)
@@ -305,6 +305,7 @@ 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);
 
        status = smbXsrv_session_update(session);
        if (!NT_STATUS_IS_OK(status)) {
@@ -331,6 +332,77 @@ 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_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=%llu - %s\n",
+                         (unsigned long long)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,
@@ -381,6 +453,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,
@@ -418,8 +497,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;