summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Metzmacher <metze@samba.org>2012-05-14 14:24:08 +0200
committerStefan Metzmacher <metze@samba.org>2012-06-25 20:55:06 +0200
commitd2e1058f42ad544dfeebfa80b4695cec6f46f00c (patch)
treeaad7f286e55653d617109d30f8353621ba3031b9
parentf3c606b13178c56bd82aaef2a3c022d2bf8b195b (diff)
downloadsamba-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.c49
-rw-r--r--source3/smbd/smb2_sesssetup.c86
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;