summaryrefslogtreecommitdiff
path: root/source3/smbd/smbXsrv_session.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/smbd/smbXsrv_session.c')
-rw-r--r--source3/smbd/smbXsrv_session.c154
1 files changed, 154 insertions, 0 deletions
diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index 0a8df7ed09..9ae078edc7 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -37,6 +37,7 @@
#include "librpc/gen_ndr/ndr_smbXsrv.h"
#include "serverid.h"
#include "lib/util/tevent_ntstatus.h"
+#include "msg_channel.h"
struct smbXsrv_session_table {
struct {
@@ -48,6 +49,7 @@ struct smbXsrv_session_table {
struct {
struct db_context *db_ctx;
} global;
+ struct msg_channel *close_channel;
};
static struct db_context *smbXsrv_session_global_db_ctx = NULL;
@@ -155,12 +157,16 @@ static NTSTATUS smbXsrv_session_local_key_to_id(TDB_DATA key, uint32_t *id)
return NT_STATUS_OK;
}
+static void smbXsrv_session_close_loop(struct tevent_req *subreq);
+
static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
uint32_t lowest_id,
uint32_t highest_id)
{
struct smbXsrv_session_table *table;
NTSTATUS status;
+ struct tevent_req *subreq;
+ int ret;
table = talloc_zero(conn, struct smbXsrv_session_table);
if (table == NULL) {
@@ -183,10 +189,158 @@ static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
table->global.db_ctx = smbXsrv_session_global_db_ctx;
+ dbwrap_watch_db(table->global.db_ctx, conn->msg_ctx);
+
+ ret = msg_channel_init(table, conn->msg_ctx,
+ MSG_SMBXSRV_SESSION_CLOSE,
+ &table->close_channel);
+ if (ret != 0) {
+ status = map_nt_error_from_unix_common(errno);
+ TALLOC_FREE(table);
+ return status;
+ }
+
+ subreq = msg_read_send(table, conn->ev_ctx, table->close_channel);
+ if (subreq == NULL) {
+ TALLOC_FREE(table);
+ return NT_STATUS_NO_MEMORY;
+ }
+ tevent_req_set_callback(subreq, smbXsrv_session_close_loop, conn);
+
conn->session_table = table;
return NT_STATUS_OK;
}
+static void smbXsrv_session_close_loop(struct tevent_req *subreq)
+{
+ struct smbXsrv_connection *conn =
+ tevent_req_callback_data(subreq,
+ struct smbXsrv_connection);
+ struct smbXsrv_session_table *table = conn->session_table;
+ int ret;
+ struct messaging_rec *rec = NULL;
+ struct smbXsrv_session_closeB close_blob;
+ enum ndr_err_code ndr_err;
+ struct smbXsrv_session_close0 *close_info0 = NULL;
+ struct smbXsrv_session *session = NULL;
+ NTSTATUS status;
+ struct timeval tv = timeval_current();
+ NTTIME now = timeval_to_nttime(&tv);
+
+ ret = msg_read_recv(subreq, talloc_tos(), &rec);
+ TALLOC_FREE(subreq);
+ if (ret != 0) {
+ goto next;
+ }
+
+ ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &close_blob,
+ (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_closeB);
+ if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+ status = ndr_map_error2ntstatus(ndr_err);
+ DEBUG(1,("smbXsrv_session_close_loop: "
+ "ndr_pull_struct_blob - %s\n",
+ nt_errstr(status)));
+ goto next;
+ }
+
+ DEBUG(10,("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n"));
+ if (DEBUGLVL(10)) {
+ NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
+ }
+
+ if (close_blob.version != SMBXSRV_VERSION_0) {
+ DEBUG(0,("smbXsrv_session_close_loop: "
+ "ignore invalid version %u\n", close_blob.version));
+ NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
+ goto next;
+ }
+
+ close_info0 = close_blob.info.info0;
+ if (close_info0 == NULL) {
+ DEBUG(0,("smbXsrv_session_close_loop: "
+ "ignore NULL info %u\n", close_blob.version));
+ NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
+ goto next;
+ }
+
+ status = smb2srv_session_lookup(conn, close_info0->old_session_wire_id,
+ now, &session);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
+ DEBUG(4,("smbXsrv_session_close_loop: "
+ "old_session_wire_id %llu not found\n",
+ (unsigned long long)close_info0->old_session_wire_id));
+ if (DEBUGLVL(4)) {
+ NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
+ }
+ goto next;
+ }
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
+ DEBUG(1,("smbXsrv_session_close_loop: "
+ "old_session_wire_id %llu - %s\n",
+ (unsigned long long)close_info0->old_session_wire_id,
+ nt_errstr(status)));
+ if (DEBUGLVL(1)) {
+ NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
+ }
+ goto next;
+ }
+
+ if (session->global->session_global_id != close_info0->old_session_global_id) {
+ DEBUG(1,("smbXsrv_session_close_loop: "
+ "old_session_wire_id %llu - global %u != %u\n",
+ (unsigned long long)close_info0->old_session_wire_id,
+ session->global->session_global_id,
+ close_info0->old_session_global_id));
+ if (DEBUGLVL(1)) {
+ NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
+ }
+ goto next;
+ }
+
+ if (session->global->creation_time != close_info0->old_creation_time) {
+ DEBUG(1,("smbXsrv_session_close_loop: "
+ "old_session_wire_id %llu - "
+ "creation %s (%llu) != %s (%llu)\n",
+ (unsigned long long)close_info0->old_session_wire_id,
+ nt_time_string(rec, session->global->creation_time),
+ (unsigned long long)session->global->creation_time,
+ nt_time_string(rec, close_info0->old_creation_time),
+ (unsigned long long)close_info0->old_creation_time));
+ if (DEBUGLVL(1)) {
+ NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
+ }
+ goto next;
+ }
+
+ /*
+ * TODO: cancel all outstanding requests on the session
+ */
+ status = smbXsrv_session_logoff(session);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("smbXsrv_session_close_loop: "
+ "smbXsrv_session_logoff(%llu) failed: %s\n",
+ (unsigned long long)session->global->session_wire_id,
+ nt_errstr(status)));
+ if (DEBUGLVL(1)) {
+ NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
+ }
+ }
+ TALLOC_FREE(session);
+
+next:
+ TALLOC_FREE(rec);
+
+ subreq = msg_read_send(table, conn->ev_ctx, table->close_channel);
+ if (subreq == NULL) {
+ smbd_server_connection_terminate(conn->sconn,
+ "msg_read_send() failed");
+ return;
+ }
+ tevent_req_set_callback(subreq, smbXsrv_session_close_loop, conn);
+}
+
struct smb1srv_session_local_allocate_state {
const uint32_t lowest_id;
const uint32_t highest_id;