smbd: avoid calling SMB_VFS_FGET_NT_ACL() if do_not_check_mask already covers all
[Samba.git] / source3 / smbd / smbXsrv_session.c
blob59c6b49f2d99058a2100491b896e081f256e80d9
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 "lib/util/server_id.h"
25 #include "smbd/smbd.h"
26 #include "smbd/globals.h"
27 #include "dbwrap/dbwrap.h"
28 #include "dbwrap/dbwrap_rbt.h"
29 #include "dbwrap/dbwrap_open.h"
30 #include "dbwrap/dbwrap_watch.h"
31 #include "session.h"
32 #include "auth.h"
33 #include "auth/gensec/gensec.h"
34 #include "../lib/tsocket/tsocket.h"
35 #include "../libcli/security/security.h"
36 #include "messages.h"
37 #include "lib/util/util_tdb.h"
38 #include "librpc/gen_ndr/ndr_smbXsrv.h"
39 #include "serverid.h"
40 #include "lib/util/tevent_ntstatus.h"
41 #include "lib/global_contexts.h"
43 struct smbXsrv_session_table {
44 struct {
45 struct db_context *db_ctx;
46 uint32_t lowest_id;
47 uint32_t highest_id;
48 uint32_t max_sessions;
49 uint32_t num_sessions;
50 } local;
51 struct {
52 struct db_context *db_ctx;
53 } global;
56 static struct db_context *smbXsrv_session_global_db_ctx = NULL;
58 NTSTATUS smbXsrv_session_global_init(struct messaging_context *msg_ctx)
60 char *global_path = NULL;
61 struct db_context *backend = NULL;
62 struct db_context *db_ctx = NULL;
64 if (smbXsrv_session_global_db_ctx != NULL) {
65 return NT_STATUS_OK;
69 * This contains secret information like session keys!
71 global_path = lock_path(talloc_tos(), "smbXsrv_session_global.tdb");
72 if (global_path == NULL) {
73 return NT_STATUS_NO_MEMORY;
76 backend = db_open(NULL, global_path,
77 0, /* hash_size */
78 TDB_DEFAULT |
79 TDB_CLEAR_IF_FIRST |
80 TDB_INCOMPATIBLE_HASH,
81 O_RDWR | O_CREAT, 0600,
82 DBWRAP_LOCK_ORDER_1,
83 DBWRAP_FLAG_NONE);
84 TALLOC_FREE(global_path);
85 if (backend == NULL) {
86 NTSTATUS status;
88 status = map_nt_error_from_unix_common(errno);
90 return status;
93 db_ctx = db_open_watched(NULL, &backend, global_messaging_context());
94 if (db_ctx == NULL) {
95 TALLOC_FREE(backend);
96 return NT_STATUS_NO_MEMORY;
99 smbXsrv_session_global_db_ctx = db_ctx;
101 return NT_STATUS_OK;
105 * NOTE:
106 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
107 * has the same result as integer comparison between the uint32_t
108 * values.
110 * TODO: implement string based key
113 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
115 static TDB_DATA smbXsrv_session_global_id_to_key(uint32_t id,
116 uint8_t *key_buf)
118 TDB_DATA key;
120 RSIVAL(key_buf, 0, id);
122 key = make_tdb_data(key_buf, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE);
124 return key;
127 #if 0
128 static NTSTATUS smbXsrv_session_global_key_to_id(TDB_DATA key, uint32_t *id)
130 if (id == NULL) {
131 return NT_STATUS_INVALID_PARAMETER;
134 if (key.dsize != SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE) {
135 return NT_STATUS_INTERNAL_DB_CORRUPTION;
138 *id = RIVAL(key.dptr, 0);
140 return NT_STATUS_OK;
142 #endif
144 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
146 static TDB_DATA smbXsrv_session_local_id_to_key(uint32_t id,
147 uint8_t *key_buf)
149 TDB_DATA key;
151 RSIVAL(key_buf, 0, id);
153 key = make_tdb_data(key_buf, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE);
155 return key;
158 static NTSTATUS smbXsrv_session_local_key_to_id(TDB_DATA key, uint32_t *id)
160 if (id == NULL) {
161 return NT_STATUS_INVALID_PARAMETER;
164 if (key.dsize != SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE) {
165 return NT_STATUS_INTERNAL_DB_CORRUPTION;
168 *id = RIVAL(key.dptr, 0);
170 return NT_STATUS_OK;
173 static struct db_record *smbXsrv_session_global_fetch_locked(
174 struct db_context *db,
175 uint32_t id,
176 TALLOC_CTX *mem_ctx)
178 TDB_DATA key;
179 uint8_t key_buf[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE];
180 struct db_record *rec = NULL;
182 key = smbXsrv_session_global_id_to_key(id, key_buf);
184 rec = dbwrap_fetch_locked(db, mem_ctx, key);
186 if (rec == NULL) {
187 DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id,
188 hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
191 return rec;
194 static struct db_record *smbXsrv_session_local_fetch_locked(
195 struct db_context *db,
196 uint32_t id,
197 TALLOC_CTX *mem_ctx)
199 TDB_DATA key;
200 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
201 struct db_record *rec = NULL;
203 key = smbXsrv_session_local_id_to_key(id, key_buf);
205 rec = dbwrap_fetch_locked(db, mem_ctx, key);
207 if (rec == NULL) {
208 DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
209 hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
212 return rec;
215 static void smbXsrv_session_close_loop(struct tevent_req *subreq);
217 static NTSTATUS smbXsrv_session_table_init(struct smbXsrv_connection *conn,
218 uint32_t lowest_id,
219 uint32_t highest_id,
220 uint32_t max_sessions)
222 struct smbXsrv_client *client = conn->client;
223 struct smbXsrv_session_table *table;
224 NTSTATUS status;
225 struct tevent_req *subreq;
226 uint64_t max_range;
228 if (lowest_id > highest_id) {
229 return NT_STATUS_INTERNAL_ERROR;
232 max_range = highest_id;
233 max_range -= lowest_id;
234 max_range += 1;
236 if (max_sessions > max_range) {
237 return NT_STATUS_INTERNAL_ERROR;
240 table = talloc_zero(client, struct smbXsrv_session_table);
241 if (table == NULL) {
242 return NT_STATUS_NO_MEMORY;
245 table->local.db_ctx = db_open_rbt(table);
246 if (table->local.db_ctx == NULL) {
247 TALLOC_FREE(table);
248 return NT_STATUS_NO_MEMORY;
250 table->local.lowest_id = lowest_id;
251 table->local.highest_id = highest_id;
252 table->local.max_sessions = max_sessions;
254 status = smbXsrv_session_global_init(client->msg_ctx);
255 if (!NT_STATUS_IS_OK(status)) {
256 TALLOC_FREE(table);
257 return status;
260 table->global.db_ctx = smbXsrv_session_global_db_ctx;
262 subreq = messaging_read_send(table,
263 client->raw_ev_ctx,
264 client->msg_ctx,
265 MSG_SMBXSRV_SESSION_CLOSE);
266 if (subreq == NULL) {
267 TALLOC_FREE(table);
268 return NT_STATUS_NO_MEMORY;
270 tevent_req_set_callback(subreq, smbXsrv_session_close_loop, client);
272 client->session_table = table;
273 return NT_STATUS_OK;
276 static void smbXsrv_session_close_shutdown_done(struct tevent_req *subreq);
278 static void smbXsrv_session_close_loop(struct tevent_req *subreq)
280 struct smbXsrv_client *client =
281 tevent_req_callback_data(subreq,
282 struct smbXsrv_client);
283 struct smbXsrv_session_table *table = client->session_table;
284 int ret;
285 struct messaging_rec *rec = NULL;
286 struct smbXsrv_session_closeB close_blob;
287 enum ndr_err_code ndr_err;
288 struct smbXsrv_session_close0 *close_info0 = NULL;
289 struct smbXsrv_session *session = NULL;
290 NTSTATUS status;
291 struct timeval tv = timeval_current();
292 NTTIME now = timeval_to_nttime(&tv);
294 ret = messaging_read_recv(subreq, talloc_tos(), &rec);
295 TALLOC_FREE(subreq);
296 if (ret != 0) {
297 goto next;
300 ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &close_blob,
301 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_closeB);
302 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
303 status = ndr_map_error2ntstatus(ndr_err);
304 DEBUG(1,("smbXsrv_session_close_loop: "
305 "ndr_pull_struct_blob - %s\n",
306 nt_errstr(status)));
307 goto next;
310 DEBUG(10,("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n"));
311 if (DEBUGLVL(10)) {
312 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
315 if (close_blob.version != SMBXSRV_VERSION_0) {
316 DEBUG(0,("smbXsrv_session_close_loop: "
317 "ignore invalid version %u\n", close_blob.version));
318 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
319 goto next;
322 close_info0 = close_blob.info.info0;
323 if (close_info0 == NULL) {
324 DEBUG(0,("smbXsrv_session_close_loop: "
325 "ignore NULL info %u\n", close_blob.version));
326 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
327 goto next;
330 status = smb2srv_session_lookup_client(client,
331 close_info0->old_session_wire_id,
332 now, &session);
333 if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) {
334 DEBUG(4,("smbXsrv_session_close_loop: "
335 "old_session_wire_id %llu not found\n",
336 (unsigned long long)close_info0->old_session_wire_id));
337 if (DEBUGLVL(4)) {
338 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
340 goto next;
342 if (!NT_STATUS_IS_OK(status) &&
343 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED) &&
344 !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) {
345 DEBUG(1,("smbXsrv_session_close_loop: "
346 "old_session_wire_id %llu - %s\n",
347 (unsigned long long)close_info0->old_session_wire_id,
348 nt_errstr(status)));
349 if (DEBUGLVL(1)) {
350 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
352 goto next;
355 if (session->global->session_global_id != close_info0->old_session_global_id) {
356 DEBUG(1,("smbXsrv_session_close_loop: "
357 "old_session_wire_id %llu - global %u != %u\n",
358 (unsigned long long)close_info0->old_session_wire_id,
359 session->global->session_global_id,
360 close_info0->old_session_global_id));
361 if (DEBUGLVL(1)) {
362 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
364 goto next;
367 if (session->global->creation_time != close_info0->old_creation_time) {
368 DEBUG(1,("smbXsrv_session_close_loop: "
369 "old_session_wire_id %llu - "
370 "creation %s (%llu) != %s (%llu)\n",
371 (unsigned long long)close_info0->old_session_wire_id,
372 nt_time_string(rec, session->global->creation_time),
373 (unsigned long long)session->global->creation_time,
374 nt_time_string(rec, close_info0->old_creation_time),
375 (unsigned long long)close_info0->old_creation_time));
376 if (DEBUGLVL(1)) {
377 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
379 goto next;
382 subreq = smb2srv_session_shutdown_send(session, client->raw_ev_ctx,
383 session, NULL);
384 if (subreq == NULL) {
385 status = NT_STATUS_NO_MEMORY;
386 DEBUG(0, ("smbXsrv_session_close_loop: "
387 "smb2srv_session_shutdown_send(%llu) failed: %s\n",
388 (unsigned long long)session->global->session_wire_id,
389 nt_errstr(status)));
390 if (DEBUGLVL(1)) {
391 NDR_PRINT_DEBUG(smbXsrv_session_closeB, &close_blob);
393 goto next;
395 tevent_req_set_callback(subreq,
396 smbXsrv_session_close_shutdown_done,
397 session);
399 next:
400 TALLOC_FREE(rec);
402 subreq = messaging_read_send(table,
403 client->raw_ev_ctx,
404 client->msg_ctx,
405 MSG_SMBXSRV_SESSION_CLOSE);
406 if (subreq == NULL) {
407 const char *r;
408 r = "messaging_read_send(MSG_SMBXSRV_SESSION_CLOSE) failed";
409 exit_server_cleanly(r);
410 return;
412 tevent_req_set_callback(subreq, smbXsrv_session_close_loop, client);
415 static void smbXsrv_session_close_shutdown_done(struct tevent_req *subreq)
417 struct smbXsrv_session *session =
418 tevent_req_callback_data(subreq,
419 struct smbXsrv_session);
420 NTSTATUS status;
422 status = smb2srv_session_shutdown_recv(subreq);
423 TALLOC_FREE(subreq);
424 if (!NT_STATUS_IS_OK(status)) {
425 DEBUG(0, ("smbXsrv_session_close_loop: "
426 "smb2srv_session_shutdown_recv(%llu) failed: %s\n",
427 (unsigned long long)session->global->session_wire_id,
428 nt_errstr(status)));
431 status = smbXsrv_session_logoff(session);
432 if (!NT_STATUS_IS_OK(status)) {
433 DEBUG(0, ("smbXsrv_session_close_loop: "
434 "smbXsrv_session_logoff(%llu) failed: %s\n",
435 (unsigned long long)session->global->session_wire_id,
436 nt_errstr(status)));
439 TALLOC_FREE(session);
442 struct smb1srv_session_local_allocate_state {
443 const uint32_t lowest_id;
444 const uint32_t highest_id;
445 uint32_t last_id;
446 uint32_t useable_id;
447 NTSTATUS status;
450 static int smb1srv_session_local_allocate_traverse(struct db_record *rec,
451 void *private_data)
453 struct smb1srv_session_local_allocate_state *state =
454 (struct smb1srv_session_local_allocate_state *)private_data;
455 TDB_DATA key = dbwrap_record_get_key(rec);
456 uint32_t id = 0;
457 NTSTATUS status;
459 status = smbXsrv_session_local_key_to_id(key, &id);
460 if (!NT_STATUS_IS_OK(status)) {
461 state->status = status;
462 return -1;
465 if (id <= state->last_id) {
466 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
467 return -1;
469 state->last_id = id;
471 if (id > state->useable_id) {
472 state->status = NT_STATUS_OK;
473 return -1;
476 if (state->useable_id == state->highest_id) {
477 state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
478 return -1;
481 state->useable_id +=1;
482 return 0;
485 static NTSTATUS smb1srv_session_local_allocate_id(struct db_context *db,
486 uint32_t lowest_id,
487 uint32_t highest_id,
488 TALLOC_CTX *mem_ctx,
489 struct db_record **_rec,
490 uint32_t *_id)
492 struct smb1srv_session_local_allocate_state state = {
493 .lowest_id = lowest_id,
494 .highest_id = highest_id,
495 .last_id = 0,
496 .useable_id = lowest_id,
497 .status = NT_STATUS_INTERNAL_ERROR,
499 uint32_t i;
500 uint32_t range;
501 NTSTATUS status;
502 int count = 0;
504 *_rec = NULL;
505 *_id = 0;
507 if (lowest_id > highest_id) {
508 return NT_STATUS_INSUFFICIENT_RESOURCES;
512 * first we try randomly
514 range = (highest_id - lowest_id) + 1;
516 for (i = 0; i < (range / 2); i++) {
517 uint32_t id;
518 TDB_DATA val;
519 struct db_record *rec = NULL;
521 id = generate_random() % range;
522 id += lowest_id;
524 if (id < lowest_id) {
525 id = lowest_id;
527 if (id > highest_id) {
528 id = highest_id;
531 rec = smbXsrv_session_local_fetch_locked(db, id, mem_ctx);
532 if (rec == NULL) {
533 return NT_STATUS_INSUFFICIENT_RESOURCES;
536 val = dbwrap_record_get_value(rec);
537 if (val.dsize != 0) {
538 TALLOC_FREE(rec);
539 continue;
542 *_rec = rec;
543 *_id = id;
544 return NT_STATUS_OK;
548 * if the range is almost full,
549 * we traverse the whole table
550 * (this relies on sorted behavior of dbwrap_rbt)
552 status = dbwrap_traverse_read(db, smb1srv_session_local_allocate_traverse,
553 &state, &count);
554 if (NT_STATUS_IS_OK(status)) {
555 if (NT_STATUS_IS_OK(state.status)) {
556 return NT_STATUS_INTERNAL_ERROR;
559 if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
560 return state.status;
563 if (state.useable_id <= state.highest_id) {
564 state.status = NT_STATUS_OK;
565 } else {
566 return NT_STATUS_INSUFFICIENT_RESOURCES;
568 } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
570 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
572 * If we get anything else it is an error, because it
573 * means we did not manage to find a free slot in
574 * the db.
576 return NT_STATUS_INSUFFICIENT_RESOURCES;
579 if (NT_STATUS_IS_OK(state.status)) {
580 uint32_t id;
581 TDB_DATA val;
582 struct db_record *rec = NULL;
584 id = state.useable_id;
586 rec = smbXsrv_session_local_fetch_locked(db, id, mem_ctx);
587 if (rec == NULL) {
588 return NT_STATUS_INSUFFICIENT_RESOURCES;
591 val = dbwrap_record_get_value(rec);
592 if (val.dsize != 0) {
593 TALLOC_FREE(rec);
594 return NT_STATUS_INTERNAL_DB_CORRUPTION;
597 *_rec = rec;
598 *_id = id;
599 return NT_STATUS_OK;
602 return state.status;
605 struct smbXsrv_session_local_fetch_state {
606 struct smbXsrv_session *session;
607 NTSTATUS status;
610 static void smbXsrv_session_local_fetch_parser(TDB_DATA key, TDB_DATA data,
611 void *private_data)
613 struct smbXsrv_session_local_fetch_state *state =
614 (struct smbXsrv_session_local_fetch_state *)private_data;
615 void *ptr;
617 if (data.dsize != sizeof(ptr)) {
618 state->status = NT_STATUS_INTERNAL_DB_ERROR;
619 return;
622 memcpy(&ptr, data.dptr, data.dsize);
623 state->session = talloc_get_type_abort(ptr, struct smbXsrv_session);
624 state->status = NT_STATUS_OK;
627 static NTSTATUS smbXsrv_session_local_lookup(struct smbXsrv_session_table *table,
628 /* conn: optional */
629 struct smbXsrv_connection *conn,
630 uint32_t session_local_id,
631 NTTIME now,
632 struct smbXsrv_session **_session)
634 struct smbXsrv_session_local_fetch_state state = {
635 .session = NULL,
636 .status = NT_STATUS_INTERNAL_ERROR,
638 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
639 TDB_DATA key;
640 NTSTATUS status;
642 *_session = NULL;
644 if (session_local_id == 0) {
645 return NT_STATUS_USER_SESSION_DELETED;
648 if (table == NULL) {
649 /* this might happen before the end of negprot */
650 return NT_STATUS_USER_SESSION_DELETED;
653 if (table->local.db_ctx == NULL) {
654 return NT_STATUS_INTERNAL_ERROR;
657 key = smbXsrv_session_local_id_to_key(session_local_id, key_buf);
659 status = dbwrap_parse_record(table->local.db_ctx, key,
660 smbXsrv_session_local_fetch_parser,
661 &state);
662 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
663 return NT_STATUS_USER_SESSION_DELETED;
664 } else if (!NT_STATUS_IS_OK(status)) {
665 return status;
667 if (!NT_STATUS_IS_OK(state.status)) {
668 return state.status;
671 if (NT_STATUS_EQUAL(state.session->status, NT_STATUS_USER_SESSION_DELETED)) {
672 return NT_STATUS_USER_SESSION_DELETED;
676 * If a connection is specified check if the session is
677 * valid on the channel.
679 if (conn != NULL) {
680 struct smbXsrv_channel_global0 *c = NULL;
682 status = smbXsrv_session_find_channel(state.session, conn, &c);
683 if (!NT_STATUS_IS_OK(status)) {
684 return status;
688 state.session->idle_time = now;
690 if (!NT_STATUS_IS_OK(state.session->status)) {
691 *_session = state.session;
692 return state.session->status;
695 if (now > state.session->global->expiration_time) {
696 state.session->status = NT_STATUS_NETWORK_SESSION_EXPIRED;
699 *_session = state.session;
700 return state.session->status;
703 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0 *global)
705 return 0;
708 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
709 bool *is_free,
710 bool *was_free,
711 TALLOC_CTX *mem_ctx,
712 struct smbXsrv_session_global0 **_g,
713 uint32_t *pseqnum);
715 static NTSTATUS smbXsrv_session_global_allocate(struct db_context *db,
716 TALLOC_CTX *mem_ctx,
717 struct smbXsrv_session_global0 **_global)
719 uint32_t i;
720 struct smbXsrv_session_global0 *global = NULL;
721 uint32_t last_free = 0;
722 const uint32_t min_tries = 3;
724 *_global = NULL;
726 global = talloc_zero(mem_ctx, struct smbXsrv_session_global0);
727 if (global == NULL) {
728 return NT_STATUS_NO_MEMORY;
730 talloc_set_destructor(global, smbXsrv_session_global_destructor);
733 * Here we just randomly try the whole 32-bit space
735 * We use just 32-bit, because we want to reuse the
736 * ID for SRVSVC.
738 for (i = 0; i < UINT32_MAX; i++) {
739 bool is_free = false;
740 bool was_free = false;
741 uint32_t id;
743 if (i >= min_tries && last_free != 0) {
744 id = last_free;
745 } else {
746 id = generate_random();
748 if (id == 0) {
749 id++;
751 if (id == UINT32_MAX) {
752 id--;
755 global->db_rec = smbXsrv_session_global_fetch_locked(db, id,
756 mem_ctx);
757 if (global->db_rec == NULL) {
758 talloc_free(global);
759 return NT_STATUS_INSUFFICIENT_RESOURCES;
762 smbXsrv_session_global_verify_record(global->db_rec,
763 &is_free,
764 &was_free,
765 NULL, NULL, NULL);
767 if (!is_free) {
768 TALLOC_FREE(global->db_rec);
769 continue;
772 if (!was_free && i < min_tries) {
774 * The session_id is free now,
775 * but was not free before.
777 * This happens if a smbd crashed
778 * and did not cleanup the record.
780 * If this is one of our first tries,
781 * then we try to find a real free one.
783 if (last_free == 0) {
784 last_free = id;
786 TALLOC_FREE(global->db_rec);
787 continue;
790 global->session_global_id = id;
792 *_global = global;
793 return NT_STATUS_OK;
796 /* should not be reached */
797 talloc_free(global);
798 return NT_STATUS_INTERNAL_ERROR;
801 static void smbXsrv_session_global_verify_record(struct db_record *db_rec,
802 bool *is_free,
803 bool *was_free,
804 TALLOC_CTX *mem_ctx,
805 struct smbXsrv_session_global0 **_g,
806 uint32_t *pseqnum)
808 TDB_DATA key;
809 TDB_DATA val;
810 DATA_BLOB blob;
811 struct smbXsrv_session_globalB global_blob;
812 enum ndr_err_code ndr_err;
813 struct smbXsrv_session_global0 *global = NULL;
814 bool exists;
815 TALLOC_CTX *frame = talloc_stackframe();
817 *is_free = false;
819 if (was_free) {
820 *was_free = false;
822 if (_g) {
823 *_g = NULL;
825 if (pseqnum) {
826 *pseqnum = 0;
829 key = dbwrap_record_get_key(db_rec);
831 val = dbwrap_record_get_value(db_rec);
832 if (val.dsize == 0) {
833 TALLOC_FREE(frame);
834 *is_free = true;
835 if (was_free) {
836 *was_free = true;
838 return;
841 blob = data_blob_const(val.dptr, val.dsize);
843 ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
844 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
845 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
846 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
847 DEBUG(1,("smbXsrv_session_global_verify_record: "
848 "key '%s' ndr_pull_struct_blob - %s\n",
849 hex_encode_talloc(frame, key.dptr, key.dsize),
850 nt_errstr(status)));
851 TALLOC_FREE(frame);
852 *is_free = true;
853 if (was_free) {
854 *was_free = true;
856 return;
859 DEBUG(10,("smbXsrv_session_global_verify_record\n"));
860 if (DEBUGLVL(10)) {
861 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
864 if (global_blob.version != SMBXSRV_VERSION_0) {
865 DEBUG(0,("smbXsrv_session_global_verify_record: "
866 "key '%s' use unsupported version %u\n",
867 hex_encode_talloc(frame, key.dptr, key.dsize),
868 global_blob.version));
869 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
870 TALLOC_FREE(frame);
871 *is_free = true;
872 if (was_free) {
873 *was_free = true;
875 return;
878 global = global_blob.info.info0;
880 #define __BLOB_KEEP_SECRET(__blob) do { \
881 if ((__blob).length != 0) { \
882 talloc_keep_secret((__blob).data); \
884 } while(0)
886 uint32_t i;
887 __BLOB_KEEP_SECRET(global->application_key_blob);
888 __BLOB_KEEP_SECRET(global->signing_key_blob);
889 __BLOB_KEEP_SECRET(global->encryption_key_blob);
890 __BLOB_KEEP_SECRET(global->decryption_key_blob);
891 for (i = 0; i < global->num_channels; i++) {
892 __BLOB_KEEP_SECRET(global->channels[i].signing_key_blob);
895 #undef __BLOB_KEEP_SECRET
897 exists = serverid_exists(&global->channels[0].server_id);
898 if (!exists) {
899 struct server_id_buf idbuf;
900 DEBUG(2,("smbXsrv_session_global_verify_record: "
901 "key '%s' server_id %s does not exist.\n",
902 hex_encode_talloc(frame, key.dptr, key.dsize),
903 server_id_str_buf(global->channels[0].server_id,
904 &idbuf)));
905 if (DEBUGLVL(2)) {
906 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
908 TALLOC_FREE(frame);
909 dbwrap_record_delete(db_rec);
910 *is_free = true;
911 return;
914 if (_g) {
915 *_g = talloc_move(mem_ctx, &global);
917 if (pseqnum) {
918 *pseqnum = global_blob.seqnum;
920 TALLOC_FREE(frame);
923 static NTSTATUS smbXsrv_session_global_store(struct smbXsrv_session_global0 *global)
925 struct smbXsrv_session_globalB global_blob;
926 DATA_BLOB blob = data_blob_null;
927 TDB_DATA key;
928 TDB_DATA val;
929 NTSTATUS status;
930 enum ndr_err_code ndr_err;
933 * TODO: if we use other versions than '0'
934 * we would add glue code here, that would be able to
935 * store the information in the old format.
938 if (global->db_rec == NULL) {
939 return NT_STATUS_INTERNAL_ERROR;
942 key = dbwrap_record_get_key(global->db_rec);
943 val = dbwrap_record_get_value(global->db_rec);
945 ZERO_STRUCT(global_blob);
946 global_blob.version = smbXsrv_version_global_current();
947 if (val.dsize >= 8) {
948 global_blob.seqnum = IVAL(val.dptr, 4);
950 global_blob.seqnum += 1;
951 global_blob.info.info0 = global;
953 ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
954 (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_globalB);
955 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
956 status = ndr_map_error2ntstatus(ndr_err);
957 DEBUG(1,("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
958 hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
959 nt_errstr(status)));
960 TALLOC_FREE(global->db_rec);
961 return status;
964 val = make_tdb_data(blob.data, blob.length);
965 status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
966 if (!NT_STATUS_IS_OK(status)) {
967 DEBUG(1,("smbXsrv_session_global_store: key '%s' store - %s\n",
968 hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
969 nt_errstr(status)));
970 TALLOC_FREE(global->db_rec);
971 return status;
974 if (DEBUGLVL(10)) {
975 DEBUG(10,("smbXsrv_session_global_store: key '%s' stored\n",
976 hex_encode_talloc(global->db_rec, key.dptr, key.dsize)));
977 NDR_PRINT_DEBUG(smbXsrv_session_globalB, &global_blob);
980 TALLOC_FREE(global->db_rec);
982 return NT_STATUS_OK;
985 struct smb2srv_session_close_previous_state {
986 struct tevent_context *ev;
987 struct smbXsrv_connection *connection;
988 struct dom_sid *current_sid;
989 uint64_t previous_session_id;
990 uint64_t current_session_id;
991 struct db_record *db_rec;
992 uint64_t watch_instance;
993 uint32_t last_seqnum;
996 static void smb2srv_session_close_previous_cleanup(struct tevent_req *req,
997 enum tevent_req_state req_state)
999 struct smb2srv_session_close_previous_state *state =
1000 tevent_req_data(req,
1001 struct smb2srv_session_close_previous_state);
1003 if (state->db_rec != NULL) {
1004 dbwrap_watched_watch_remove_instance(state->db_rec,
1005 state->watch_instance);
1006 state->watch_instance = 0;
1007 TALLOC_FREE(state->db_rec);
1011 static void smb2srv_session_close_previous_check(struct tevent_req *req);
1012 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq);
1014 struct tevent_req *smb2srv_session_close_previous_send(TALLOC_CTX *mem_ctx,
1015 struct tevent_context *ev,
1016 struct smbXsrv_connection *conn,
1017 struct auth_session_info *session_info,
1018 uint64_t previous_session_id,
1019 uint64_t current_session_id)
1021 struct tevent_req *req;
1022 struct smb2srv_session_close_previous_state *state;
1023 uint32_t global_id = previous_session_id & UINT32_MAX;
1024 uint64_t global_zeros = previous_session_id & 0xFFFFFFFF00000000LLU;
1025 struct smbXsrv_session_table *table = conn->client->session_table;
1026 struct security_token *current_token = NULL;
1028 req = tevent_req_create(mem_ctx, &state,
1029 struct smb2srv_session_close_previous_state);
1030 if (req == NULL) {
1031 return NULL;
1033 state->ev = ev;
1034 state->connection = conn;
1035 state->previous_session_id = previous_session_id;
1036 state->current_session_id = current_session_id;
1038 tevent_req_set_cleanup_fn(req, smb2srv_session_close_previous_cleanup);
1040 if (global_zeros != 0) {
1041 tevent_req_done(req);
1042 return tevent_req_post(req, ev);
1045 if (session_info == NULL) {
1046 tevent_req_done(req);
1047 return tevent_req_post(req, ev);
1049 current_token = session_info->security_token;
1051 if (current_token->num_sids > PRIMARY_USER_SID_INDEX) {
1052 state->current_sid = &current_token->sids[PRIMARY_USER_SID_INDEX];
1055 if (state->current_sid == NULL) {
1056 tevent_req_done(req);
1057 return tevent_req_post(req, ev);
1060 if (!security_token_has_nt_authenticated_users(current_token)) {
1061 /* TODO */
1062 tevent_req_done(req);
1063 return tevent_req_post(req, ev);
1066 state->db_rec = smbXsrv_session_global_fetch_locked(
1067 table->global.db_ctx,
1068 global_id,
1069 state /* TALLOC_CTX */);
1070 if (state->db_rec == NULL) {
1071 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1072 return tevent_req_post(req, ev);
1075 smb2srv_session_close_previous_check(req);
1076 if (!tevent_req_is_in_progress(req)) {
1077 return tevent_req_post(req, ev);
1080 return req;
1083 static void smb2srv_session_close_previous_check(struct tevent_req *req)
1085 struct smb2srv_session_close_previous_state *state =
1086 tevent_req_data(req,
1087 struct smb2srv_session_close_previous_state);
1088 struct smbXsrv_connection *conn = state->connection;
1089 DATA_BLOB blob;
1090 struct security_token *previous_token = NULL;
1091 struct smbXsrv_session_global0 *global = NULL;
1092 enum ndr_err_code ndr_err;
1093 struct smbXsrv_session_close0 close_info0;
1094 struct smbXsrv_session_closeB close_blob;
1095 struct tevent_req *subreq = NULL;
1096 NTSTATUS status;
1097 bool is_free = false;
1098 uint32_t seqnum = 0;
1100 smbXsrv_session_global_verify_record(state->db_rec,
1101 &is_free,
1102 NULL,
1103 state,
1104 &global,
1105 &seqnum);
1107 if (is_free) {
1108 tevent_req_done(req);
1109 return;
1112 if (global->auth_session_info == NULL) {
1113 tevent_req_done(req);
1114 return;
1117 previous_token = global->auth_session_info->security_token;
1119 if (!security_token_is_sid(previous_token, state->current_sid)) {
1120 tevent_req_done(req);
1121 return;
1125 * If the record changed, but we are not happy with the change yet,
1126 * we better remove ourself from the waiter list
1127 * (most likely the first position)
1128 * and re-add us at the end of the list.
1130 * This gives other waiters a change
1131 * to make progress.
1133 * Otherwise we'll keep our waiter instance alive,
1134 * keep waiting (most likely at first position).
1135 * It means the order of watchers stays fair.
1137 if (state->last_seqnum != seqnum) {
1138 state->last_seqnum = seqnum;
1139 dbwrap_watched_watch_remove_instance(state->db_rec,
1140 state->watch_instance);
1141 state->watch_instance =
1142 dbwrap_watched_watch_add_instance(state->db_rec);
1145 subreq = dbwrap_watched_watch_send(state, state->ev, state->db_rec,
1146 state->watch_instance,
1147 (struct server_id){0});
1148 if (tevent_req_nomem(subreq, req)) {
1149 return;
1151 tevent_req_set_callback(subreq,
1152 smb2srv_session_close_previous_modified,
1153 req);
1155 close_info0.old_session_global_id = global->session_global_id;
1156 close_info0.old_session_wire_id = global->session_wire_id;
1157 close_info0.old_creation_time = global->creation_time;
1158 close_info0.new_session_wire_id = state->current_session_id;
1160 ZERO_STRUCT(close_blob);
1161 close_blob.version = smbXsrv_version_global_current();
1162 close_blob.info.info0 = &close_info0;
1164 ndr_err = ndr_push_struct_blob(&blob, state, &close_blob,
1165 (ndr_push_flags_fn_t)ndr_push_smbXsrv_session_closeB);
1166 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1167 status = ndr_map_error2ntstatus(ndr_err);
1168 DEBUG(1,("smb2srv_session_close_previous_check: "
1169 "old_session[%llu] new_session[%llu] ndr_push - %s\n",
1170 (unsigned long long)close_info0.old_session_wire_id,
1171 (unsigned long long)close_info0.new_session_wire_id,
1172 nt_errstr(status)));
1173 tevent_req_nterror(req, status);
1174 return;
1177 status = messaging_send(conn->client->msg_ctx,
1178 global->channels[0].server_id,
1179 MSG_SMBXSRV_SESSION_CLOSE, &blob);
1180 TALLOC_FREE(global);
1181 if (tevent_req_nterror(req, status)) {
1182 return;
1185 TALLOC_FREE(state->db_rec);
1186 return;
1189 static void smb2srv_session_close_previous_modified(struct tevent_req *subreq)
1191 struct tevent_req *req =
1192 tevent_req_callback_data(subreq,
1193 struct tevent_req);
1194 struct smb2srv_session_close_previous_state *state =
1195 tevent_req_data(req,
1196 struct smb2srv_session_close_previous_state);
1197 uint32_t global_id;
1198 NTSTATUS status;
1199 uint64_t instance = 0;
1201 status = dbwrap_watched_watch_recv(subreq, &instance, NULL, NULL);
1202 TALLOC_FREE(subreq);
1203 if (tevent_req_nterror(req, status)) {
1204 return;
1207 state->watch_instance = instance;
1209 global_id = state->previous_session_id & UINT32_MAX;
1211 state->db_rec = smbXsrv_session_global_fetch_locked(
1212 state->connection->client->session_table->global.db_ctx,
1213 global_id, state /* TALLOC_CTX */);
1214 if (state->db_rec == NULL) {
1215 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1216 return;
1219 smb2srv_session_close_previous_check(req);
1222 NTSTATUS smb2srv_session_close_previous_recv(struct tevent_req *req)
1224 NTSTATUS status;
1226 if (tevent_req_is_nterror(req, &status)) {
1227 tevent_req_received(req);
1228 return status;
1231 tevent_req_received(req);
1232 return NT_STATUS_OK;
1235 static NTSTATUS smbXsrv_session_clear_and_logoff(struct smbXsrv_session *session)
1237 NTSTATUS status;
1238 struct smbXsrv_connection *xconn = NULL;
1240 if (session->client != NULL) {
1241 xconn = session->client->connections;
1244 for (; xconn != NULL; xconn = xconn->next) {
1245 struct smbd_smb2_request *preq;
1247 for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
1248 if (preq->session != session) {
1249 continue;
1252 preq->session = NULL;
1254 * If we no longer have a session we can't
1255 * sign or encrypt replies.
1257 preq->do_signing = false;
1258 preq->do_encryption = false;
1259 preq->preauth = NULL;
1263 status = smbXsrv_session_logoff(session);
1264 return status;
1267 static int smbXsrv_session_destructor(struct smbXsrv_session *session)
1269 NTSTATUS status;
1271 DBG_DEBUG("destructing session(%llu)\n",
1272 (unsigned long long)session->global->session_wire_id);
1274 status = smbXsrv_session_clear_and_logoff(session);
1275 if (!NT_STATUS_IS_OK(status)) {
1276 DEBUG(0, ("smbXsrv_session_destructor: "
1277 "smbXsrv_session_logoff() failed: %s\n",
1278 nt_errstr(status)));
1281 TALLOC_FREE(session->global);
1283 return 0;
1286 NTSTATUS smbXsrv_session_create(struct smbXsrv_connection *conn,
1287 NTTIME now,
1288 struct smbXsrv_session **_session)
1290 struct smbXsrv_session_table *table = conn->client->session_table;
1291 struct db_record *local_rec = NULL;
1292 struct smbXsrv_session *session = NULL;
1293 void *ptr = NULL;
1294 TDB_DATA val;
1295 struct smbXsrv_session_global0 *global = NULL;
1296 struct smbXsrv_channel_global0 *channel = NULL;
1297 NTSTATUS status;
1299 if (table->local.num_sessions >= table->local.max_sessions) {
1300 return NT_STATUS_INSUFFICIENT_RESOURCES;
1303 session = talloc_zero(table, struct smbXsrv_session);
1304 if (session == NULL) {
1305 return NT_STATUS_NO_MEMORY;
1307 session->table = table;
1308 session->idle_time = now;
1309 session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
1310 session->client = conn->client;
1311 session->homes_snum = -1;
1313 status = smbXsrv_session_global_allocate(table->global.db_ctx,
1314 session,
1315 &global);
1316 if (!NT_STATUS_IS_OK(status)) {
1317 TALLOC_FREE(session);
1318 return status;
1320 session->global = global;
1322 if (conn->protocol >= PROTOCOL_SMB2_02) {
1323 uint64_t id = global->session_global_id;
1325 global->connection_dialect = conn->smb2.server.dialect;
1327 global->session_wire_id = id;
1329 status = smb2srv_tcon_table_init(session);
1330 if (!NT_STATUS_IS_OK(status)) {
1331 TALLOC_FREE(session);
1332 return status;
1335 session->local_id = global->session_global_id;
1337 local_rec = smbXsrv_session_local_fetch_locked(
1338 table->local.db_ctx,
1339 session->local_id,
1340 session /* TALLOC_CTX */);
1341 if (local_rec == NULL) {
1342 TALLOC_FREE(session);
1343 return NT_STATUS_NO_MEMORY;
1346 val = dbwrap_record_get_value(local_rec);
1347 if (val.dsize != 0) {
1348 TALLOC_FREE(session);
1349 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1351 } else {
1353 status = smb1srv_session_local_allocate_id(table->local.db_ctx,
1354 table->local.lowest_id,
1355 table->local.highest_id,
1356 session,
1357 &local_rec,
1358 &session->local_id);
1359 if (!NT_STATUS_IS_OK(status)) {
1360 TALLOC_FREE(session);
1361 return status;
1364 global->session_wire_id = session->local_id;
1367 global->creation_time = now;
1368 global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY;
1370 status = smbXsrv_session_add_channel(session, conn, now, &channel);
1371 if (!NT_STATUS_IS_OK(status)) {
1372 TALLOC_FREE(session);
1373 return status;
1376 ptr = session;
1377 val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
1378 status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
1379 TALLOC_FREE(local_rec);
1380 if (!NT_STATUS_IS_OK(status)) {
1381 TALLOC_FREE(session);
1382 return status;
1384 table->local.num_sessions += 1;
1386 talloc_set_destructor(session, smbXsrv_session_destructor);
1388 status = smbXsrv_session_global_store(global);
1389 if (!NT_STATUS_IS_OK(status)) {
1390 DEBUG(0,("smbXsrv_session_create: "
1391 "global_id (0x%08x) store failed - %s\n",
1392 session->global->session_global_id,
1393 nt_errstr(status)));
1394 TALLOC_FREE(session);
1395 return status;
1398 if (DEBUGLVL(10)) {
1399 struct smbXsrv_sessionB session_blob = {
1400 .version = SMBXSRV_VERSION_0,
1401 .info.info0 = session,
1404 DEBUG(10,("smbXsrv_session_create: global_id (0x%08x) stored\n",
1405 session->global->session_global_id));
1406 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1409 *_session = session;
1410 return NT_STATUS_OK;
1413 NTSTATUS smbXsrv_session_add_channel(struct smbXsrv_session *session,
1414 struct smbXsrv_connection *conn,
1415 NTTIME now,
1416 struct smbXsrv_channel_global0 **_c)
1418 struct smbXsrv_session_global0 *global = session->global;
1419 struct smbXsrv_channel_global0 *c = NULL;
1421 if (global->num_channels > 31) {
1423 * Windows allow up to 32 channels
1425 return NT_STATUS_INSUFFICIENT_RESOURCES;
1428 c = talloc_realloc(global,
1429 global->channels,
1430 struct smbXsrv_channel_global0,
1431 global->num_channels + 1);
1432 if (c == NULL) {
1433 return NT_STATUS_NO_MEMORY;
1435 global->channels = c;
1437 c = &global->channels[global->num_channels];
1438 ZERO_STRUCTP(c);
1440 c->server_id = messaging_server_id(conn->client->msg_ctx);
1441 c->channel_id = conn->channel_id;
1442 c->creation_time = now;
1443 c->local_address = tsocket_address_string(conn->local_address,
1444 global->channels);
1445 if (c->local_address == NULL) {
1446 return NT_STATUS_NO_MEMORY;
1448 c->remote_address = tsocket_address_string(conn->remote_address,
1449 global->channels);
1450 if (c->remote_address == NULL) {
1451 return NT_STATUS_NO_MEMORY;
1453 c->remote_name = talloc_strdup(global->channels,
1454 conn->remote_hostname);
1455 if (c->remote_name == NULL) {
1456 return NT_STATUS_NO_MEMORY;
1458 c->connection = conn;
1460 global->num_channels += 1;
1462 *_c = c;
1463 return NT_STATUS_OK;
1466 NTSTATUS smbXsrv_session_update(struct smbXsrv_session *session)
1468 struct smbXsrv_session_table *table = session->table;
1469 NTSTATUS status;
1471 if (session->global->db_rec != NULL) {
1472 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1473 "Called with db_rec != NULL'\n",
1474 session->global->session_global_id));
1475 return NT_STATUS_INTERNAL_ERROR;
1478 if (table == NULL) {
1479 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1480 "Called with table == NULL'\n",
1481 session->global->session_global_id));
1482 return NT_STATUS_INTERNAL_ERROR;
1485 session->global->db_rec = smbXsrv_session_global_fetch_locked(
1486 table->global.db_ctx,
1487 session->global->session_global_id,
1488 session->global /* TALLOC_CTX */);
1489 if (session->global->db_rec == NULL) {
1490 return NT_STATUS_INTERNAL_DB_ERROR;
1493 status = smbXsrv_session_global_store(session->global);
1494 if (!NT_STATUS_IS_OK(status)) {
1495 DEBUG(0,("smbXsrv_session_update: "
1496 "global_id (0x%08x) store failed - %s\n",
1497 session->global->session_global_id,
1498 nt_errstr(status)));
1499 return status;
1502 if (DEBUGLVL(10)) {
1503 struct smbXsrv_sessionB session_blob = {
1504 .version = SMBXSRV_VERSION_0,
1505 .info.info0 = session,
1508 DEBUG(10,("smbXsrv_session_update: global_id (0x%08x) stored\n",
1509 session->global->session_global_id));
1510 NDR_PRINT_DEBUG(smbXsrv_sessionB, &session_blob);
1513 return NT_STATUS_OK;
1516 NTSTATUS smbXsrv_session_find_channel(const struct smbXsrv_session *session,
1517 const struct smbXsrv_connection *conn,
1518 struct smbXsrv_channel_global0 **_c)
1520 uint32_t i;
1522 for (i=0; i < session->global->num_channels; i++) {
1523 struct smbXsrv_channel_global0 *c = &session->global->channels[i];
1525 if (c->channel_id != conn->channel_id) {
1526 continue;
1529 if (c->connection != conn) {
1530 continue;
1533 *_c = c;
1534 return NT_STATUS_OK;
1537 return NT_STATUS_USER_SESSION_DELETED;
1540 NTSTATUS smbXsrv_session_find_auth(const struct smbXsrv_session *session,
1541 const struct smbXsrv_connection *conn,
1542 NTTIME now,
1543 struct smbXsrv_session_auth0 **_a)
1545 struct smbXsrv_session_auth0 *a;
1547 for (a = session->pending_auth; a != NULL; a = a->next) {
1548 if (a->channel_id != conn->channel_id) {
1549 continue;
1552 if (a->connection == conn) {
1553 if (now != 0) {
1554 a->idle_time = now;
1556 *_a = a;
1557 return NT_STATUS_OK;
1561 return NT_STATUS_USER_SESSION_DELETED;
1564 static int smbXsrv_session_auth0_destructor(struct smbXsrv_session_auth0 *a)
1566 if (a->session == NULL) {
1567 return 0;
1570 DLIST_REMOVE(a->session->pending_auth, a);
1571 a->session = NULL;
1572 return 0;
1575 NTSTATUS smbXsrv_session_create_auth(struct smbXsrv_session *session,
1576 struct smbXsrv_connection *conn,
1577 NTTIME now,
1578 uint8_t in_flags,
1579 uint8_t in_security_mode,
1580 struct smbXsrv_session_auth0 **_a)
1582 struct smbXsrv_session_auth0 *a;
1583 NTSTATUS status;
1585 status = smbXsrv_session_find_auth(session, conn, 0, &a);
1586 if (NT_STATUS_IS_OK(status)) {
1587 return NT_STATUS_INTERNAL_ERROR;
1590 a = talloc_zero(session, struct smbXsrv_session_auth0);
1591 if (a == NULL) {
1592 return NT_STATUS_NO_MEMORY;
1594 a->session = session;
1595 a->connection = conn;
1596 a->in_flags = in_flags;
1597 a->in_security_mode = in_security_mode;
1598 a->creation_time = now;
1599 a->idle_time = now;
1600 a->channel_id = conn->channel_id;
1602 if (conn->protocol >= PROTOCOL_SMB3_11) {
1603 a->preauth = talloc(a, struct smbXsrv_preauth);
1604 if (a->preauth == NULL) {
1605 TALLOC_FREE(session);
1606 return NT_STATUS_NO_MEMORY;
1608 *a->preauth = conn->smb2.preauth;
1611 talloc_set_destructor(a, smbXsrv_session_auth0_destructor);
1612 DLIST_ADD_END(session->pending_auth, a);
1614 *_a = a;
1615 return NT_STATUS_OK;
1618 static void smbXsrv_session_remove_channel_done(struct tevent_req *subreq);
1620 NTSTATUS smbXsrv_session_remove_channel(struct smbXsrv_session *session,
1621 struct smbXsrv_connection *xconn)
1623 struct smbXsrv_session_auth0 *a = NULL;
1624 struct smbXsrv_channel_global0 *c = NULL;
1625 NTSTATUS status;
1626 bool need_update = false;
1628 status = smbXsrv_session_find_auth(session, xconn, 0, &a);
1629 if (!NT_STATUS_IS_OK(status)) {
1630 a = NULL;
1632 status = smbXsrv_session_find_channel(session, xconn, &c);
1633 if (!NT_STATUS_IS_OK(status)) {
1634 c = NULL;
1637 if (a != NULL) {
1638 smbXsrv_session_auth0_destructor(a);
1639 a->connection = NULL;
1640 need_update = true;
1643 if (c != NULL) {
1644 struct smbXsrv_session_global0 *global = session->global;
1645 ptrdiff_t n;
1647 n = (c - global->channels);
1648 if (n >= global->num_channels || n < 0) {
1649 return NT_STATUS_INTERNAL_ERROR;
1651 ARRAY_DEL_ELEMENT(global->channels, n, global->num_channels);
1652 global->num_channels--;
1653 if (global->num_channels == 0) {
1654 struct smbXsrv_client *client = session->client;
1655 struct tevent_queue *xconn_wait_queue =
1656 xconn->transport.shutdown_wait_queue;
1657 struct tevent_req *subreq = NULL;
1660 * Let the connection wait until the session is
1661 * destroyed.
1663 * We don't set a callback, as we just want to block the
1664 * wait queue and the talloc_free() of the session will
1665 * remove the item from the wait queue in order
1666 * to remove allow the connection to disapear.
1668 if (xconn_wait_queue != NULL) {
1669 subreq = tevent_queue_wait_send(session,
1670 client->raw_ev_ctx,
1671 xconn_wait_queue);
1672 if (subreq == NULL) {
1673 status = NT_STATUS_NO_MEMORY;
1674 DBG_ERR("tevent_queue_wait_send() session(%llu) failed: %s\n",
1675 (unsigned long long)session->global->session_wire_id,
1676 nt_errstr(status));
1677 return status;
1682 * This is garanteed to set
1683 * session->status = NT_STATUS_USER_SESSION_DELETED
1684 * even if NULL is returned.
1686 subreq = smb2srv_session_shutdown_send(session,
1687 client->raw_ev_ctx,
1688 session,
1689 NULL);
1690 if (subreq == NULL) {
1691 status = NT_STATUS_NO_MEMORY;
1692 DBG_ERR("smb2srv_session_shutdown_send(%llu) failed: %s\n",
1693 (unsigned long long)session->global->session_wire_id,
1694 nt_errstr(status));
1695 return status;
1697 tevent_req_set_callback(subreq,
1698 smbXsrv_session_remove_channel_done,
1699 session);
1701 need_update = true;
1704 if (!need_update) {
1705 return NT_STATUS_OK;
1708 return smbXsrv_session_update(session);
1711 static void smbXsrv_session_remove_channel_done(struct tevent_req *subreq)
1713 struct smbXsrv_session *session =
1714 tevent_req_callback_data(subreq,
1715 struct smbXsrv_session);
1716 NTSTATUS status;
1718 status = smb2srv_session_shutdown_recv(subreq);
1719 TALLOC_FREE(subreq);
1720 if (!NT_STATUS_IS_OK(status)) {
1721 DBG_ERR("smb2srv_session_shutdown_recv(%llu) failed: %s\n",
1722 (unsigned long long)session->global->session_wire_id,
1723 nt_errstr(status));
1726 status = smbXsrv_session_logoff(session);
1727 if (!NT_STATUS_IS_OK(status)) {
1728 DBG_ERR("smbXsrv_session_logoff(%llu) failed: %s\n",
1729 (unsigned long long)session->global->session_wire_id,
1730 nt_errstr(status));
1733 TALLOC_FREE(session);
1736 struct smb2srv_session_shutdown_state {
1737 struct tevent_queue *wait_queue;
1740 static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq);
1742 struct tevent_req *smb2srv_session_shutdown_send(TALLOC_CTX *mem_ctx,
1743 struct tevent_context *ev,
1744 struct smbXsrv_session *session,
1745 struct smbd_smb2_request *current_req)
1747 struct tevent_req *req;
1748 struct smb2srv_session_shutdown_state *state;
1749 struct tevent_req *subreq;
1750 struct smbXsrv_connection *xconn = NULL;
1751 size_t len = 0;
1754 * Make sure that no new request will be able to use this session.
1756 session->status = NT_STATUS_USER_SESSION_DELETED;
1758 req = tevent_req_create(mem_ctx, &state,
1759 struct smb2srv_session_shutdown_state);
1760 if (req == NULL) {
1761 return NULL;
1764 state->wait_queue = tevent_queue_create(state, "smb2srv_session_shutdown_queue");
1765 if (tevent_req_nomem(state->wait_queue, req)) {
1766 return tevent_req_post(req, ev);
1769 for (xconn = session->client->connections; xconn != NULL; xconn = xconn->next) {
1770 struct smbd_smb2_request *preq;
1772 for (preq = xconn->smb2.requests; preq != NULL; preq = preq->next) {
1773 if (preq == current_req) {
1774 /* Can't cancel current request. */
1775 continue;
1777 if (preq->session != session) {
1778 /* Request on different session. */
1779 continue;
1782 if (preq->subreq != NULL) {
1783 tevent_req_cancel(preq->subreq);
1787 * Now wait until the request is finished.
1789 * We don't set a callback, as we just want to block the
1790 * wait queue and the talloc_free() of the request will
1791 * remove the item from the wait queue.
1793 subreq = tevent_queue_wait_send(preq, ev, state->wait_queue);
1794 if (tevent_req_nomem(subreq, req)) {
1795 return tevent_req_post(req, ev);
1800 len = tevent_queue_length(state->wait_queue);
1801 if (len == 0) {
1802 tevent_req_done(req);
1803 return tevent_req_post(req, ev);
1807 * Now we add our own waiter to the end of the queue,
1808 * this way we get notified when all pending requests are finished
1809 * and send to the socket.
1811 subreq = tevent_queue_wait_send(state, ev, state->wait_queue);
1812 if (tevent_req_nomem(subreq, req)) {
1813 return tevent_req_post(req, ev);
1815 tevent_req_set_callback(subreq, smb2srv_session_shutdown_wait_done, req);
1817 return req;
1820 static void smb2srv_session_shutdown_wait_done(struct tevent_req *subreq)
1822 struct tevent_req *req =
1823 tevent_req_callback_data(subreq,
1824 struct tevent_req);
1826 tevent_queue_wait_recv(subreq);
1827 TALLOC_FREE(subreq);
1829 tevent_req_done(req);
1832 NTSTATUS smb2srv_session_shutdown_recv(struct tevent_req *req)
1834 return tevent_req_simple_recv_ntstatus(req);
1837 NTSTATUS smbXsrv_session_logoff(struct smbXsrv_session *session)
1839 struct smbXsrv_session_table *table;
1840 struct db_record *local_rec = NULL;
1841 struct db_record *global_rec = NULL;
1842 struct smbd_server_connection *sconn = NULL;
1843 NTSTATUS status;
1844 NTSTATUS error = NT_STATUS_OK;
1846 if (session->table == NULL) {
1847 return NT_STATUS_OK;
1850 table = session->table;
1851 session->table = NULL;
1853 sconn = session->client->sconn;
1854 session->client = NULL;
1855 session->status = NT_STATUS_USER_SESSION_DELETED;
1858 * For SMB2 this is a bit redundant as files are also close
1859 * below via smb2srv_tcon_disconnect_all() -> ... ->
1860 * smbXsrv_tcon_disconnect() -> close_cnum() ->
1861 * file_close_conn().
1863 file_close_user(sconn, session->global->session_wire_id);
1865 if (session->tcon_table != NULL) {
1867 * Note: We only have a tcon_table for SMB2.
1869 status = smb2srv_tcon_disconnect_all(session);
1870 if (!NT_STATUS_IS_OK(status)) {
1871 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1872 "smb2srv_tcon_disconnect_all() failed: %s\n",
1873 session->global->session_global_id,
1874 nt_errstr(status)));
1875 error = status;
1879 invalidate_vuid(sconn, session->global->session_wire_id);
1881 global_rec = session->global->db_rec;
1882 session->global->db_rec = NULL;
1883 if (global_rec == NULL) {
1884 global_rec = smbXsrv_session_global_fetch_locked(
1885 table->global.db_ctx,
1886 session->global->session_global_id,
1887 session->global /* TALLOC_CTX */);
1888 if (global_rec == NULL) {
1889 error = NT_STATUS_INTERNAL_ERROR;
1893 if (global_rec != NULL) {
1894 status = dbwrap_record_delete(global_rec);
1895 if (!NT_STATUS_IS_OK(status)) {
1896 TDB_DATA key = dbwrap_record_get_key(global_rec);
1898 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1899 "failed to delete global key '%s': %s\n",
1900 session->global->session_global_id,
1901 hex_encode_talloc(global_rec, key.dptr,
1902 key.dsize),
1903 nt_errstr(status)));
1904 error = status;
1907 TALLOC_FREE(global_rec);
1909 local_rec = session->db_rec;
1910 if (local_rec == NULL) {
1911 local_rec = smbXsrv_session_local_fetch_locked(
1912 table->local.db_ctx,
1913 session->local_id,
1914 session /* TALLOC_CTX */);
1915 if (local_rec == NULL) {
1916 error = NT_STATUS_INTERNAL_ERROR;
1920 if (local_rec != NULL) {
1921 status = dbwrap_record_delete(local_rec);
1922 if (!NT_STATUS_IS_OK(status)) {
1923 TDB_DATA key = dbwrap_record_get_key(local_rec);
1925 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1926 "failed to delete local key '%s': %s\n",
1927 session->global->session_global_id,
1928 hex_encode_talloc(local_rec, key.dptr,
1929 key.dsize),
1930 nt_errstr(status)));
1931 error = status;
1933 table->local.num_sessions -= 1;
1935 if (session->db_rec == NULL) {
1936 TALLOC_FREE(local_rec);
1938 session->db_rec = NULL;
1940 return error;
1943 struct smbXsrv_session_logoff_all_state {
1944 NTSTATUS first_status;
1945 int errors;
1948 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1949 void *private_data);
1951 NTSTATUS smbXsrv_session_logoff_all(struct smbXsrv_client *client)
1953 struct smbXsrv_session_table *table = client->session_table;
1954 struct smbXsrv_session_logoff_all_state state;
1955 NTSTATUS status;
1956 int count = 0;
1958 if (table == NULL) {
1959 DEBUG(10, ("smbXsrv_session_logoff_all: "
1960 "empty session_table, nothing to do.\n"));
1961 return NT_STATUS_OK;
1964 ZERO_STRUCT(state);
1966 status = dbwrap_traverse(table->local.db_ctx,
1967 smbXsrv_session_logoff_all_callback,
1968 &state, &count);
1969 if (!NT_STATUS_IS_OK(status)) {
1970 DEBUG(0, ("smbXsrv_session_logoff_all: "
1971 "dbwrap_traverse() failed: %s\n",
1972 nt_errstr(status)));
1973 return status;
1976 if (!NT_STATUS_IS_OK(state.first_status)) {
1977 DEBUG(0, ("smbXsrv_session_logoff_all: "
1978 "count[%d] errors[%d] first[%s]\n",
1979 count, state.errors,
1980 nt_errstr(state.first_status)));
1981 return state.first_status;
1984 return NT_STATUS_OK;
1987 static int smbXsrv_session_logoff_all_callback(struct db_record *local_rec,
1988 void *private_data)
1990 struct smbXsrv_session_logoff_all_state *state =
1991 (struct smbXsrv_session_logoff_all_state *)private_data;
1992 TDB_DATA val;
1993 void *ptr = NULL;
1994 struct smbXsrv_session *session = NULL;
1995 NTSTATUS status;
1997 val = dbwrap_record_get_value(local_rec);
1998 if (val.dsize != sizeof(ptr)) {
1999 status = NT_STATUS_INTERNAL_ERROR;
2000 if (NT_STATUS_IS_OK(state->first_status)) {
2001 state->first_status = status;
2003 state->errors++;
2004 return 0;
2007 memcpy(&ptr, val.dptr, val.dsize);
2008 session = talloc_get_type_abort(ptr, struct smbXsrv_session);
2010 session->db_rec = local_rec;
2011 status = smbXsrv_session_clear_and_logoff(session);
2012 session->db_rec = NULL;
2013 if (!NT_STATUS_IS_OK(status)) {
2014 if (NT_STATUS_IS_OK(state->first_status)) {
2015 state->first_status = status;
2017 state->errors++;
2018 return 0;
2021 return 0;
2024 struct smbXsrv_session_local_trav_state {
2025 NTSTATUS status;
2026 int (*caller_cb)(struct smbXsrv_session *session,
2027 void *caller_data);
2028 void *caller_data;
2031 static int smbXsrv_session_local_traverse_cb(struct db_record *local_rec,
2032 void *private_data);
2034 NTSTATUS smbXsrv_session_local_traverse(
2035 struct smbXsrv_client *client,
2036 int (*caller_cb)(struct smbXsrv_session *session,
2037 void *caller_data),
2038 void *caller_data)
2040 struct smbXsrv_session_table *table = client->session_table;
2041 struct smbXsrv_session_local_trav_state state;
2042 NTSTATUS status;
2043 int count = 0;
2045 state = (struct smbXsrv_session_local_trav_state) {
2046 .status = NT_STATUS_OK,
2047 .caller_cb = caller_cb,
2048 .caller_data = caller_data,
2051 if (table == NULL) {
2052 DBG_DEBUG("empty session_table, nothing to do.\n");
2053 return NT_STATUS_OK;
2056 status = dbwrap_traverse(table->local.db_ctx,
2057 smbXsrv_session_local_traverse_cb,
2058 &state,
2059 &count);
2060 if (!NT_STATUS_IS_OK(status)) {
2061 DBG_ERR("dbwrap_traverse() failed: %s\n", nt_errstr(status));
2062 return status;
2064 if (!NT_STATUS_IS_OK(state.status)) {
2065 DBG_ERR("count[%d] status[%s]\n",
2066 count, nt_errstr(state.status));
2067 return state.status;
2070 return NT_STATUS_OK;
2073 static int smbXsrv_session_local_traverse_cb(struct db_record *local_rec,
2074 void *private_data)
2076 struct smbXsrv_session_local_trav_state *state =
2077 (struct smbXsrv_session_local_trav_state *)private_data;
2078 TDB_DATA val;
2079 void *ptr = NULL;
2080 struct smbXsrv_session *session = NULL;
2081 int ret;
2083 val = dbwrap_record_get_value(local_rec);
2084 if (val.dsize != sizeof(ptr)) {
2085 state->status = NT_STATUS_INTERNAL_ERROR;
2086 return -1;
2089 memcpy(&ptr, val.dptr, val.dsize);
2090 session = talloc_get_type_abort(ptr, struct smbXsrv_session);
2092 session->db_rec = local_rec;
2093 ret = state->caller_cb(session, state->caller_data);
2094 session->db_rec = NULL;
2096 return ret;
2099 struct smbXsrv_session_disconnect_xconn_state {
2100 struct smbXsrv_connection *xconn;
2101 NTSTATUS first_status;
2102 int errors;
2105 static int smbXsrv_session_disconnect_xconn_callback(struct db_record *local_rec,
2106 void *private_data);
2108 NTSTATUS smbXsrv_session_disconnect_xconn(struct smbXsrv_connection *xconn)
2110 struct smbXsrv_client *client = xconn->client;
2111 struct smbXsrv_session_table *table = client->session_table;
2112 struct smbXsrv_session_disconnect_xconn_state state;
2113 NTSTATUS status;
2114 int count = 0;
2116 if (table == NULL) {
2117 DBG_ERR("empty session_table, nothing to do.\n");
2118 return NT_STATUS_OK;
2121 ZERO_STRUCT(state);
2122 state.xconn = xconn;
2124 status = dbwrap_traverse(table->local.db_ctx,
2125 smbXsrv_session_disconnect_xconn_callback,
2126 &state, &count);
2127 if (!NT_STATUS_IS_OK(status)) {
2128 DBG_ERR("dbwrap_traverse() failed: %s\n",
2129 nt_errstr(status));
2130 return status;
2133 if (!NT_STATUS_IS_OK(state.first_status)) {
2134 DBG_ERR("count[%d] errors[%d] first[%s]\n",
2135 count, state.errors,
2136 nt_errstr(state.first_status));
2137 return state.first_status;
2140 return NT_STATUS_OK;
2143 static int smbXsrv_session_disconnect_xconn_callback(struct db_record *local_rec,
2144 void *private_data)
2146 struct smbXsrv_session_disconnect_xconn_state *state =
2147 (struct smbXsrv_session_disconnect_xconn_state *)private_data;
2148 TDB_DATA val;
2149 void *ptr = NULL;
2150 struct smbXsrv_session *session = NULL;
2151 NTSTATUS status;
2153 val = dbwrap_record_get_value(local_rec);
2154 if (val.dsize != sizeof(ptr)) {
2155 status = NT_STATUS_INTERNAL_ERROR;
2156 if (NT_STATUS_IS_OK(state->first_status)) {
2157 state->first_status = status;
2159 state->errors++;
2160 return 0;
2163 memcpy(&ptr, val.dptr, val.dsize);
2164 session = talloc_get_type_abort(ptr, struct smbXsrv_session);
2166 session->db_rec = local_rec;
2167 status = smbXsrv_session_remove_channel(session, state->xconn);
2168 session->db_rec = NULL;
2169 if (!NT_STATUS_IS_OK(status)) {
2170 if (NT_STATUS_IS_OK(state->first_status)) {
2171 state->first_status = status;
2173 state->errors++;
2176 return 0;
2179 NTSTATUS smb1srv_session_table_init(struct smbXsrv_connection *conn)
2182 * Allow a range from 1..65534 with 65534 values.
2184 return smbXsrv_session_table_init(conn, 1, UINT16_MAX - 1,
2185 UINT16_MAX - 1);
2188 NTSTATUS smb1srv_session_lookup(struct smbXsrv_connection *conn,
2189 uint16_t vuid, NTTIME now,
2190 struct smbXsrv_session **session)
2192 struct smbXsrv_session_table *table = conn->client->session_table;
2193 uint32_t local_id = vuid;
2195 return smbXsrv_session_local_lookup(table, conn, local_id, now,
2196 session);
2199 NTSTATUS smbXsrv_session_info_lookup(struct smbXsrv_client *client,
2200 uint64_t session_wire_id,
2201 struct auth_session_info **si)
2203 struct smbXsrv_session_table *table = client->session_table;
2204 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
2205 struct smbXsrv_session_local_fetch_state state = {
2206 .session = NULL,
2207 .status = NT_STATUS_INTERNAL_ERROR,
2209 TDB_DATA key;
2210 NTSTATUS status;
2212 if (session_wire_id == 0) {
2213 return NT_STATUS_USER_SESSION_DELETED;
2216 if (table == NULL) {
2217 /* this might happen before the end of negprot */
2218 return NT_STATUS_USER_SESSION_DELETED;
2221 if (table->local.db_ctx == NULL) {
2222 return NT_STATUS_INTERNAL_ERROR;
2225 key = smbXsrv_session_local_id_to_key(session_wire_id, key_buf);
2227 status = dbwrap_parse_record(table->local.db_ctx, key,
2228 smbXsrv_session_local_fetch_parser,
2229 &state);
2230 if (!NT_STATUS_IS_OK(status)) {
2231 return status;
2233 if (!NT_STATUS_IS_OK(state.status)) {
2234 return state.status;
2236 if (state.session->global->auth_session_info == NULL) {
2237 return NT_STATUS_USER_SESSION_DELETED;
2240 *si = state.session->global->auth_session_info;
2241 return NT_STATUS_OK;
2245 * In memory of get_valid_user_struct()
2247 * This function is similar to smbXsrv_session_local_lookup() and it's wrappers,
2248 * but it doesn't implement the state checks of
2249 * those. get_valid_smbXsrv_session() is NOT meant to be called to validate the
2250 * session wire-id of incoming SMB requests, it MUST only be used in later
2251 * internal processing where the session wire-id has already been validated.
2253 NTSTATUS get_valid_smbXsrv_session(struct smbXsrv_client *client,
2254 uint64_t session_wire_id,
2255 struct smbXsrv_session **session)
2257 struct smbXsrv_session_table *table = client->session_table;
2258 uint8_t key_buf[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE];
2259 struct smbXsrv_session_local_fetch_state state = {
2260 .session = NULL,
2261 .status = NT_STATUS_INTERNAL_ERROR,
2263 TDB_DATA key;
2264 NTSTATUS status;
2266 if (session_wire_id == 0) {
2267 return NT_STATUS_USER_SESSION_DELETED;
2270 if (table == NULL) {
2271 /* this might happen before the end of negprot */
2272 return NT_STATUS_USER_SESSION_DELETED;
2275 if (table->local.db_ctx == NULL) {
2276 return NT_STATUS_INTERNAL_ERROR;
2279 key = smbXsrv_session_local_id_to_key(session_wire_id, key_buf);
2281 status = dbwrap_parse_record(table->local.db_ctx, key,
2282 smbXsrv_session_local_fetch_parser,
2283 &state);
2284 if (!NT_STATUS_IS_OK(status)) {
2285 return status;
2287 if (!NT_STATUS_IS_OK(state.status)) {
2288 return state.status;
2290 if (state.session->global->auth_session_info == NULL) {
2291 return NT_STATUS_USER_SESSION_DELETED;
2294 *session = state.session;
2295 return NT_STATUS_OK;
2298 NTSTATUS smb2srv_session_lookup_global(struct smbXsrv_client *client,
2299 uint64_t session_wire_id,
2300 TALLOC_CTX *mem_ctx,
2301 struct smbXsrv_session **_session)
2303 TALLOC_CTX *frame = talloc_stackframe();
2304 struct smbXsrv_session_table *table = client->session_table;
2305 uint32_t global_id = session_wire_id & UINT32_MAX;
2306 uint64_t global_zeros = session_wire_id & 0xFFFFFFFF00000000LLU;
2307 struct smbXsrv_session *session = NULL;
2308 struct db_record *global_rec = NULL;
2309 bool is_free = false;
2310 NTSTATUS status;
2312 if (global_id == 0) {
2313 TALLOC_FREE(frame);
2314 return NT_STATUS_USER_SESSION_DELETED;
2316 if (global_zeros != 0) {
2317 TALLOC_FREE(frame);
2318 return NT_STATUS_USER_SESSION_DELETED;
2321 if (table == NULL) {
2322 /* this might happen before the end of negprot */
2323 TALLOC_FREE(frame);
2324 return NT_STATUS_USER_SESSION_DELETED;
2327 if (table->global.db_ctx == NULL) {
2328 TALLOC_FREE(frame);
2329 return NT_STATUS_INTERNAL_ERROR;
2332 session = talloc_zero(mem_ctx, struct smbXsrv_session);
2333 if (session == NULL) {
2334 TALLOC_FREE(frame);
2335 return NT_STATUS_NO_MEMORY;
2337 talloc_steal(frame, session);
2339 session->client = client;
2340 session->status = NT_STATUS_BAD_LOGON_SESSION_STATE;
2341 session->local_id = global_id;
2344 * This means smb2_get_new_nonce() will return
2345 * NT_STATUS_ENCRYPTION_FAILED.
2347 * But we intialize some random parts just in case...
2349 session->nonce_high_max = session->nonce_high = 0;
2350 generate_nonce_buffer((uint8_t *)&session->nonce_high_random,
2351 sizeof(session->nonce_high_random));
2352 generate_nonce_buffer((uint8_t *)&session->nonce_low,
2353 sizeof(session->nonce_low));
2355 global_rec = smbXsrv_session_global_fetch_locked(table->global.db_ctx,
2356 global_id,
2357 frame);
2358 if (global_rec == NULL) {
2359 TALLOC_FREE(frame);
2360 return NT_STATUS_INTERNAL_DB_ERROR;
2363 smbXsrv_session_global_verify_record(global_rec,
2364 &is_free,
2365 NULL,
2366 session,
2367 &session->global,
2368 NULL);
2369 if (is_free) {
2370 TALLOC_FREE(frame);
2371 return NT_STATUS_USER_SESSION_DELETED;
2375 * We don't have channels on this session
2376 * and only the main signing key
2378 session->global->num_channels = 0;
2379 status = smb2_signing_key_sign_create(session->global,
2380 session->global->signing_algo,
2381 NULL, /* no master key */
2382 NULL, /* derivations */
2383 &session->global->signing_key);
2384 if (!NT_STATUS_IS_OK(status)) {
2385 TALLOC_FREE(frame);
2386 return NT_STATUS_NO_MEMORY;
2388 session->global->signing_key->blob = session->global->signing_key_blob;
2389 session->global->signing_flags = 0;
2391 status = smb2_signing_key_cipher_create(session->global,
2392 session->global->encryption_cipher,
2393 NULL, /* no master key */
2394 NULL, /* derivations */
2395 &session->global->decryption_key);
2396 if (!NT_STATUS_IS_OK(status)) {
2397 TALLOC_FREE(frame);
2398 return NT_STATUS_NO_MEMORY;
2400 session->global->decryption_key->blob = session->global->decryption_key_blob;
2401 session->global->encryption_flags = 0;
2403 *_session = talloc_move(mem_ctx, &session);
2404 TALLOC_FREE(frame);
2405 return NT_STATUS_OK;
2408 NTSTATUS smb2srv_session_table_init(struct smbXsrv_connection *conn)
2411 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
2413 return smbXsrv_session_table_init(conn, 1, UINT32_MAX - 1,
2414 UINT16_MAX - 1);
2417 static NTSTATUS smb2srv_session_lookup_raw(struct smbXsrv_session_table *table,
2418 /* conn: optional */
2419 struct smbXsrv_connection *conn,
2420 uint64_t session_id, NTTIME now,
2421 struct smbXsrv_session **session)
2423 uint32_t local_id = session_id & UINT32_MAX;
2424 uint64_t local_zeros = session_id & 0xFFFFFFFF00000000LLU;
2426 if (local_zeros != 0) {
2427 return NT_STATUS_USER_SESSION_DELETED;
2430 return smbXsrv_session_local_lookup(table, conn, local_id, now,
2431 session);
2434 NTSTATUS smb2srv_session_lookup_conn(struct smbXsrv_connection *conn,
2435 uint64_t session_id, NTTIME now,
2436 struct smbXsrv_session **session)
2438 struct smbXsrv_session_table *table = conn->client->session_table;
2439 return smb2srv_session_lookup_raw(table, conn, session_id, now,
2440 session);
2443 NTSTATUS smb2srv_session_lookup_client(struct smbXsrv_client *client,
2444 uint64_t session_id, NTTIME now,
2445 struct smbXsrv_session **session)
2447 struct smbXsrv_session_table *table = client->session_table;
2448 return smb2srv_session_lookup_raw(table, NULL, session_id, now,
2449 session);
2452 struct smbXsrv_session_global_traverse_state {
2453 int (*fn)(struct smbXsrv_session_global0 *, void *);
2454 void *private_data;
2457 static int smbXsrv_session_global_traverse_fn(struct db_record *rec, void *data)
2459 int ret = -1;
2460 struct smbXsrv_session_global_traverse_state *state =
2461 (struct smbXsrv_session_global_traverse_state*)data;
2462 TDB_DATA key = dbwrap_record_get_key(rec);
2463 TDB_DATA val = dbwrap_record_get_value(rec);
2464 DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
2465 struct smbXsrv_session_globalB global_blob;
2466 enum ndr_err_code ndr_err;
2467 TALLOC_CTX *frame = talloc_stackframe();
2469 ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
2470 (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_session_globalB);
2471 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2472 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
2473 "key '%s' ndr_pull_struct_blob - %s\n",
2474 hex_encode_talloc(frame, key.dptr, key.dsize),
2475 ndr_errstr(ndr_err)));
2476 goto done;
2479 if (global_blob.version != SMBXSRV_VERSION_0) {
2480 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
2481 "key '%s' unsupported version - %d\n",
2482 hex_encode_talloc(frame, key.dptr, key.dsize),
2483 (int)global_blob.version));
2484 goto done;
2487 if (global_blob.info.info0 == NULL) {
2488 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
2489 "key '%s' info0 NULL pointer\n",
2490 hex_encode_talloc(frame, key.dptr, key.dsize)));
2491 goto done;
2494 global_blob.info.info0->db_rec = rec;
2495 ret = state->fn(global_blob.info.info0, state->private_data);
2496 done:
2497 TALLOC_FREE(frame);
2498 return ret;
2501 NTSTATUS smbXsrv_session_global_traverse(
2502 int (*fn)(struct smbXsrv_session_global0 *, void *),
2503 void *private_data)
2506 NTSTATUS status;
2507 int count = 0;
2508 struct smbXsrv_session_global_traverse_state state = {
2509 .fn = fn,
2510 .private_data = private_data,
2513 become_root();
2514 status = smbXsrv_session_global_init(NULL);
2515 if (!NT_STATUS_IS_OK(status)) {
2516 unbecome_root();
2517 DEBUG(0, ("Failed to initialize session_global: %s\n",
2518 nt_errstr(status)));
2519 return status;
2522 status = dbwrap_traverse_read(smbXsrv_session_global_db_ctx,
2523 smbXsrv_session_global_traverse_fn,
2524 &state,
2525 &count);
2526 unbecome_root();
2528 return status;