auth/auth_sam_reply: add some const to input parameters
[Samba.git] / source3 / smbd / smbXsrv_session.c
blobcdad47f0e3d025b95f3c36c413f55850617300ec
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 2011-2012
5 Copyright (C) Michael Adam 2012
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include <tevent.h>
24 #include "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_rbt.h"
28 #include "dbwrap/dbwrap_open.h"
29 #include "dbwrap/dbwrap_watch.h"
30 #include "session.h"
31 #include "auth.h"
32 #include "auth/gensec/gensec.h"
33 #include "../lib/tsocket/tsocket.h"
34 #include "../libcli/security/security.h"
35 #include "messages.h"
36 #include "lib/util/util_tdb.h"
37 #include "librpc/gen_ndr/ndr_smbXsrv.h"
38 #include "serverid.h"
39 #include "lib/util/tevent_ntstatus.h"
41 struct smbXsrv_session_table {
42 struct {
43 struct db_context *db_ctx;
44 uint32_t lowest_id;
45 uint32_t highest_id;
46 uint32_t max_sessions;
47 uint32_t num_sessions;
48 } local;
49 struct {
50 struct db_context *db_ctx;
51 } global;
54 static struct db_context *smbXsrv_session_global_db_ctx = NULL;
56 NTSTATUS smbXsrv_session_global_init(void)
58 char *global_path = NULL;
59 struct db_context *db_ctx = NULL;
61 if (smbXsrv_session_global_db_ctx != NULL) {
62 return NT_STATUS_OK;
66 * This contains secret information like session keys!
68 global_path = lock_path("smbXsrv_session_global.tdb");
69 if (global_path == NULL) {
70 return NT_STATUS_NO_MEMORY;
73 db_ctx = db_open(NULL, global_path,
74 0, /* hash_size */
75 TDB_DEFAULT |
76 TDB_CLEAR_IF_FIRST |
77 TDB_INCOMPATIBLE_HASH,
78 O_RDWR | O_CREAT, 0600,
79 DBWRAP_LOCK_ORDER_1,
80 DBWRAP_FLAG_NONE);
81 TALLOC_FREE(global_path);
82 if (db_ctx == NULL) {
83 NTSTATUS status;
85 status = map_nt_error_from_unix_common(errno);
87 return status;
90 smbXsrv_session_global_db_ctx = db_ctx;
92 return NT_STATUS_OK;
96 * NOTE:
97 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
98 * has the same result as integer comparison between the uint32_t
99 * values.
101 * TODO: implement string based key
104 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
106 static TDB_DATA smbXsrv_session_global_id_to_key(uint32_t id,
107 uint8_t *key_buf)
109 TDB_DATA key;
111 RSIVAL(key_buf, 0, id);
113 key = make_tdb_data(key_buf, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE);
115 return key;
118 #if 0
119 static NTSTATUS smbXsrv_session_global_key_to_id(TDB_DATA key, uint32_t *id)
121 if (id == NULL) {
122 return NT_STATUS_INVALID_PARAMETER;
125 if (key.dsize != SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE) {
126 return NT_STATUS_INTERNAL_DB_CORRUPTION;
129 *id = RIVAL(key.dptr, 0);
131 return NT_STATUS_OK;
133 #endif
135 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
137 static TDB_DATA smbXsrv_session_local_id_to_key(uint32_t id,
138 uint8_t *key_buf)
140 TDB_DATA key;
142 RSIVAL(key_buf, 0, id);
144 key = make_tdb_data(key_buf, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE);
146 return key;
149 static NTSTATUS smbXsrv_session_local_key_to_id(TDB_DATA key, uint32_t *id)
151 if (id == NULL) {
152 return NT_STATUS_INVALID_PARAMETER;
155 if (key.dsize != SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE) {
156 return NT_STATUS_INTERNAL_DB_CORRUPTION;
159 *id = RIVAL(key.dptr, 0);
161 return NT_STATUS_OK;
164 static struct db_record *smbXsrv_session_global_fetch_locked(
165 struct db_context *db,
166 uint32_t id,
167 TALLOC_CTX *mem_ctx)
169 TDB_DATA key;
170 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
171 struct db_record *rec = NULL;
173 key = smbXsrv_session_global_id_to_key(id, key_buf);
175 rec = dbwrap_fetch_locked(db, mem_ctx, key);
177 if (rec == NULL) {
178 DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id,
179 hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
182 return rec;
185 static struct db_record *smbXsrv_session_local_fetch_locked(
186 struct db_context *db,
187 uint32_t id,
188 TALLOC_CTX *mem_ctx)
190 TDB_DATA key;
191 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
192 struct db_record *rec = NULL;
194 key = smbXsrv_session_local_id_to_key(id, key_buf);
196 rec = dbwrap_fetch_locked(db, mem_ctx, key);
198 if (rec == NULL) {
199 DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
200 hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
203 return rec;
206 static void smbXsrv_session_close_loop(struct tevent_req *subreq);
208 static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
209 uint32_t lowest_id,
210 uint32_t highest_id,
211 uint32_t max_sessions)
213 struct smbXsrv_client *client = conn->client;
214 struct smbXsrv_session_table *table;
215 NTSTATUS status;
216 struct tevent_req *subreq;
217 uint64_t max_range;
219 if (lowest_id > highest_id) {
220 return NT_STATUS_INTERNAL_ERROR;
223 max_range = highest_id;
224 max_range -= lowest_id;
225 max_range += 1;
227 if (max_sessions > max_range) {
228 return NT_STATUS_INTERNAL_ERROR;
231 table = talloc_zero(client, struct smbXsrv_session_table);
232 if (table == NULL) {
233 return NT_STATUS_NO_MEMORY;
236 table->local.db_ctx = db_open_rbt(table);
237 if (table->local.db_ctx == NULL) {
238 TALLOC_FREE(table);
239 return NT_STATUS_NO_MEMORY;
241 table->local.lowest_id = lowest_id;
242 table->local.highest_id = highest_id;
243 table->local.max_sessions = max_sessions;
245 status = smbXsrv_session_global_init();
246 if (!NT_STATUS_IS_OK(status)) {
247 TALLOC_FREE(table);
248 return status;
251 table->global.db_ctx = smbXsrv_session_global_db_ctx;
253 dbwrap_watch_db(table->global.db_ctx, client->msg_ctx);
255 subreq = messaging_read_send(table, client->ev_ctx, client->msg_ctx,
256 MSG_SMBXSRV_SESSION_CLOSE);
257 if (subreq == NULL) {
258 TALLOC_FREE(table);
259 return NT_STATUS_NO_MEMORY;
261 tevent_req_set_callback(subreq, smbXsrv_session_close_loop, client);
263 client->session_table = table;
264 return NT_STATUS_OK;
267 static void smbXsrv_session_close_shutdown_done(struct tevent_req *subreq);
269 static void smbXsrv_session_close_loop(struct tevent_req *subreq)
271 struct smbXsrv_client *client =
272 tevent_req_callback_data(subreq,
273 struct smbXsrv_client);
274 struct smbXsrv_session_table *table = client->session_table;
275 int ret;
276 struct messaging_rec *rec = NULL;
277 struct smbXsrv_session_closeB close_blob;
278 enum ndr_err_code ndr_err;
279 struct smbXsrv_session_close0 *close_info0 = NULL;
280 struct smbXsrv_session *session = NULL;
281 NTSTATUS status;
282 struct timeval tv = timeval_current();
283 NTTIME now = timeval_to_nttime(&tv);
285 ret = messaging_read_recv(subreq, talloc_tos(), &rec);
286 TALLOC_FREE(subreq);
287 if (ret != 0) {
288 goto next;
291 ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &close_blob,
292 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_closeB);
293 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
294 status = ndr_map_error2ntstatus(ndr_err);
295 DEBUG(1,("smbXsrv_session_close_loop: "
296 "ndr_pull_struct_blob - %s\n",
297 nt_errstr(status)));
298 goto next;
301 DEBUG(10,("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n"));
302 if (DEBUGLVL(10)) {
303 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
306 if (close_blob.version != SMBXSRV_VERSION_0) {
307 DEBUG(0,("smbXsrv_session_close_loop: "
308 "ignore invalid version %u\n", close_blob.version));
309 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
310 goto next;
313 close_info0 = close_blob.info.info0;
314 if (close_info0 == NULL) {
315 DEBUG(0,("smbXsrv_session_close_loop: "
316 "ignore NULL info %u\n", close_blob.version));
317 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
318 goto next;
321 status = smb2srv_session_lookup_client(client,
322 close_info0->old_session_wire_id,
323 now, &session);
324 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
325 DEBUG(4,("smbXsrv_session_close_loop: "
326 "old_session_wire_id %llu not found\n",
327 (unsigned long long)close_info0->old_session_wire_id));
328 if (DEBUGLVL(4)) {
329 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
331 goto next;
333 if (!NT_STATUS_IS_OK(status) &&
334 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
335 !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
336 DEBUG(1,("smbXsrv_session_close_loop: "
337 "old_session_wire_id %llu - %s\n",
338 (unsigned long long)close_info0->old_session_wire_id,
339 nt_errstr(status)));
340 if (DEBUGLVL(1)) {
341 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
343 goto next;
346 if (session->global->session_global_id != close_info0->old_session_global_id) {
347 DEBUG(1,("smbXsrv_session_close_loop: "
348 "old_session_wire_id %llu - global %u != %u\n",
349 (unsigned long long)close_info0->old_session_wire_id,
350 session->global->session_global_id,
351 close_info0->old_session_global_id));
352 if (DEBUGLVL(1)) {
353 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
355 goto next;
358 if (session->global->creation_time != close_info0->old_creation_time) {
359 DEBUG(1,("smbXsrv_session_close_loop: "
360 "old_session_wire_id %llu - "
361 "creation %s (%llu) != %s (%llu)\n",
362 (unsigned long long)close_info0->old_session_wire_id,
363 nt_time_string(rec, session->global->creation_time),
364 (unsigned long long)session->global->creation_time,
365 nt_time_string(rec, close_info0->old_creation_time),
366 (unsigned long long)close_info0->old_creation_time));
367 if (DEBUGLVL(1)) {
368 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
370 goto next;
373 subreq = smb2srv_session_shutdown_send(session, client->ev_ctx,
374 session, NULL);
375 if (subreq == NULL) {
376 status = NT_STATUS_NO_MEMORY;
377 DEBUG(0, ("smbXsrv_session_close_loop: "
378 "smb2srv_session_shutdown_send(%llu) failed: %s\n",
379 (unsigned long long)session->global->session_wire_id,
380 nt_errstr(status)));
381 if (DEBUGLVL(1)) {
382 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
384 goto next;
386 tevent_req_set_callback(subreq,
387 smbXsrv_session_close_shutdown_done,
388 session);
390 next:
391 TALLOC_FREE(rec);
393 subreq = messaging_read_send(table, client->ev_ctx, client->msg_ctx,
394 MSG_SMBXSRV_SESSION_CLOSE);
395 if (subreq == NULL) {
396 const char *r;
397 r = "messaging_read_send(MSG_SMBXSRV_SESSION_CLOSE) failed";
398 exit_server_cleanly(r);
399 return;
401 tevent_req_set_callback(subreq, smbXsrv_session_close_loop, client);
404 static void smbXsrv_session_close_shutdown_done(struct tevent_req *subreq)
406 struct smbXsrv_session *session =
407 tevent_req_callback_data(subreq,
408 struct smbXsrv_session);
409 NTSTATUS status;
411 status = smb2srv_session_shutdown_recv(subreq);
412 TALLOC_FREE(subreq);
413 if (!NT_STATUS_IS_OK(status)) {
414 DEBUG(0, ("smbXsrv_session_close_loop: "
415 "smb2srv_session_shutdown_recv(%llu) failed: %s\n",
416 (unsigned long long)session->global->session_wire_id,
417 nt_errstr(status)));
420 status = smbXsrv_session_logoff(session);
421 if (!NT_STATUS_IS_OK(status)) {
422 DEBUG(0, ("smbXsrv_session_close_loop: "
423 "smbXsrv_session_logoff(%llu) failed: %s\n",
424 (unsigned long long)session->global->session_wire_id,
425 nt_errstr(status)));
428 TALLOC_FREE(session);
431 struct smb1srv_session_local_allocate_state {
432 const uint32_t lowest_id;
433 const uint32_t highest_id;
434 uint32_t last_id;
435 uint32_t useable_id;
436 NTSTATUS status;
439 static int smb1srv_session_local_allocate_traverse(struct db_record *rec,
440 void *private_data)
442 struct smb1srv_session_local_allocate_state *state =
443 (struct smb1srv_session_local_allocate_state *)private_data;
444 TDB_DATA key = dbwrap_record_get_key(rec);
445 uint32_t id = 0;
446 NTSTATUS status;
448 status = smbXsrv_session_local_key_to_id(key, &id);
449 if (!NT_STATUS_IS_OK(status)) {
450 state->status = status;
451 return -1;
454 if (id <= state->last_id) {
455 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
456 return -1;
458 state->last_id = id;
460 if (id > state->useable_id) {
461 state->status = NT_STATUS_OK;
462 return -1;
465 if (state->useable_id == state->highest_id) {
466 state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
467 return -1;
470 state->useable_id +=1;
471 return 0;
474 static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
475 uint32_t lowest_id,
476 uint32_t highest_id,
477 TALLOC_CTX *mem_ctx,
478 struct db_record **_rec,
479 uint32_t *_id)
481 struct smb1srv_session_local_allocate_state state = {
482 .lowest_id = lowest_id,
483 .highest_id = highest_id,
484 .last_id = 0,
485 .useable_id = lowest_id,
486 .status = NT_STATUS_INTERNAL_ERROR,
488 uint32_t i;
489 uint32_t range;
490 NTSTATUS status;
491 int count = 0;
493 *_rec = NULL;
494 *_id = 0;
496 if (lowest_id > highest_id) {
497 return NT_STATUS_INSUFFICIENT_RESOURCES;
501 * first we try randomly
503 range = (highest_id - lowest_id) + 1;
505 for (i = 0; i < (range / 2); i++) {
506 uint32_t id;
507 TDB_DATA val;
508 struct db_record *rec = NULL;
510 id = generate_random() % range;
511 id += lowest_id;
513 if (id < lowest_id) {
514 id = lowest_id;
516 if (id > highest_id) {
517 id = highest_id;
520 rec = smbXsrv_session_local_fetch_locked(db, id, mem_ctx);
521 if (rec == NULL) {
522 return NT_STATUS_INSUFFICIENT_RESOURCES;
525 val = dbwrap_record_get_value(rec);
526 if (val.dsize != 0) {
527 TALLOC_FREE(rec);
528 continue;
531 *_rec = rec;
532 *_id = id;
533 return NT_STATUS_OK;
537 * if the range is almost full,
538 * we traverse the whole table
539 * (this relies on sorted behavior of dbwrap_rbt)
541 status = dbwrap_traverse_read(db, smb1srv_session_local_allocate_traverse,
542 &state, &count);
543 if (NT_STATUS_IS_OK(status)) {
544 if (NT_STATUS_IS_OK(state.status)) {
545 return NT_STATUS_INTERNAL_ERROR;
548 if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
549 return state.status;
552 if (state.useable_id <= state.highest_id) {
553 state.status = NT_STATUS_OK;
554 } else {
555 return NT_STATUS_INSUFFICIENT_RESOURCES;
557 } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
559 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
561 * If we get anything else it is an error, because it
562 * means we did not manage to find a free slot in
563 * the db.
565 return NT_STATUS_INSUFFICIENT_RESOURCES;
568 if (NT_STATUS_IS_OK(state.status)) {
569 uint32_t id;
570 TDB_DATA val;
571 struct db_record *rec = NULL;
573 id = state.useable_id;
575 rec = smbXsrv_session_local_fetch_locked(db, id, mem_ctx);
576 if (rec == NULL) {
577 return NT_STATUS_INSUFFICIENT_RESOURCES;
580 val = dbwrap_record_get_value(rec);
581 if (val.dsize != 0) {
582 TALLOC_FREE(rec);
583 return NT_STATUS_INTERNAL_DB_CORRUPTION;
586 *_rec = rec;
587 *_id = id;
588 return NT_STATUS_OK;
591 return state.status;
594 struct smbXsrv_session_local_fetch_state {
595 struct smbXsrv_session *session;
596 NTSTATUS status;
599 static void smbXsrv_session_local_fetch_parser(TDB_DATA key, TDB_DATA data,
600 void *private_data)
602 struct smbXsrv_session_local_fetch_state *state =
603 (struct smbXsrv_session_local_fetch_state *)private_data;
604 void *ptr;
606 if (data.dsize != sizeof(ptr)) {
607 state->status = NT_STATUS_INTERNAL_DB_ERROR;
608 return;
611 memcpy(&ptr, data.dptr, data.dsize);
612 state->session = talloc_get_type_abort(ptr, struct smbXsrv_session);
613 state->status = NT_STATUS_OK;
616 static NTSTATUS smbXsrv_session_local_lookup(struct smbXsrv_session_table *table,
617 /* conn: optional */
618 struct smbXsrv_connection *conn,
619 uint32_t session_local_id,
620 NTTIME now,
621 struct smbXsrv_session **_session)
623 struct smbXsrv_session_local_fetch_state state = {
624 .session = NULL,
625 .status = NT_STATUS_INTERNAL_ERROR,
627 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
628 TDB_DATA key;
629 NTSTATUS status;
631 *_session = NULL;
633 if (session_local_id == 0) {
634 return NT_STATUS_USER_SESSION_DELETED;
637 if (table == NULL) {
638 /* this might happen before the end of negprot */
639 return NT_STATUS_USER_SESSION_DELETED;
642 if (table->local.db_ctx == NULL) {
643 return NT_STATUS_INTERNAL_ERROR;
646 key = smbXsrv_session_local_id_to_key(session_local_id, key_buf);
648 status = dbwrap_parse_record(table->local.db_ctx, key,
649 smbXsrv_session_local_fetch_parser,
650 &state);
651 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
652 return NT_STATUS_USER_SESSION_DELETED;
653 } else if (!NT_STATUS_IS_OK(status)) {
654 return status;
656 if (!NT_STATUS_IS_OK(state.status)) {
657 return state.status;
660 if (NT_STATUS_EQUAL(state.session->status, NT_STATUS_USER_SESSION_DELETED)) {
661 return NT_STATUS_USER_SESSION_DELETED;
665 * If a connection is specified check if the session is
666 * valid on the channel.
668 if (conn != NULL) {
669 struct smbXsrv_channel_global0 *c = NULL;
671 status = smbXsrv_session_find_channel(state.session, conn, &c);
672 if (!NT_STATUS_IS_OK(status)) {
673 return status;
677 state.session->idle_time = now;
679 if (!NT_STATUS_IS_OK(state.session->status)) {
680 *_session = state.session;
681 return state.session->status;
684 if (now > state.session->global->expiration_time) {
685 state.session->status = NT_STATUS_NETWORK_SESSION_EXPIRED;
688 *_session = state.session;
689 return state.session->status;
692 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0 *global)
694 return 0;
697 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
698 bool *is_free,
699 bool *was_free,
700 TALLOC_CTX *mem_ctx,
701 struct smbXsrv_session_global0 **_g);
703 static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db,
704 TALLOC_CTX *mem_ctx,
705 struct smbXsrv_session_global0 **_global)
707 uint32_t i;
708 struct smbXsrv_session_global0 *global = NULL;
709 uint32_t last_free = 0;
710 const uint32_t min_tries = 3;
712 *_global = NULL;
714 global = talloc_zero(mem_ctx, struct smbXsrv_session_global0);
715 if (global == NULL) {
716 return NT_STATUS_NO_MEMORY;
718 talloc_set_destructor(global, smbXsrv_session_global_destructor);
721 * Here we just randomly try the whole 32-bit space
723 * We use just 32-bit, because we want to reuse the
724 * ID for SRVSVC.
726 for (i = 0; i < UINT32_MAX; i++) {
727 bool is_free = false;
728 bool was_free = false;
729 uint32_t id;
731 if (i >= min_tries && last_free != 0) {
732 id = last_free;
733 } else {
734 id = generate_random();
736 if (id == 0) {
737 id++;
739 if (id == UINT32_MAX) {
740 id--;
743 global->db_rec = smbXsrv_session_global_fetch_locked(db, id,
744 mem_ctx);
745 if (global->db_rec == NULL) {
746 talloc_free(global);
747 return NT_STATUS_INSUFFICIENT_RESOURCES;
750 smbXsrv_session_global_verify_record(global->db_rec,
751 &is_free,
752 &was_free,
753 NULL, NULL);
755 if (!is_free) {
756 TALLOC_FREE(global->db_rec);
757 continue;
760 if (!was_free && i < min_tries) {
762 * The session_id is free now,
763 * but was not free before.
765 * This happens if a smbd crashed
766 * and did not cleanup the record.
768 * If this is one of our first tries,
769 * then we try to find a real free one.
771 if (last_free == 0) {
772 last_free = id;
774 TALLOC_FREE(global->db_rec);
775 continue;
778 global->session_global_id = id;
780 *_global = global;
781 return NT_STATUS_OK;
784 /* should not be reached */
785 talloc_free(global);
786 return NT_STATUS_INTERNAL_ERROR;
789 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
790 bool *is_free,
791 bool *was_free,
792 TALLOC_CTX *mem_ctx,
793 struct smbXsrv_session_global0 **_g)
795 TDB_DATA key;
796 TDB_DATA val;
797 DATA_BLOB blob;
798 struct smbXsrv_session_globalB global_blob;
799 enum ndr_err_code ndr_err;
800 struct smbXsrv_session_global0 *global = NULL;
801 bool exists;
802 TALLOC_CTX *frame = talloc_stackframe();
804 *is_free = false;
806 if (was_free) {
807 *was_free = false;
809 if (_g) {
810 *_g = NULL;
813 key = dbwrap_record_get_key(db_rec);
815 val = dbwrap_record_get_value(db_rec);
816 if (val.dsize == 0) {
817 TALLOC_FREE(frame);
818 *is_free = true;
819 if (was_free) {
820 *was_free = true;
822 return;
825 blob = data_blob_const(val.dptr, val.dsize);
827 ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
828 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
829 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
830 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
831 DEBUG(1,("smbXsrv_session_global_verify_record: "
832 "key '%s' ndr_pull_struct_blob - %s\n",
833 hex_encode_talloc(frame, key.dptr, key.dsize),
834 nt_errstr(status)));
835 TALLOC_FREE(frame);
836 *is_free = true;
837 if (was_free) {
838 *was_free = true;
840 return;
843 DEBUG(10,("smbXsrv_session_global_verify_record\n"));
844 if (DEBUGLVL(10)) {
845 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
848 if (global_blob.version != SMBXSRV_VERSION_0) {
849 DEBUG(0,("smbXsrv_session_global_verify_record: "
850 "key '%s' use unsupported version %u\n",
851 hex_encode_talloc(frame, key.dptr, key.dsize),
852 global_blob.version));
853 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
854 TALLOC_FREE(frame);
855 *is_free = true;
856 if (was_free) {
857 *was_free = true;
859 return;
862 global = global_blob.info.info0;
864 exists = serverid_exists(&global->channels[0].server_id);
865 if (!exists) {
866 struct server_id_buf idbuf;
867 DEBUG(2,("smbXsrv_session_global_verify_record: "
868 "key '%s' server_id %s does not exist.\n",
869 hex_encode_talloc(frame, key.dptr, key.dsize),
870 server_id_str_buf(global->channels[0].server_id,
871 &idbuf)));
872 if (DEBUGLVL(2)) {
873 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
875 TALLOC_FREE(frame);
876 dbwrap_record_delete(db_rec);
877 *is_free = true;
878 return;
881 if (_g) {
882 *_g = talloc_move(mem_ctx, &global);
884 TALLOC_FREE(frame);
887 static NTSTATUS smbXsrv_session_global_store(struct smbXsrv_session_global0 *global)
889 struct smbXsrv_session_globalB global_blob;
890 DATA_BLOB blob = data_blob_null;
891 TDB_DATA key;
892 TDB_DATA val;
893 NTSTATUS status;
894 enum ndr_err_code ndr_err;
897 * TODO: if we use other versions than '0'
898 * we would add glue code here, that would be able to
899 * store the information in the old format.
902 if (global->db_rec == NULL) {
903 return NT_STATUS_INTERNAL_ERROR;
906 key = dbwrap_record_get_key(global->db_rec);
907 val = dbwrap_record_get_value(global->db_rec);
909 ZERO_STRUCT(global_blob);
910 global_blob.version = smbXsrv_version_global_current();
911 if (val.dsize >= 8) {
912 global_blob.seqnum = IVAL(val.dptr, 4);
914 global_blob.seqnum += 1;
915 global_blob.info.info0 = global;
917 ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
918 (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_globalB);
919 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
920 status = ndr_map_error2ntstatus(ndr_err);
921 DEBUG(1,("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
922 hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
923 nt_errstr(status)));
924 TALLOC_FREE(global->db_rec);
925 return status;
928 val = make_tdb_data(blob.data, blob.length);
929 status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
930 if (!NT_STATUS_IS_OK(status)) {
931 DEBUG(1,("smbXsrv_session_global_store: key '%s' store - %s\n",
932 hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
933 nt_errstr(status)));
934 TALLOC_FREE(global->db_rec);
935 return status;
938 if (DEBUGLVL(10)) {
939 DEBUG(10,("smbXsrv_session_global_store: key '%s' stored\n",
940 hex_encode_talloc(global->db_rec, key.dptr, key.dsize)));
941 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
944 TALLOC_FREE(global->db_rec);
946 return NT_STATUS_OK;
949 struct smb2srv_session_close_previous_state {
950 struct tevent_context *ev;
951 struct smbXsrv_connection *connection;
952 struct dom_sid *current_sid;
953 uint64_t current_session_id;
954 struct db_record *db_rec;
957 static void smb2srv_session_close_previous_check(struct tevent_req *req);
958 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq);
960 struct tevent_req *smb2srv_session_close_previous_send(TALLOC_CTX *mem_ctx,
961 struct tevent_context *ev,
962 struct smbXsrv_connection *conn,
963 struct auth_session_info *session_info,
964 uint64_t previous_session_id,
965 uint64_t current_session_id)
967 struct tevent_req *req;
968 struct smb2srv_session_close_previous_state *state;
969 uint32_t global_id = previous_session_id & UINT32_MAX;
970 uint64_t global_zeros = previous_session_id & 0xFFFFFFFF00000000LLU;
971 struct smbXsrv_session_table *table = conn->client->session_table;
972 struct security_token *current_token = NULL;
974 req = tevent_req_create(mem_ctx, &state,
975 struct smb2srv_session_close_previous_state);
976 if (req == NULL) {
977 return NULL;
979 state->ev = ev;
980 state->connection = conn;
981 state->current_session_id = current_session_id;
983 if (global_zeros != 0) {
984 tevent_req_done(req);
985 return tevent_req_post(req, ev);
988 if (session_info == NULL) {
989 tevent_req_done(req);
990 return tevent_req_post(req, ev);
992 current_token = session_info->security_token;
994 if (current_token->num_sids > PRIMARY_USER_SID_INDEX) {
995 state->current_sid = &current_token->sids[PRIMARY_USER_SID_INDEX];
998 if (state->current_sid == NULL) {
999 tevent_req_done(req);
1000 return tevent_req_post(req, ev);
1003 if (!security_token_has_nt_authenticated_users(current_token)) {
1004 /* TODO */
1005 tevent_req_done(req);
1006 return tevent_req_post(req, ev);
1009 state->db_rec = smbXsrv_session_global_fetch_locked(
1010 table->global.db_ctx,
1011 global_id,
1012 state /* TALLOC_CTX */);
1013 if (state->db_rec == NULL) {
1014 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1015 return tevent_req_post(req, ev);
1018 smb2srv_session_close_previous_check(req);
1019 if (!tevent_req_is_in_progress(req)) {
1020 return tevent_req_post(req, ev);
1023 return req;
1026 static void smb2srv_session_close_previous_check(struct tevent_req *req)
1028 struct smb2srv_session_close_previous_state *state =
1029 tevent_req_data(req,
1030 struct smb2srv_session_close_previous_state);
1031 struct smbXsrv_connection *conn = state->connection;
1032 DATA_BLOB blob;
1033 struct security_token *previous_token = NULL;
1034 struct smbXsrv_session_global0 *global = NULL;
1035 enum ndr_err_code ndr_err;
1036 struct smbXsrv_session_close0 close_info0;
1037 struct smbXsrv_session_closeB close_blob;
1038 struct tevent_req *subreq = NULL;
1039 NTSTATUS status;
1040 bool is_free = false;
1042 smbXsrv_session_global_verify_record(state->db_rec,
1043 &is_free,
1044 NULL,
1045 state,
1046 &global);
1048 if (is_free) {
1049 TALLOC_FREE(state->db_rec);
1050 tevent_req_done(req);
1051 return;
1054 if (global->auth_session_info == NULL) {
1055 TALLOC_FREE(state->db_rec);
1056 tevent_req_done(req);
1057 return;
1060 previous_token = global->auth_session_info->security_token;
1062 if (!security_token_is_sid(previous_token, state->current_sid)) {
1063 TALLOC_FREE(state->db_rec);
1064 tevent_req_done(req);
1065 return;
1068 subreq = dbwrap_record_watch_send(state, state->ev,
1069 state->db_rec, conn->msg_ctx);
1070 if (tevent_req_nomem(subreq, req)) {
1071 TALLOC_FREE(state->db_rec);
1072 return;
1074 tevent_req_set_callback(subreq,
1075 smb2srv_session_close_previous_modified,
1076 req);
1078 close_info0.old_session_global_id = global->session_global_id;
1079 close_info0.old_session_wire_id = global->session_wire_id;
1080 close_info0.old_creation_time = global->creation_time;
1081 close_info0.new_session_wire_id = state->current_session_id;
1083 ZERO_STRUCT(close_blob);
1084 close_blob.version = smbXsrv_version_global_current();
1085 close_blob.info.info0 = &close_info0;
1087 ndr_err = ndr_push_struct_blob(&blob, state, &close_blob,
1088 (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_closeB);
1089 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1090 TALLOC_FREE(state->db_rec);
1091 status = ndr_map_error2ntstatus(ndr_err);
1092 DEBUG(1,("smb2srv_session_close_previous_check: "
1093 "old_session[%llu] new_session[%llu] ndr_push - %s\n",
1094 (unsigned long long)close_info0.old_session_wire_id,
1095 (unsigned long long)close_info0.new_session_wire_id,
1096 nt_errstr(status)));
1097 tevent_req_nterror(req, status);
1098 return;
1101 status = messaging_send(conn->msg_ctx,
1102 global->channels[0].server_id,
1103 MSG_SMBXSRV_SESSION_CLOSE, &blob);
1104 TALLOC_FREE(state->db_rec);
1105 if (tevent_req_nterror(req, status)) {
1106 return;
1109 TALLOC_FREE(global);
1110 return;
1113 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq)
1115 struct tevent_req *req =
1116 tevent_req_callback_data(subreq,
1117 struct tevent_req);
1118 struct smb2srv_session_close_previous_state *state =
1119 tevent_req_data(req,
1120 struct smb2srv_session_close_previous_state);
1121 NTSTATUS status;
1123 status = dbwrap_record_watch_recv(subreq, state, &state->db_rec);
1124 TALLOC_FREE(subreq);
1125 if (tevent_req_nterror(req, status)) {
1126 return;
1129 smb2srv_session_close_previous_check(req);
1132 NTSTATUS smb2srv_session_close_previous_recv(struct tevent_req *req)
1134 NTSTATUS status;
1136 if (tevent_req_is_nterror(req, &status)) {
1137 tevent_req_received(req);
1138 return status;
1141 tevent_req_received(req);
1142 return NT_STATUS_OK;
1145 static NTSTATUS smbXsrv_session_clear_and_logoff(struct smbXsrv_session *session)
1147 NTSTATUS status;
1148 struct smbXsrv_connection *xconn = NULL;
1150 if (session->client != NULL) {
1151 xconn = session->client->connections;
1154 for (; xconn != NULL; xconn = xconn->next) {
1155 struct smbd_smb2_request *preq;
1157 for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
1158 if (preq->session != session) {
1159 continue;
1162 preq->session = NULL;
1164 * If we no longer have a session we can't
1165 * sign or encrypt replies.
1167 preq->do_signing = false;
1168 preq->do_encryption = false;
1169 preq->preauth = NULL;
1173 status = smbXsrv_session_logoff(session);
1174 return status;
1177 static int smbXsrv_session_destructor(struct smbXsrv_session *session)
1179 NTSTATUS status;
1181 status = smbXsrv_session_clear_and_logoff(session);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 DEBUG(0, ("smbXsrv_session_destructor: "
1184 "smbXsrv_session_logoff() failed: %s\n",
1185 nt_errstr(status)));
1188 TALLOC_FREE(session->global);
1190 return 0;
1193 NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
1194 NTTIME now,
1195 struct smbXsrv_session **_session)
1197 struct smbXsrv_session_table *table = conn->client->session_table;
1198 struct db_record *local_rec = NULL;
1199 struct smbXsrv_session *session = NULL;
1200 void *ptr = NULL;
1201 TDB_DATA val;
1202 struct smbXsrv_session_global0 *global = NULL;
1203 struct smbXsrv_channel_global0 *channel = NULL;
1204 NTSTATUS status;
1206 if (table->local.num_sessions >= table->local.max_sessions) {
1207 return NT_STATUS_INSUFFICIENT_RESOURCES;
1210 session = talloc_zero(table, struct smbXsrv_session);
1211 if (session == NULL) {
1212 return NT_STATUS_NO_MEMORY;
1214 session->table = table;
1215 session->idle_time = now;
1216 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1217 session->client = conn->client;
1219 status = smbXsrv_session_global_allocate(table->global.db_ctx,
1220 session,
1221 &global);
1222 if (!NT_STATUS_IS_OK(status)) {
1223 TALLOC_FREE(session);
1224 return status;
1226 session->global = global;
1228 if (conn->protocol >= PROTOCOL_SMB2_02) {
1229 uint64_t id = global->session_global_id;
1231 global->connection_dialect = conn->smb2.server.dialect;
1233 global->session_wire_id = id;
1235 status = smb2srv_tcon_table_init(session);
1236 if (!NT_STATUS_IS_OK(status)) {
1237 TALLOC_FREE(session);
1238 return status;
1241 session->local_id = global->session_global_id;
1243 local_rec = smbXsrv_session_local_fetch_locked(
1244 table->local.db_ctx,
1245 session->local_id,
1246 session /* TALLOC_CTX */);
1247 if (local_rec == NULL) {
1248 TALLOC_FREE(session);
1249 return NT_STATUS_NO_MEMORY;
1252 val = dbwrap_record_get_value(local_rec);
1253 if (val.dsize != 0) {
1254 TALLOC_FREE(session);
1255 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1257 } else {
1259 status = smb1srv_session_local_allocate_id(table->local.db_ctx,
1260 table->local.lowest_id,
1261 table->local.highest_id,
1262 session,
1263 &local_rec,
1264 &session->local_id);
1265 if (!NT_STATUS_IS_OK(status)) {
1266 TALLOC_FREE(session);
1267 return status;
1270 global->session_wire_id = session->local_id;
1273 global->creation_time = now;
1274 global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY;
1276 status = smbXsrv_session_add_channel(session, conn, &channel);
1277 if (!NT_STATUS_IS_OK(status)) {
1278 TALLOC_FREE(session);
1279 return status;
1282 ptr = session;
1283 val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
1284 status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
1285 TALLOC_FREE(local_rec);
1286 if (!NT_STATUS_IS_OK(status)) {
1287 TALLOC_FREE(session);
1288 return status;
1290 table->local.num_sessions += 1;
1292 talloc_set_destructor(session, smbXsrv_session_destructor);
1294 status = smbXsrv_session_global_store(global);
1295 if (!NT_STATUS_IS_OK(status)) {
1296 DEBUG(0,("smbXsrv_session_create: "
1297 "global_id (0x%08x) store failed - %s\n",
1298 session->global->session_global_id,
1299 nt_errstr(status)));
1300 TALLOC_FREE(session);
1301 return status;
1304 if (DEBUGLVL(10)) {
1305 struct smbXsrv_sessionB session_blob;
1307 ZERO_STRUCT(session_blob);
1308 session_blob.version = SMBXSRV_VERSION_0;
1309 session_blob.info.info0 = session;
1311 DEBUG(10,("smbXsrv_session_create: global_id (0x%08x) stored\n",
1312 session->global->session_global_id));
1313 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1316 *_session = session;
1317 return NT_STATUS_OK;
1320 NTSTATUS smbXsrv_session_add_channel(struct smbXsrv_session *session,
1321 struct smbXsrv_connection *conn,
1322 struct smbXsrv_channel_global0 **_c)
1324 struct smbXsrv_session_global0 *global = session->global;
1325 struct smbXsrv_channel_global0 *c = NULL;
1327 if (global->num_channels > 31) {
1329 * Windows 2012 and 2012R2 allow up to 32 channels
1331 return NT_STATUS_INSUFFICIENT_RESOURCES;
1334 c = talloc_realloc(global,
1335 global->channels,
1336 struct smbXsrv_channel_global0,
1337 global->num_channels + 1);
1338 if (c == NULL) {
1339 return NT_STATUS_NO_MEMORY;
1341 global->channels = c;
1343 c = &global->channels[global->num_channels];
1344 ZERO_STRUCTP(c);
1346 c->server_id = messaging_server_id(conn->msg_ctx);
1347 c->local_address = tsocket_address_string(conn->local_address,
1348 global->channels);
1349 if (c->local_address == NULL) {
1350 return NT_STATUS_NO_MEMORY;
1352 c->remote_address = tsocket_address_string(conn->remote_address,
1353 global->channels);
1354 if (c->remote_address == NULL) {
1355 return NT_STATUS_NO_MEMORY;
1357 c->remote_name = talloc_strdup(global->channels,
1358 conn->remote_hostname);
1359 if (c->remote_name == NULL) {
1360 return NT_STATUS_NO_MEMORY;
1362 c->connection = conn;
1364 global->num_channels += 1;
1366 *_c = c;
1367 return NT_STATUS_OK;
1370 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
1372 struct smbXsrv_session_table *table = session->table;
1373 NTSTATUS status;
1375 if (session->global->db_rec != NULL) {
1376 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1377 "Called with db_rec != NULL'\n",
1378 session->global->session_global_id));
1379 return NT_STATUS_INTERNAL_ERROR;
1382 session->global->db_rec = smbXsrv_session_global_fetch_locked(
1383 table->global.db_ctx,
1384 session->global->session_global_id,
1385 session->global /* TALLOC_CTX */);
1386 if (session->global->db_rec == NULL) {
1387 return NT_STATUS_INTERNAL_DB_ERROR;
1390 status = smbXsrv_session_global_store(session->global);
1391 if (!NT_STATUS_IS_OK(status)) {
1392 DEBUG(0,("smbXsrv_session_update: "
1393 "global_id (0x%08x) store failed - %s\n",
1394 session->global->session_global_id,
1395 nt_errstr(status)));
1396 return status;
1399 if (DEBUGLVL(10)) {
1400 struct smbXsrv_sessionB session_blob;
1402 ZERO_STRUCT(session_blob);
1403 session_blob.version = SMBXSRV_VERSION_0;
1404 session_blob.info.info0 = session;
1406 DEBUG(10,("smbXsrv_session_update: global_id (0x%08x) stored\n",
1407 session->global->session_global_id));
1408 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1411 return NT_STATUS_OK;
1414 NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session,
1415 const struct smbXsrv_connection *conn,
1416 struct smbXsrv_channel_global0 **_c)
1418 uint32_t i;
1420 for (i=0; i < session->global->num_channels; i++) {
1421 struct smbXsrv_channel_global0 *c = &session->global->channels[i];
1423 if (c->connection == conn) {
1424 *_c = c;
1425 return NT_STATUS_OK;
1429 return NT_STATUS_USER_SESSION_DELETED;
1432 NTSTATUS smbXsrv_session_find_auth(const struct smbXsrv_session *session,
1433 const struct smbXsrv_connection *conn,
1434 NTTIME now,
1435 struct smbXsrv_session_auth0 **_a)
1437 struct smbXsrv_session_auth0 *a;
1439 for (a = session->pending_auth; a != NULL; a = a->next) {
1440 if (a->connection == conn) {
1441 if (now != 0) {
1442 a->idle_time = now;
1444 *_a = a;
1445 return NT_STATUS_OK;
1449 return NT_STATUS_USER_SESSION_DELETED;
1452 static int smbXsrv_session_auth0_destructor(struct smbXsrv_session_auth0 *a)
1454 if (a->session == NULL) {
1455 return 0;
1458 DLIST_REMOVE(a->session->pending_auth, a);
1459 a->session = NULL;
1460 return 0;
1463 NTSTATUS smbXsrv_session_create_auth(struct smbXsrv_session *session,
1464 struct smbXsrv_connection *conn,
1465 NTTIME now,
1466 uint8_t in_flags,
1467 uint8_t in_security_mode,
1468 struct smbXsrv_session_auth0 **_a)
1470 struct smbXsrv_session_auth0 *a;
1471 NTSTATUS status;
1473 status = smbXsrv_session_find_auth(session, conn, 0, &a);
1474 if (NT_STATUS_IS_OK(status)) {
1475 return NT_STATUS_INTERNAL_ERROR;
1478 a = talloc_zero(session, struct smbXsrv_session_auth0);
1479 if (a == NULL) {
1480 return NT_STATUS_NO_MEMORY;
1482 a->session = session;
1483 a->connection = conn;
1484 a->in_flags = in_flags;
1485 a->in_security_mode = in_security_mode;
1486 a->creation_time = now;
1487 a->idle_time = now;
1489 if (conn->protocol >= PROTOCOL_SMB3_10) {
1490 a->preauth = talloc(a, struct smbXsrv_preauth);
1491 if (a->preauth == NULL) {
1492 TALLOC_FREE(session);
1493 return NT_STATUS_NO_MEMORY;
1495 *a->preauth = conn->smb2.preauth;
1498 talloc_set_destructor(a, smbXsrv_session_auth0_destructor);
1499 DLIST_ADD_END(session->pending_auth, a);
1501 *_a = a;
1502 return NT_STATUS_OK;
1505 struct smb2srv_session_shutdown_state {
1506 struct tevent_queue *wait_queue;
1509 static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq);
1511 struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
1512 struct tevent_context *ev,
1513 struct smbXsrv_session *session,
1514 struct smbd_smb2_request *current_req)
1516 struct tevent_req *req;
1517 struct smb2srv_session_shutdown_state *state;
1518 struct tevent_req *subreq;
1519 struct smbXsrv_connection *xconn = NULL;
1520 size_t len = 0;
1523 * Make sure that no new request will be able to use this session.
1525 session->status = NT_STATUS_USER_SESSION_DELETED;
1527 req = tevent_req_create(mem_ctx, &state,
1528 struct smb2srv_session_shutdown_state);
1529 if (req == NULL) {
1530 return NULL;
1533 state->wait_queue = tevent_queue_create(state, "smb2srv_session_shutdown_queue");
1534 if (tevent_req_nomem(state->wait_queue, req)) {
1535 return tevent_req_post(req, ev);
1538 for (xconn = session->client->connections; xconn != NULL; xconn = xconn->next) {
1539 struct smbd_smb2_request *preq;
1541 for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
1542 if (preq == current_req) {
1543 /* Can't cancel current request. */
1544 continue;
1546 if (preq->session != session) {
1547 /* Request on different session. */
1548 continue;
1551 if (!NT_STATUS_IS_OK(xconn->transport.status)) {
1552 preq->session = NULL;
1554 * If we no longer have a session we can't
1555 * sign or encrypt replies.
1557 preq->do_signing = false;
1558 preq->do_encryption = false;
1559 preq->preauth = NULL;
1561 if (preq->subreq != NULL) {
1562 tevent_req_cancel(preq->subreq);
1564 continue;
1568 * Never cancel anything in a compound
1569 * request. Way too hard to deal with
1570 * the result.
1572 if (!preq->compound_related && preq->subreq != NULL) {
1573 tevent_req_cancel(preq->subreq);
1577 * Now wait until the request is finished.
1579 * We don't set a callback, as we just want to block the
1580 * wait queue and the talloc_free() of the request will
1581 * remove the item from the wait queue.
1583 subreq = tevent_queue_wait_send(preq, ev, state->wait_queue);
1584 if (tevent_req_nomem(subreq, req)) {
1585 return tevent_req_post(req, ev);
1590 len = tevent_queue_length(state->wait_queue);
1591 if (len == 0) {
1592 tevent_req_done(req);
1593 return tevent_req_post(req, ev);
1597 * Now we add our own waiter to the end of the queue,
1598 * this way we get notified when all pending requests are finished
1599 * and send to the socket.
1601 subreq = tevent_queue_wait_send(state, ev, state->wait_queue);
1602 if (tevent_req_nomem(subreq, req)) {
1603 return tevent_req_post(req, ev);
1605 tevent_req_set_callback(subreq, smb2srv_session_shutdown_wait_done, req);
1607 return req;
1610 static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq)
1612 struct tevent_req *req =
1613 tevent_req_callback_data(subreq,
1614 struct tevent_req);
1616 tevent_queue_wait_recv(subreq);
1617 TALLOC_FREE(subreq);
1619 tevent_req_done(req);
1622 NTSTATUS smb2srv_session_shutdown_recv(struct tevent_req *req)
1624 return tevent_req_simple_recv_ntstatus(req);
1627 NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session)
1629 struct smbXsrv_session_table *table;
1630 struct db_record *local_rec = NULL;
1631 struct db_record *global_rec = NULL;
1632 struct smbd_server_connection *sconn = NULL;
1633 NTSTATUS status;
1634 NTSTATUS error = NT_STATUS_OK;
1636 if (session->table == NULL) {
1637 return NT_STATUS_OK;
1640 table = session->table;
1641 session->table = NULL;
1643 sconn = session->client->sconn;
1644 session->client = NULL;
1645 session->status = NT_STATUS_USER_SESSION_DELETED;
1647 global_rec = session->global->db_rec;
1648 session->global->db_rec = NULL;
1649 if (global_rec == NULL) {
1650 global_rec = smbXsrv_session_global_fetch_locked(
1651 table->global.db_ctx,
1652 session->global->session_global_id,
1653 session->global /* TALLOC_CTX */);
1654 if (global_rec == NULL) {
1655 error = NT_STATUS_INTERNAL_ERROR;
1659 if (global_rec != NULL) {
1660 status = dbwrap_record_delete(global_rec);
1661 if (!NT_STATUS_IS_OK(status)) {
1662 TDB_DATA key = dbwrap_record_get_key(global_rec);
1664 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1665 "failed to delete global key '%s': %s\n",
1666 session->global->session_global_id,
1667 hex_encode_talloc(global_rec, key.dptr,
1668 key.dsize),
1669 nt_errstr(status)));
1670 error = status;
1673 TALLOC_FREE(global_rec);
1675 local_rec = session->db_rec;
1676 if (local_rec == NULL) {
1677 local_rec = smbXsrv_session_local_fetch_locked(
1678 table->local.db_ctx,
1679 session->local_id,
1680 session /* TALLOC_CTX */);
1681 if (local_rec == NULL) {
1682 error = NT_STATUS_INTERNAL_ERROR;
1686 if (local_rec != NULL) {
1687 status = dbwrap_record_delete(local_rec);
1688 if (!NT_STATUS_IS_OK(status)) {
1689 TDB_DATA key = dbwrap_record_get_key(local_rec);
1691 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1692 "failed to delete local key '%s': %s\n",
1693 session->global->session_global_id,
1694 hex_encode_talloc(local_rec, key.dptr,
1695 key.dsize),
1696 nt_errstr(status)));
1697 error = status;
1699 table->local.num_sessions -= 1;
1701 if (session->db_rec == NULL) {
1702 TALLOC_FREE(local_rec);
1704 session->db_rec = NULL;
1706 if (session->compat) {
1707 file_close_user(sconn, session->compat->vuid);
1710 if (session->tcon_table != NULL) {
1712 * Note: We only have a tcon_table for SMB2.
1714 status = smb2srv_tcon_disconnect_all(session);
1715 if (!NT_STATUS_IS_OK(status)) {
1716 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1717 "smb2srv_tcon_disconnect_all() failed: %s\n",
1718 session->global->session_global_id,
1719 nt_errstr(status)));
1720 error = status;
1724 if (session->compat) {
1725 invalidate_vuid(sconn, session->compat->vuid);
1726 session->compat = NULL;
1729 return error;
1732 struct smbXsrv_session_logoff_all_state {
1733 NTSTATUS first_status;
1734 int errors;
1737 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1738 void *private_data);
1740 NTSTATUS smbXsrv_session_logoff_all(struct smbXsrv_connection *conn)
1742 struct smbXsrv_session_table *table = conn->client->session_table;
1743 struct smbXsrv_session_logoff_all_state state;
1744 NTSTATUS status;
1745 int count = 0;
1747 if (table == NULL) {
1748 DEBUG(10, ("smbXsrv_session_logoff_all: "
1749 "empty session_table, nothing to do.\n"));
1750 return NT_STATUS_OK;
1753 ZERO_STRUCT(state);
1755 status = dbwrap_traverse(table->local.db_ctx,
1756 smbXsrv_session_logoff_all_callback,
1757 &state, &count);
1758 if (!NT_STATUS_IS_OK(status)) {
1759 DEBUG(0, ("smbXsrv_session_logoff_all: "
1760 "dbwrap_traverse() failed: %s\n",
1761 nt_errstr(status)));
1762 return status;
1765 if (!NT_STATUS_IS_OK(state.first_status)) {
1766 DEBUG(0, ("smbXsrv_session_logoff_all: "
1767 "count[%d] errors[%d] first[%s]\n",
1768 count, state.errors,
1769 nt_errstr(state.first_status)));
1770 return state.first_status;
1773 return NT_STATUS_OK;
1776 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1777 void *private_data)
1779 struct smbXsrv_session_logoff_all_state *state =
1780 (struct smbXsrv_session_logoff_all_state *)private_data;
1781 TDB_DATA val;
1782 void *ptr = NULL;
1783 struct smbXsrv_session *session = NULL;
1784 NTSTATUS status;
1786 val = dbwrap_record_get_value(local_rec);
1787 if (val.dsize != sizeof(ptr)) {
1788 status = NT_STATUS_INTERNAL_ERROR;
1789 if (NT_STATUS_IS_OK(state->first_status)) {
1790 state->first_status = status;
1792 state->errors++;
1793 return 0;
1796 memcpy(&ptr, val.dptr, val.dsize);
1797 session = talloc_get_type_abort(ptr, struct smbXsrv_session);
1799 session->db_rec = local_rec;
1801 status = smbXsrv_session_clear_and_logoff(session);
1802 if (!NT_STATUS_IS_OK(status)) {
1803 if (NT_STATUS_IS_OK(state->first_status)) {
1804 state->first_status = status;
1806 state->errors++;
1807 return 0;
1810 return 0;
1813 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn)
1816 * Allow a range from 1..65534 with 65534 values.
1818 return smbXsrv_session_table_init(conn, 1, UINT16_MAX - 1,
1819 UINT16_MAX - 1);
1822 NTSTATUS smb1srv_session_lookup(struct smbXsrv_connection *conn,
1823 uint16_t vuid, NTTIME now,
1824 struct smbXsrv_session **session)
1826 struct smbXsrv_session_table *table = conn->client->session_table;
1827 uint32_t local_id = vuid;
1829 return smbXsrv_session_local_lookup(table, conn, local_id, now,
1830 session);
1833 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
1836 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1838 return smbXsrv_session_table_init(conn, 1, UINT32_MAX - 1,
1839 UINT16_MAX - 1);
1842 static NTSTATUS smb2srv_session_lookup_raw(struct smbXsrv_session_table *table,
1843 /* conn: optional */
1844 struct smbXsrv_connection *conn,
1845 uint64_t session_id, NTTIME now,
1846 struct smbXsrv_session **session)
1848 uint32_t local_id = session_id & UINT32_MAX;
1849 uint64_t local_zeros = session_id & 0xFFFFFFFF00000000LLU;
1851 if (local_zeros != 0) {
1852 return NT_STATUS_USER_SESSION_DELETED;
1855 return smbXsrv_session_local_lookup(table, conn, local_id, now,
1856 session);
1859 NTSTATUS smb2srv_session_lookup_conn(struct smbXsrv_connection *conn,
1860 uint64_t session_id, NTTIME now,
1861 struct smbXsrv_session **session)
1863 struct smbXsrv_session_table *table = conn->client->session_table;
1864 return smb2srv_session_lookup_raw(table, conn, session_id, now,
1865 session);
1868 NTSTATUS smb2srv_session_lookup_client(struct smbXsrv_client *client,
1869 uint64_t session_id, NTTIME now,
1870 struct smbXsrv_session **session)
1872 struct smbXsrv_session_table *table = client->session_table;
1873 return smb2srv_session_lookup_raw(table, NULL, session_id, now,
1874 session);
1877 struct smbXsrv_session_global_traverse_state {
1878 int (*fn)(struct smbXsrv_session_global0 *, void *);
1879 void *private_data;
1882 static int smbXsrv_session_global_traverse_fn(struct db_record *rec, void *data)
1884 int ret = -1;
1885 struct smbXsrv_session_global_traverse_state *state =
1886 (struct smbXsrv_session_global_traverse_state*)data;
1887 TDB_DATA key = dbwrap_record_get_key(rec);
1888 TDB_DATA val = dbwrap_record_get_value(rec);
1889 DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
1890 struct smbXsrv_session_globalB global_blob;
1891 enum ndr_err_code ndr_err;
1892 TALLOC_CTX *frame = talloc_stackframe();
1894 ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
1895 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
1896 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1897 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1898 "key '%s' ndr_pull_struct_blob - %s\n",
1899 hex_encode_talloc(frame, key.dptr, key.dsize),
1900 ndr_errstr(ndr_err)));
1901 goto done;
1904 if (global_blob.version != SMBXSRV_VERSION_0) {
1905 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1906 "key '%s' unsuported version - %d\n",
1907 hex_encode_talloc(frame, key.dptr, key.dsize),
1908 (int)global_blob.version));
1909 goto done;
1912 global_blob.info.info0->db_rec = rec;
1913 ret = state->fn(global_blob.info.info0, state->private_data);
1914 done:
1915 TALLOC_FREE(frame);
1916 return ret;
1919 NTSTATUS smbXsrv_session_global_traverse(
1920 int (*fn)(struct smbXsrv_session_global0 *, void *),
1921 void *private_data)
1924 NTSTATUS status;
1925 int count = 0;
1926 struct smbXsrv_session_global_traverse_state state = {
1927 .fn = fn,
1928 .private_data = private_data,
1931 become_root();
1932 status = smbXsrv_session_global_init();
1933 if (!NT_STATUS_IS_OK(status)) {
1934 unbecome_root();
1935 DEBUG(0, ("Failed to initialize session_global: %s\n",
1936 nt_errstr(status)));
1937 return status;
1940 status = dbwrap_traverse_read(smbXsrv_session_global_db_ctx,
1941 smbXsrv_session_global_traverse_fn,
1942 &state,
1943 &count);
1944 unbecome_root();
1946 return status;