diff options
author | Stefan Metzmacher <metze@samba.org> | 2012-05-14 14:24:08 +0200 |
---|---|---|
committer | Stefan Metzmacher <metze@samba.org> | 2012-06-25 20:55:06 +0200 |
commit | d2e1058f42ad544dfeebfa80b4695cec6f46f00c (patch) | |
tree | aad7f286e55653d617109d30f8353621ba3031b9 | |
parent | f3c606b13178c56bd82aaef2a3c022d2bf8b195b (diff) | |
download | samba-d2e1058f42ad544dfeebfa80b4695cec6f46f00c.tar.gz samba-d2e1058f42ad544dfeebfa80b4695cec6f46f00c.tar.bz2 samba-d2e1058f42ad544dfeebfa80b4695cec6f46f00c.zip |
s3:smb2_sesssetup: implement dynamic re-authentication and expire sessions
metze
-rw-r--r-- | source3/smbd/smb2_server.c | 49 | ||||
-rw-r--r-- | source3/smbd/smb2_sesssetup.c | 86 |
2 files changed, 129 insertions, 6 deletions
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c index a3d7c2c506..de43bcfa38 100644 --- a/source3/smbd/smb2_server.c +++ b/source3/smbd/smb2_server.c @@ -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); } diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c index dc01fc38bd..5188838a16 100644 --- a/source3/smbd/smb2_sesssetup.c +++ b/source3/smbd/smb2_sesssetup.c @@ -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; |