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/>.
22 #include "system/filesys.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"
33 #include "auth/gensec/gensec.h"
34 #include "../lib/tsocket/tsocket.h"
35 #include "../libcli/security/security.h"
37 #include "lib/util/util_tdb.h"
38 #include "librpc/gen_ndr/ndr_smbXsrv.h"
40 #include "lib/util/tevent_ntstatus.h"
41 #include "lib/global_contexts.h"
42 #include "source3/include/util_tdb.h"
44 struct smbXsrv_session_table
{
46 struct db_context
*db_ctx
;
49 uint32_t max_sessions
;
50 uint32_t num_sessions
;
53 struct db_context
*db_ctx
;
57 static struct db_context
*smbXsrv_session_global_db_ctx
= NULL
;
59 NTSTATUS
smbXsrv_session_global_init(struct messaging_context
*msg_ctx
)
61 char *global_path
= NULL
;
62 struct db_context
*backend
= NULL
;
63 struct db_context
*db_ctx
= NULL
;
65 if (smbXsrv_session_global_db_ctx
!= NULL
) {
70 * This contains secret information like session keys!
72 global_path
= lock_path(talloc_tos(), "smbXsrv_session_global.tdb");
73 if (global_path
== NULL
) {
74 return NT_STATUS_NO_MEMORY
;
77 backend
= db_open(NULL
, global_path
,
78 SMBD_VOLATILE_TDB_HASH_SIZE
,
79 SMBD_VOLATILE_TDB_FLAGS
,
80 O_RDWR
| O_CREAT
, 0600,
83 TALLOC_FREE(global_path
);
84 if (backend
== NULL
) {
87 status
= map_nt_error_from_unix_common(errno
);
92 db_ctx
= db_open_watched(NULL
, &backend
, global_messaging_context());
95 return NT_STATUS_NO_MEMORY
;
98 smbXsrv_session_global_db_ctx
= db_ctx
;
105 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
106 * has the same result as integer comparison between the uint32_t
109 * TODO: implement string based key
112 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
114 static TDB_DATA
smbXsrv_session_global_id_to_key(uint32_t id
,
119 RSIVAL(key_buf
, 0, id
);
121 key
= make_tdb_data(key_buf
, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
);
127 static NTSTATUS
smbXsrv_session_global_key_to_id(TDB_DATA key
, uint32_t *id
)
130 return NT_STATUS_INVALID_PARAMETER
;
133 if (key
.dsize
!= SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
) {
134 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
137 *id
= RIVAL(key
.dptr
, 0);
143 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
145 static TDB_DATA
smbXsrv_session_local_id_to_key(uint32_t id
,
150 RSIVAL(key_buf
, 0, id
);
152 key
= make_tdb_data(key_buf
, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
);
157 static NTSTATUS
smbXsrv_session_local_key_to_id(TDB_DATA key
, uint32_t *id
)
160 return NT_STATUS_INVALID_PARAMETER
;
163 if (key
.dsize
!= SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
) {
164 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
167 *id
= RIVAL(key
.dptr
, 0);
172 static struct db_record
*smbXsrv_session_global_fetch_locked(
173 struct db_context
*db
,
178 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
179 struct db_record
*rec
= NULL
;
181 key
= smbXsrv_session_global_id_to_key(id
, key_buf
);
183 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
186 DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id
,
193 static struct db_record
*smbXsrv_session_local_fetch_locked(
194 struct db_context
*db
,
199 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
200 struct db_record
*rec
= NULL
;
202 key
= smbXsrv_session_local_id_to_key(id
, key_buf
);
204 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
207 DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id
,
214 static void smbXsrv_session_close_loop(struct tevent_req
*subreq
);
216 static NTSTATUS
smbXsrv_session_table_init(struct smbXsrv_connection
*conn
,
219 uint32_t max_sessions
)
221 struct smbXsrv_client
*client
= conn
->client
;
222 struct smbXsrv_session_table
*table
;
224 struct tevent_req
*subreq
;
227 if (lowest_id
> highest_id
) {
228 return NT_STATUS_INTERNAL_ERROR
;
231 max_range
= highest_id
;
232 max_range
-= lowest_id
;
235 if (max_sessions
> max_range
) {
236 return NT_STATUS_INTERNAL_ERROR
;
239 table
= talloc_zero(client
, struct smbXsrv_session_table
);
241 return NT_STATUS_NO_MEMORY
;
244 table
->local
.db_ctx
= db_open_rbt(table
);
245 if (table
->local
.db_ctx
== NULL
) {
247 return NT_STATUS_NO_MEMORY
;
249 table
->local
.lowest_id
= lowest_id
;
250 table
->local
.highest_id
= highest_id
;
251 table
->local
.max_sessions
= max_sessions
;
253 status
= smbXsrv_session_global_init(client
->msg_ctx
);
254 if (!NT_STATUS_IS_OK(status
)) {
259 table
->global
.db_ctx
= smbXsrv_session_global_db_ctx
;
261 subreq
= messaging_read_send(table
,
264 MSG_SMBXSRV_SESSION_CLOSE
);
265 if (subreq
== NULL
) {
267 return NT_STATUS_NO_MEMORY
;
269 tevent_req_set_callback(subreq
, smbXsrv_session_close_loop
, client
);
271 client
->session_table
= table
;
275 static void smbXsrv_session_close_shutdown_done(struct tevent_req
*subreq
);
277 static void smbXsrv_session_close_loop(struct tevent_req
*subreq
)
279 struct smbXsrv_client
*client
=
280 tevent_req_callback_data(subreq
,
281 struct smbXsrv_client
);
282 struct smbXsrv_session_table
*table
= client
->session_table
;
284 struct messaging_rec
*rec
= NULL
;
285 struct smbXsrv_session_closeB close_blob
;
286 enum ndr_err_code ndr_err
;
287 struct smbXsrv_session_close0
*close_info0
= NULL
;
288 struct smbXsrv_session
*session
= NULL
;
290 struct timeval tv
= timeval_current();
291 NTTIME now
= timeval_to_nttime(&tv
);
293 ret
= messaging_read_recv(subreq
, talloc_tos(), &rec
);
299 ndr_err
= ndr_pull_struct_blob(&rec
->buf
, rec
, &close_blob
,
300 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_closeB
);
301 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
302 status
= ndr_map_error2ntstatus(ndr_err
);
303 DBG_WARNING("smbXsrv_session_close_loop: "
304 "ndr_pull_struct_blob - %s\n",
309 DBG_DEBUG("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n");
310 if (DEBUGLVL(DBGLVL_DEBUG
)) {
311 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
314 if (close_blob
.version
!= SMBXSRV_VERSION_0
) {
315 DBG_ERR("smbXsrv_session_close_loop: "
316 "ignore invalid version %u\n", close_blob
.version
);
317 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
321 close_info0
= close_blob
.info
.info0
;
322 if (close_info0
== NULL
) {
323 DBG_ERR("smbXsrv_session_close_loop: "
324 "ignore NULL info %u\n", close_blob
.version
);
325 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
329 status
= smb2srv_session_lookup_client(client
,
330 close_info0
->old_session_wire_id
,
332 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_SESSION_DELETED
)) {
333 DBG_INFO("smbXsrv_session_close_loop: "
334 "old_session_wire_id %llu not found\n",
335 (unsigned long long)close_info0
->old_session_wire_id
);
336 if (DEBUGLVL(DBGLVL_INFO
)) {
337 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
341 if (!NT_STATUS_IS_OK(status
) &&
342 !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) &&
343 !NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_SESSION_EXPIRED
)) {
344 DBG_WARNING("smbXsrv_session_close_loop: "
345 "old_session_wire_id %llu - %s\n",
346 (unsigned long long)close_info0
->old_session_wire_id
,
348 if (DEBUGLVL(DBGLVL_WARNING
)) {
349 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
354 if (session
->global
->session_global_id
!= close_info0
->old_session_global_id
) {
355 DBG_WARNING("smbXsrv_session_close_loop: "
356 "old_session_wire_id %llu - global %u != %u\n",
357 (unsigned long long)close_info0
->old_session_wire_id
,
358 session
->global
->session_global_id
,
359 close_info0
->old_session_global_id
);
360 if (DEBUGLVL(DBGLVL_WARNING
)) {
361 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
366 if (session
->global
->creation_time
!= close_info0
->old_creation_time
) {
367 DBG_WARNING("smbXsrv_session_close_loop: "
368 "old_session_wire_id %llu - "
369 "creation %s (%llu) != %s (%llu)\n",
370 (unsigned long long)close_info0
->old_session_wire_id
,
371 nt_time_string(rec
, session
->global
->creation_time
),
372 (unsigned long long)session
->global
->creation_time
,
373 nt_time_string(rec
, close_info0
->old_creation_time
),
374 (unsigned long long)close_info0
->old_creation_time
);
375 if (DEBUGLVL(DBGLVL_WARNING
)) {
376 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
381 subreq
= smb2srv_session_shutdown_send(session
, client
->raw_ev_ctx
,
383 if (subreq
== NULL
) {
384 status
= NT_STATUS_NO_MEMORY
;
385 DBG_ERR("smbXsrv_session_close_loop: "
386 "smb2srv_session_shutdown_send(%llu) failed: %s\n",
387 (unsigned long long)session
->global
->session_wire_id
,
389 if (DEBUGLVL(DBGLVL_WARNING
)) {
390 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
394 tevent_req_set_callback(subreq
,
395 smbXsrv_session_close_shutdown_done
,
401 subreq
= messaging_read_send(table
,
404 MSG_SMBXSRV_SESSION_CLOSE
);
405 if (subreq
== NULL
) {
407 r
= "messaging_read_send(MSG_SMBXSRV_SESSION_CLOSE) failed";
408 exit_server_cleanly(r
);
411 tevent_req_set_callback(subreq
, smbXsrv_session_close_loop
, client
);
414 static void smbXsrv_session_close_shutdown_done(struct tevent_req
*subreq
)
416 struct smbXsrv_session
*session
=
417 tevent_req_callback_data(subreq
,
418 struct smbXsrv_session
);
421 status
= smb2srv_session_shutdown_recv(subreq
);
423 if (!NT_STATUS_IS_OK(status
)) {
424 DBG_ERR("smbXsrv_session_close_loop: "
425 "smb2srv_session_shutdown_recv(%llu) failed: %s\n",
426 (unsigned long long)session
->global
->session_wire_id
,
430 status
= smbXsrv_session_logoff(session
);
431 if (!NT_STATUS_IS_OK(status
)) {
432 DBG_ERR("smbXsrv_session_close_loop: "
433 "smbXsrv_session_logoff(%llu) failed: %s\n",
434 (unsigned long long)session
->global
->session_wire_id
,
438 TALLOC_FREE(session
);
441 struct smb1srv_session_local_allocate_state
{
442 const uint32_t lowest_id
;
443 const uint32_t highest_id
;
449 static int smb1srv_session_local_allocate_traverse(struct db_record
*rec
,
452 struct smb1srv_session_local_allocate_state
*state
=
453 (struct smb1srv_session_local_allocate_state
*)private_data
;
454 TDB_DATA key
= dbwrap_record_get_key(rec
);
458 status
= smbXsrv_session_local_key_to_id(key
, &id
);
459 if (!NT_STATUS_IS_OK(status
)) {
460 state
->status
= status
;
464 if (id
<= state
->last_id
) {
465 state
->status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
470 if (id
> state
->useable_id
) {
471 state
->status
= NT_STATUS_OK
;
475 if (state
->useable_id
== state
->highest_id
) {
476 state
->status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
480 state
->useable_id
+=1;
484 static NTSTATUS
smb1srv_session_local_allocate_id(struct db_context
*db
,
488 struct db_record
**_rec
,
491 struct smb1srv_session_local_allocate_state state
= {
492 .lowest_id
= lowest_id
,
493 .highest_id
= highest_id
,
495 .useable_id
= lowest_id
,
496 .status
= NT_STATUS_INTERNAL_ERROR
,
506 if (lowest_id
> highest_id
) {
507 return NT_STATUS_INSUFFICIENT_RESOURCES
;
511 * first we try randomly
513 range
= (highest_id
- lowest_id
) + 1;
515 for (i
= 0; i
< (range
/ 2); i
++) {
518 struct db_record
*rec
= NULL
;
520 id
= generate_random() % range
;
523 if (id
< lowest_id
) {
526 if (id
> highest_id
) {
530 rec
= smbXsrv_session_local_fetch_locked(db
, id
, mem_ctx
);
532 return NT_STATUS_INSUFFICIENT_RESOURCES
;
535 val
= dbwrap_record_get_value(rec
);
536 if (val
.dsize
!= 0) {
547 * if the range is almost full,
548 * we traverse the whole table
549 * (this relies on sorted behavior of dbwrap_rbt)
551 status
= dbwrap_traverse_read(db
, smb1srv_session_local_allocate_traverse
,
553 if (NT_STATUS_IS_OK(status
)) {
554 if (NT_STATUS_IS_OK(state
.status
)) {
555 return NT_STATUS_INTERNAL_ERROR
;
558 if (!NT_STATUS_EQUAL(state
.status
, NT_STATUS_INTERNAL_ERROR
)) {
562 if (state
.useable_id
<= state
.highest_id
) {
563 state
.status
= NT_STATUS_OK
;
565 return NT_STATUS_INSUFFICIENT_RESOURCES
;
567 } else if (!NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_DB_CORRUPTION
)) {
569 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
571 * If we get anything else it is an error, because it
572 * means we did not manage to find a free slot in
575 return NT_STATUS_INSUFFICIENT_RESOURCES
;
578 if (NT_STATUS_IS_OK(state
.status
)) {
581 struct db_record
*rec
= NULL
;
583 id
= state
.useable_id
;
585 rec
= smbXsrv_session_local_fetch_locked(db
, id
, mem_ctx
);
587 return NT_STATUS_INSUFFICIENT_RESOURCES
;
590 val
= dbwrap_record_get_value(rec
);
591 if (val
.dsize
!= 0) {
593 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
604 struct smbXsrv_session_local_fetch_state
{
605 struct smbXsrv_session
*session
;
609 static void smbXsrv_session_local_fetch_parser(TDB_DATA key
, TDB_DATA data
,
612 struct smbXsrv_session_local_fetch_state
*state
=
613 (struct smbXsrv_session_local_fetch_state
*)private_data
;
616 if (data
.dsize
!= sizeof(ptr
)) {
617 state
->status
= NT_STATUS_INTERNAL_DB_ERROR
;
621 memcpy(&ptr
, data
.dptr
, data
.dsize
);
622 state
->session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
623 state
->status
= NT_STATUS_OK
;
626 static NTSTATUS
smbXsrv_session_local_lookup(struct smbXsrv_session_table
*table
,
628 struct smbXsrv_connection
*conn
,
629 uint32_t session_local_id
,
631 struct smbXsrv_session
**_session
)
633 struct smbXsrv_session_local_fetch_state state
= {
635 .status
= NT_STATUS_INTERNAL_ERROR
,
637 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
643 if (session_local_id
== 0) {
644 return NT_STATUS_USER_SESSION_DELETED
;
648 /* this might happen before the end of negprot */
649 return NT_STATUS_USER_SESSION_DELETED
;
652 if (table
->local
.db_ctx
== NULL
) {
653 return NT_STATUS_INTERNAL_ERROR
;
656 key
= smbXsrv_session_local_id_to_key(session_local_id
, key_buf
);
658 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
659 smbXsrv_session_local_fetch_parser
,
661 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
662 return NT_STATUS_USER_SESSION_DELETED
;
663 } else if (!NT_STATUS_IS_OK(status
)) {
666 if (!NT_STATUS_IS_OK(state
.status
)) {
670 if (NT_STATUS_EQUAL(state
.session
->status
, NT_STATUS_USER_SESSION_DELETED
)) {
671 return NT_STATUS_USER_SESSION_DELETED
;
675 * If a connection is specified check if the session is
676 * valid on the channel.
679 struct smbXsrv_channel_global0
*c
= NULL
;
681 status
= smbXsrv_session_find_channel(state
.session
, conn
, &c
);
682 if (!NT_STATUS_IS_OK(status
)) {
687 state
.session
->idle_time
= now
;
689 if (!NT_STATUS_IS_OK(state
.session
->status
)) {
690 *_session
= state
.session
;
691 return state
.session
->status
;
694 if (now
> state
.session
->global
->expiration_time
) {
695 state
.session
->status
= NT_STATUS_NETWORK_SESSION_EXPIRED
;
698 *_session
= state
.session
;
699 return state
.session
->status
;
702 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0
*global
)
707 static void smbXsrv_session_global_verify_record(struct db_record
*db_rec
,
711 struct smbXsrv_session_global0
**_g
,
714 static NTSTATUS
smbXsrv_session_global_allocate(struct db_context
*db
,
716 struct smbXsrv_session_global0
**_global
)
719 struct smbXsrv_session_global0
*global
= NULL
;
720 uint32_t last_free
= 0;
721 const uint32_t min_tries
= 3;
725 global
= talloc_zero(mem_ctx
, struct smbXsrv_session_global0
);
726 if (global
== NULL
) {
727 return NT_STATUS_NO_MEMORY
;
729 talloc_set_destructor(global
, smbXsrv_session_global_destructor
);
732 * Here we just randomly try the whole 32-bit space
734 * We use just 32-bit, because we want to reuse the
737 for (i
= 0; i
< UINT32_MAX
; i
++) {
738 bool is_free
= false;
739 bool was_free
= false;
742 if (i
>= min_tries
&& last_free
!= 0) {
745 id
= generate_random();
750 if (id
== UINT32_MAX
) {
754 global
->db_rec
= smbXsrv_session_global_fetch_locked(db
, id
,
756 if (global
->db_rec
== NULL
) {
758 return NT_STATUS_INSUFFICIENT_RESOURCES
;
761 smbXsrv_session_global_verify_record(global
->db_rec
,
767 TALLOC_FREE(global
->db_rec
);
771 if (!was_free
&& i
< min_tries
) {
773 * The session_id is free now,
774 * but was not free before.
776 * This happens if a smbd crashed
777 * and did not cleanup the record.
779 * If this is one of our first tries,
780 * then we try to find a real free one.
782 if (last_free
== 0) {
785 TALLOC_FREE(global
->db_rec
);
789 global
->session_global_id
= id
;
795 /* should not be reached */
797 return NT_STATUS_INTERNAL_ERROR
;
800 static void smbXsrv_session_global_verify_record(struct db_record
*db_rec
,
804 struct smbXsrv_session_global0
**_g
,
810 struct smbXsrv_session_globalB global_blob
;
811 enum ndr_err_code ndr_err
;
812 struct smbXsrv_session_global0
*global
= NULL
;
814 TALLOC_CTX
*frame
= talloc_stackframe();
828 key
= dbwrap_record_get_key(db_rec
);
830 val
= dbwrap_record_get_value(db_rec
);
831 if (val
.dsize
== 0) {
840 blob
= data_blob_const(val
.dptr
, val
.dsize
);
842 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
843 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_globalB
);
844 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
845 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
846 DBG_WARNING("smbXsrv_session_global_verify_record: "
847 "key '%s' ndr_pull_struct_blob - %s\n",
858 DBG_DEBUG("smbXsrv_session_global_verify_record\n");
859 if (DEBUGLVL(DBGLVL_DEBUG
)) {
860 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
863 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
864 DBG_ERR("smbXsrv_session_global_verify_record: "
865 "key '%s' use unsupported version %u\n",
867 global_blob
.version
);
868 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
877 global
= global_blob
.info
.info0
;
879 #define __BLOB_KEEP_SECRET(__blob) do { \
880 if ((__blob).length != 0) { \
881 talloc_keep_secret((__blob).data); \
886 __BLOB_KEEP_SECRET(global
->application_key_blob
);
887 __BLOB_KEEP_SECRET(global
->signing_key_blob
);
888 __BLOB_KEEP_SECRET(global
->encryption_key_blob
);
889 __BLOB_KEEP_SECRET(global
->decryption_key_blob
);
890 for (i
= 0; i
< global
->num_channels
; i
++) {
891 __BLOB_KEEP_SECRET(global
->channels
[i
].signing_key_blob
);
894 #undef __BLOB_KEEP_SECRET
896 exists
= serverid_exists(&global
->channels
[0].server_id
);
898 struct server_id_buf idbuf
;
899 DBG_NOTICE("smbXsrv_session_global_verify_record: "
900 "key '%s' server_id %s does not exist.\n",
902 server_id_str_buf(global
->channels
[0].server_id
,
904 if (DEBUGLVL(DBGLVL_NOTICE
)) {
905 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
908 dbwrap_record_delete(db_rec
);
914 *_g
= talloc_move(mem_ctx
, &global
);
917 *pseqnum
= global_blob
.seqnum
;
922 static NTSTATUS
smbXsrv_session_global_store(struct smbXsrv_session_global0
*global
)
924 struct smbXsrv_session_globalB global_blob
;
925 DATA_BLOB blob
= data_blob_null
;
929 enum ndr_err_code ndr_err
;
932 * TODO: if we use other versions than '0'
933 * we would add glue code here, that would be able to
934 * store the information in the old format.
937 if (global
->db_rec
== NULL
) {
938 return NT_STATUS_INTERNAL_ERROR
;
941 key
= dbwrap_record_get_key(global
->db_rec
);
942 val
= dbwrap_record_get_value(global
->db_rec
);
944 ZERO_STRUCT(global_blob
);
945 global_blob
.version
= smbXsrv_version_global_current();
946 if (val
.dsize
>= 8) {
947 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
949 global_blob
.seqnum
+= 1;
950 global_blob
.info
.info0
= global
;
952 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
953 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_session_globalB
);
954 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
955 status
= ndr_map_error2ntstatus(ndr_err
);
956 DBG_WARNING("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
959 TALLOC_FREE(global
->db_rec
);
963 val
= make_tdb_data(blob
.data
, blob
.length
);
964 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
965 if (!NT_STATUS_IS_OK(status
)) {
966 DBG_WARNING("smbXsrv_session_global_store: key '%s' store - %s\n",
969 TALLOC_FREE(global
->db_rec
);
973 if (DEBUGLVL(DBGLVL_DEBUG
)) {
974 DBG_DEBUG("smbXsrv_session_global_store: key '%s' stored\n",
976 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
979 TALLOC_FREE(global
->db_rec
);
984 struct smb2srv_session_close_previous_state
{
985 struct tevent_context
*ev
;
986 struct smbXsrv_connection
*connection
;
987 struct dom_sid
*current_sid
;
988 uint64_t previous_session_id
;
989 uint64_t current_session_id
;
990 struct db_record
*db_rec
;
991 uint64_t watch_instance
;
992 uint32_t last_seqnum
;
995 static void smb2srv_session_close_previous_cleanup(struct tevent_req
*req
,
996 enum tevent_req_state req_state
)
998 struct smb2srv_session_close_previous_state
*state
=
1000 struct smb2srv_session_close_previous_state
);
1002 if (state
->db_rec
!= NULL
) {
1003 dbwrap_watched_watch_remove_instance(state
->db_rec
,
1004 state
->watch_instance
);
1005 state
->watch_instance
= 0;
1006 TALLOC_FREE(state
->db_rec
);
1010 static void smb2srv_session_close_previous_check(struct tevent_req
*req
);
1011 static void smb2srv_session_close_previous_modified(struct tevent_req
*subreq
);
1013 struct tevent_req
*smb2srv_session_close_previous_send(TALLOC_CTX
*mem_ctx
,
1014 struct tevent_context
*ev
,
1015 struct smbXsrv_connection
*conn
,
1016 struct auth_session_info
*session_info
,
1017 uint64_t previous_session_id
,
1018 uint64_t current_session_id
)
1020 struct tevent_req
*req
;
1021 struct smb2srv_session_close_previous_state
*state
;
1022 uint32_t global_id
= previous_session_id
& UINT32_MAX
;
1023 uint64_t global_zeros
= previous_session_id
& 0xFFFFFFFF00000000LLU
;
1024 struct smbXsrv_session_table
*table
= conn
->client
->session_table
;
1025 struct security_token
*current_token
= NULL
;
1027 req
= tevent_req_create(mem_ctx
, &state
,
1028 struct smb2srv_session_close_previous_state
);
1033 state
->connection
= conn
;
1034 state
->previous_session_id
= previous_session_id
;
1035 state
->current_session_id
= current_session_id
;
1037 tevent_req_set_cleanup_fn(req
, smb2srv_session_close_previous_cleanup
);
1039 if (global_zeros
!= 0) {
1040 tevent_req_done(req
);
1041 return tevent_req_post(req
, ev
);
1044 if (session_info
== NULL
) {
1045 tevent_req_done(req
);
1046 return tevent_req_post(req
, ev
);
1048 current_token
= session_info
->security_token
;
1050 if (current_token
->num_sids
> PRIMARY_USER_SID_INDEX
) {
1051 state
->current_sid
= ¤t_token
->sids
[PRIMARY_USER_SID_INDEX
];
1054 if (state
->current_sid
== NULL
) {
1055 tevent_req_done(req
);
1056 return tevent_req_post(req
, ev
);
1059 if (!security_token_has_nt_authenticated_users(current_token
)) {
1061 tevent_req_done(req
);
1062 return tevent_req_post(req
, ev
);
1065 state
->db_rec
= smbXsrv_session_global_fetch_locked(
1066 table
->global
.db_ctx
,
1068 state
/* TALLOC_CTX */);
1069 if (state
->db_rec
== NULL
) {
1070 tevent_req_nterror(req
, NT_STATUS_UNSUCCESSFUL
);
1071 return tevent_req_post(req
, ev
);
1074 smb2srv_session_close_previous_check(req
);
1075 if (!tevent_req_is_in_progress(req
)) {
1076 return tevent_req_post(req
, ev
);
1082 static void smb2srv_session_close_previous_check(struct tevent_req
*req
)
1084 struct smb2srv_session_close_previous_state
*state
=
1085 tevent_req_data(req
,
1086 struct smb2srv_session_close_previous_state
);
1087 struct smbXsrv_connection
*conn
= state
->connection
;
1089 struct security_token
*previous_token
= NULL
;
1090 struct smbXsrv_session_global0
*global
= NULL
;
1091 enum ndr_err_code ndr_err
;
1092 struct smbXsrv_session_close0 close_info0
;
1093 struct smbXsrv_session_closeB close_blob
;
1094 struct tevent_req
*subreq
= NULL
;
1096 bool is_free
= false;
1097 uint32_t seqnum
= 0;
1099 smbXsrv_session_global_verify_record(state
->db_rec
,
1107 tevent_req_done(req
);
1111 if (global
->auth_session_info
== NULL
) {
1112 tevent_req_done(req
);
1116 previous_token
= global
->auth_session_info
->security_token
;
1118 if (!security_token_is_sid(previous_token
, state
->current_sid
)) {
1119 tevent_req_done(req
);
1124 * If the record changed, but we are not happy with the change yet,
1125 * we better remove ourself from the waiter list
1126 * (most likely the first position)
1127 * and re-add us at the end of the list.
1129 * This gives other waiters a change
1132 * Otherwise we'll keep our waiter instance alive,
1133 * keep waiting (most likely at first position).
1134 * It means the order of watchers stays fair.
1136 if (state
->last_seqnum
!= seqnum
) {
1137 state
->last_seqnum
= seqnum
;
1138 dbwrap_watched_watch_remove_instance(state
->db_rec
,
1139 state
->watch_instance
);
1140 state
->watch_instance
=
1141 dbwrap_watched_watch_add_instance(state
->db_rec
);
1144 subreq
= dbwrap_watched_watch_send(state
, state
->ev
, state
->db_rec
,
1145 state
->watch_instance
,
1146 (struct server_id
){0});
1147 if (tevent_req_nomem(subreq
, req
)) {
1150 tevent_req_set_callback(subreq
,
1151 smb2srv_session_close_previous_modified
,
1154 close_info0
.old_session_global_id
= global
->session_global_id
;
1155 close_info0
.old_session_wire_id
= global
->session_wire_id
;
1156 close_info0
.old_creation_time
= global
->creation_time
;
1157 close_info0
.new_session_wire_id
= state
->current_session_id
;
1159 ZERO_STRUCT(close_blob
);
1160 close_blob
.version
= smbXsrv_version_global_current();
1161 close_blob
.info
.info0
= &close_info0
;
1163 ndr_err
= ndr_push_struct_blob(&blob
, state
, &close_blob
,
1164 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_session_closeB
);
1165 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1166 status
= ndr_map_error2ntstatus(ndr_err
);
1167 DBG_WARNING("smb2srv_session_close_previous_check: "
1168 "old_session[%llu] new_session[%llu] ndr_push - %s\n",
1169 (unsigned long long)close_info0
.old_session_wire_id
,
1170 (unsigned long long)close_info0
.new_session_wire_id
,
1172 tevent_req_nterror(req
, status
);
1176 status
= messaging_send(conn
->client
->msg_ctx
,
1177 global
->channels
[0].server_id
,
1178 MSG_SMBXSRV_SESSION_CLOSE
, &blob
);
1179 TALLOC_FREE(global
);
1180 if (tevent_req_nterror(req
, status
)) {
1184 TALLOC_FREE(state
->db_rec
);
1188 static void smb2srv_session_close_previous_modified(struct tevent_req
*subreq
)
1190 struct tevent_req
*req
=
1191 tevent_req_callback_data(subreq
,
1193 struct smb2srv_session_close_previous_state
*state
=
1194 tevent_req_data(req
,
1195 struct smb2srv_session_close_previous_state
);
1198 uint64_t instance
= 0;
1200 status
= dbwrap_watched_watch_recv(subreq
, &instance
, NULL
, NULL
);
1201 TALLOC_FREE(subreq
);
1202 if (tevent_req_nterror(req
, status
)) {
1206 state
->watch_instance
= instance
;
1208 global_id
= state
->previous_session_id
& UINT32_MAX
;
1210 state
->db_rec
= smbXsrv_session_global_fetch_locked(
1211 state
->connection
->client
->session_table
->global
.db_ctx
,
1212 global_id
, state
/* TALLOC_CTX */);
1213 if (state
->db_rec
== NULL
) {
1214 tevent_req_nterror(req
, NT_STATUS_UNSUCCESSFUL
);
1218 smb2srv_session_close_previous_check(req
);
1221 NTSTATUS
smb2srv_session_close_previous_recv(struct tevent_req
*req
)
1225 if (tevent_req_is_nterror(req
, &status
)) {
1226 tevent_req_received(req
);
1230 tevent_req_received(req
);
1231 return NT_STATUS_OK
;
1234 static NTSTATUS
smbXsrv_session_clear_and_logoff(struct smbXsrv_session
*session
)
1237 struct smbXsrv_connection
*xconn
= NULL
;
1239 if (session
->client
!= NULL
) {
1240 xconn
= session
->client
->connections
;
1243 for (; xconn
!= NULL
; xconn
= xconn
->next
) {
1244 struct smbd_smb2_request
*preq
;
1246 for (preq
= xconn
->smb2
.requests
; preq
!= NULL
; preq
= preq
->next
) {
1247 if (preq
->session
!= session
) {
1251 preq
->session
= NULL
;
1253 * If we no longer have a session we can't
1254 * sign or encrypt replies.
1256 preq
->do_signing
= false;
1257 preq
->do_encryption
= false;
1258 preq
->preauth
= NULL
;
1262 status
= smbXsrv_session_logoff(session
);
1266 static int smbXsrv_session_destructor(struct smbXsrv_session
*session
)
1270 DBG_DEBUG("destructing session(%llu)\n",
1271 (unsigned long long)session
->global
->session_wire_id
);
1273 status
= smbXsrv_session_clear_and_logoff(session
);
1274 if (!NT_STATUS_IS_OK(status
)) {
1275 DBG_ERR("smbXsrv_session_destructor: "
1276 "smbXsrv_session_logoff() failed: %s\n",
1280 TALLOC_FREE(session
->global
);
1285 NTSTATUS
smbXsrv_session_create(struct smbXsrv_connection
*conn
,
1287 struct smbXsrv_session
**_session
)
1289 struct smbXsrv_session_table
*table
= conn
->client
->session_table
;
1290 struct db_record
*local_rec
= NULL
;
1291 struct smbXsrv_session
*session
= NULL
;
1294 struct smbXsrv_session_global0
*global
= NULL
;
1295 struct smbXsrv_channel_global0
*channel
= NULL
;
1298 if (table
->local
.num_sessions
>= table
->local
.max_sessions
) {
1299 return NT_STATUS_INSUFFICIENT_RESOURCES
;
1302 session
= talloc_zero(table
, struct smbXsrv_session
);
1303 if (session
== NULL
) {
1304 return NT_STATUS_NO_MEMORY
;
1306 session
->table
= table
;
1307 session
->idle_time
= now
;
1308 session
->status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1309 session
->client
= conn
->client
;
1310 session
->homes_snum
= -1;
1312 status
= smbXsrv_session_global_allocate(table
->global
.db_ctx
,
1315 if (!NT_STATUS_IS_OK(status
)) {
1316 TALLOC_FREE(session
);
1319 session
->global
= global
;
1321 if (conn
->protocol
>= PROTOCOL_SMB2_02
) {
1322 uint64_t id
= global
->session_global_id
;
1324 global
->connection_dialect
= conn
->smb2
.server
.dialect
;
1326 global
->session_wire_id
= id
;
1328 status
= smb2srv_tcon_table_init(session
);
1329 if (!NT_STATUS_IS_OK(status
)) {
1330 TALLOC_FREE(session
);
1334 session
->local_id
= global
->session_global_id
;
1336 local_rec
= smbXsrv_session_local_fetch_locked(
1337 table
->local
.db_ctx
,
1339 session
/* TALLOC_CTX */);
1340 if (local_rec
== NULL
) {
1341 TALLOC_FREE(session
);
1342 return NT_STATUS_NO_MEMORY
;
1345 val
= dbwrap_record_get_value(local_rec
);
1346 if (val
.dsize
!= 0) {
1347 TALLOC_FREE(session
);
1348 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1352 status
= smb1srv_session_local_allocate_id(table
->local
.db_ctx
,
1353 table
->local
.lowest_id
,
1354 table
->local
.highest_id
,
1357 &session
->local_id
);
1358 if (!NT_STATUS_IS_OK(status
)) {
1359 TALLOC_FREE(session
);
1363 global
->session_wire_id
= session
->local_id
;
1366 global
->creation_time
= now
;
1367 global
->expiration_time
= GENSEC_EXPIRE_TIME_INFINITY
;
1369 status
= smbXsrv_session_add_channel(session
, conn
, now
, &channel
);
1370 if (!NT_STATUS_IS_OK(status
)) {
1371 TALLOC_FREE(session
);
1376 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
1377 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
1378 TALLOC_FREE(local_rec
);
1379 if (!NT_STATUS_IS_OK(status
)) {
1380 TALLOC_FREE(session
);
1383 table
->local
.num_sessions
+= 1;
1385 talloc_set_destructor(session
, smbXsrv_session_destructor
);
1387 status
= smbXsrv_session_global_store(global
);
1388 if (!NT_STATUS_IS_OK(status
)) {
1389 DBG_ERR("smbXsrv_session_create: "
1390 "global_id (0x%08x) store failed - %s\n",
1391 session
->global
->session_global_id
,
1393 TALLOC_FREE(session
);
1397 if (DEBUGLVL(DBGLVL_DEBUG
)) {
1398 struct smbXsrv_sessionB session_blob
= {
1399 .version
= SMBXSRV_VERSION_0
,
1400 .info
.info0
= session
,
1403 DBG_DEBUG("smbXsrv_session_create: global_id (0x%08x) stored\n",
1404 session
->global
->session_global_id
);
1405 NDR_PRINT_DEBUG(smbXsrv_sessionB
, &session_blob
);
1408 *_session
= session
;
1409 return NT_STATUS_OK
;
1412 NTSTATUS
smbXsrv_session_add_channel(struct smbXsrv_session
*session
,
1413 struct smbXsrv_connection
*conn
,
1415 struct smbXsrv_channel_global0
**_c
)
1417 struct smbXsrv_session_global0
*global
= session
->global
;
1418 struct smbXsrv_channel_global0
*c
= NULL
;
1420 if (global
->num_channels
> 31) {
1422 * Windows allow up to 32 channels
1424 return NT_STATUS_INSUFFICIENT_RESOURCES
;
1427 c
= talloc_realloc(global
,
1429 struct smbXsrv_channel_global0
,
1430 global
->num_channels
+ 1);
1432 return NT_STATUS_NO_MEMORY
;
1434 global
->channels
= c
;
1436 c
= &global
->channels
[global
->num_channels
];
1439 c
->server_id
= messaging_server_id(conn
->client
->msg_ctx
);
1440 c
->channel_id
= conn
->channel_id
;
1441 c
->creation_time
= now
;
1442 c
->local_address
= tsocket_address_string(conn
->local_address
,
1444 if (c
->local_address
== NULL
) {
1445 return NT_STATUS_NO_MEMORY
;
1447 c
->remote_address
= tsocket_address_string(conn
->remote_address
,
1449 if (c
->remote_address
== NULL
) {
1450 return NT_STATUS_NO_MEMORY
;
1452 c
->remote_name
= talloc_strdup(global
->channels
,
1453 conn
->remote_hostname
);
1454 if (c
->remote_name
== NULL
) {
1455 return NT_STATUS_NO_MEMORY
;
1457 c
->connection
= conn
;
1459 global
->num_channels
+= 1;
1462 return NT_STATUS_OK
;
1465 NTSTATUS
smbXsrv_session_update(struct smbXsrv_session
*session
)
1467 struct smbXsrv_session_table
*table
= session
->table
;
1470 if (session
->global
->db_rec
!= NULL
) {
1471 DBG_ERR("smbXsrv_session_update(0x%08x): "
1472 "Called with db_rec != NULL'\n",
1473 session
->global
->session_global_id
);
1474 return NT_STATUS_INTERNAL_ERROR
;
1477 if (table
== NULL
) {
1478 DBG_ERR("smbXsrv_session_update(0x%08x): "
1479 "Called with table == NULL'\n",
1480 session
->global
->session_global_id
);
1481 return NT_STATUS_INTERNAL_ERROR
;
1484 session
->global
->db_rec
= smbXsrv_session_global_fetch_locked(
1485 table
->global
.db_ctx
,
1486 session
->global
->session_global_id
,
1487 session
->global
/* TALLOC_CTX */);
1488 if (session
->global
->db_rec
== NULL
) {
1489 return NT_STATUS_INTERNAL_DB_ERROR
;
1492 status
= smbXsrv_session_global_store(session
->global
);
1493 if (!NT_STATUS_IS_OK(status
)) {
1494 DBG_ERR("smbXsrv_session_update: "
1495 "global_id (0x%08x) store failed - %s\n",
1496 session
->global
->session_global_id
,
1501 if (DEBUGLVL(DBGLVL_DEBUG
)) {
1502 struct smbXsrv_sessionB session_blob
= {
1503 .version
= SMBXSRV_VERSION_0
,
1504 .info
.info0
= session
,
1507 DBG_DEBUG("smbXsrv_session_update: global_id (0x%08x) stored\n",
1508 session
->global
->session_global_id
);
1509 NDR_PRINT_DEBUG(smbXsrv_sessionB
, &session_blob
);
1512 return NT_STATUS_OK
;
1515 NTSTATUS
smbXsrv_session_find_channel(const struct smbXsrv_session
*session
,
1516 const struct smbXsrv_connection
*conn
,
1517 struct smbXsrv_channel_global0
**_c
)
1521 for (i
=0; i
< session
->global
->num_channels
; i
++) {
1522 struct smbXsrv_channel_global0
*c
= &session
->global
->channels
[i
];
1524 if (c
->channel_id
!= conn
->channel_id
) {
1528 if (c
->connection
!= conn
) {
1533 return NT_STATUS_OK
;
1536 return NT_STATUS_USER_SESSION_DELETED
;
1539 NTSTATUS
smbXsrv_session_find_auth(const struct smbXsrv_session
*session
,
1540 const struct smbXsrv_connection
*conn
,
1542 struct smbXsrv_session_auth0
**_a
)
1544 struct smbXsrv_session_auth0
*a
;
1546 for (a
= session
->pending_auth
; a
!= NULL
; a
= a
->next
) {
1547 if (a
->channel_id
!= conn
->channel_id
) {
1551 if (a
->connection
== conn
) {
1556 return NT_STATUS_OK
;
1560 return NT_STATUS_USER_SESSION_DELETED
;
1563 static int smbXsrv_session_auth0_destructor(struct smbXsrv_session_auth0
*a
)
1565 if (a
->session
== NULL
) {
1569 DLIST_REMOVE(a
->session
->pending_auth
, a
);
1574 NTSTATUS
smbXsrv_session_create_auth(struct smbXsrv_session
*session
,
1575 struct smbXsrv_connection
*conn
,
1578 uint8_t in_security_mode
,
1579 struct smbXsrv_session_auth0
**_a
)
1581 struct smbXsrv_session_auth0
*a
;
1584 status
= smbXsrv_session_find_auth(session
, conn
, 0, &a
);
1585 if (NT_STATUS_IS_OK(status
)) {
1586 return NT_STATUS_INTERNAL_ERROR
;
1589 a
= talloc_zero(session
, struct smbXsrv_session_auth0
);
1591 return NT_STATUS_NO_MEMORY
;
1593 a
->session
= session
;
1594 a
->connection
= conn
;
1595 a
->in_flags
= in_flags
;
1596 a
->in_security_mode
= in_security_mode
;
1597 a
->creation_time
= now
;
1599 a
->channel_id
= conn
->channel_id
;
1601 if (conn
->protocol
>= PROTOCOL_SMB3_11
) {
1602 a
->preauth
= talloc(a
, struct smbXsrv_preauth
);
1603 if (a
->preauth
== NULL
) {
1604 TALLOC_FREE(session
);
1605 return NT_STATUS_NO_MEMORY
;
1607 *a
->preauth
= conn
->smb2
.preauth
;
1610 talloc_set_destructor(a
, smbXsrv_session_auth0_destructor
);
1611 DLIST_ADD_END(session
->pending_auth
, a
);
1614 return NT_STATUS_OK
;
1617 static void smbXsrv_session_remove_channel_done(struct tevent_req
*subreq
);
1619 NTSTATUS
smbXsrv_session_remove_channel(struct smbXsrv_session
*session
,
1620 struct smbXsrv_connection
*xconn
)
1622 struct smbXsrv_session_auth0
*a
= NULL
;
1623 struct smbXsrv_channel_global0
*c
= NULL
;
1625 bool need_update
= false;
1627 status
= smbXsrv_session_find_auth(session
, xconn
, 0, &a
);
1628 if (!NT_STATUS_IS_OK(status
)) {
1631 status
= smbXsrv_session_find_channel(session
, xconn
, &c
);
1632 if (!NT_STATUS_IS_OK(status
)) {
1637 smbXsrv_session_auth0_destructor(a
);
1638 a
->connection
= NULL
;
1643 struct smbXsrv_session_global0
*global
= session
->global
;
1646 n
= (c
- global
->channels
);
1647 if (n
>= global
->num_channels
|| n
< 0) {
1648 return NT_STATUS_INTERNAL_ERROR
;
1650 ARRAY_DEL_ELEMENT(global
->channels
, n
, global
->num_channels
);
1651 global
->num_channels
--;
1652 if (global
->num_channels
== 0) {
1653 struct smbXsrv_client
*client
= session
->client
;
1654 struct tevent_queue
*xconn_wait_queue
=
1655 xconn
->transport
.shutdown_wait_queue
;
1656 struct tevent_req
*subreq
= NULL
;
1659 * Let the connection wait until the session is
1662 * We don't set a callback, as we just want to block the
1663 * wait queue and the talloc_free() of the session will
1664 * remove the item from the wait queue in order
1665 * to remove allow the connection to disappear.
1667 if (xconn_wait_queue
!= NULL
) {
1668 subreq
= tevent_queue_wait_send(session
,
1671 if (subreq
== NULL
) {
1672 status
= NT_STATUS_NO_MEMORY
;
1673 DBG_ERR("tevent_queue_wait_send() session(%llu) failed: %s\n",
1674 (unsigned long long)session
->global
->session_wire_id
,
1681 * This is guaranteed to set
1682 * session->status = NT_STATUS_USER_SESSION_DELETED
1683 * even if NULL is returned.
1685 subreq
= smb2srv_session_shutdown_send(session
,
1689 if (subreq
== NULL
) {
1690 status
= NT_STATUS_NO_MEMORY
;
1691 DBG_ERR("smb2srv_session_shutdown_send(%llu) failed: %s\n",
1692 (unsigned long long)session
->global
->session_wire_id
,
1696 tevent_req_set_callback(subreq
,
1697 smbXsrv_session_remove_channel_done
,
1704 return NT_STATUS_OK
;
1707 return smbXsrv_session_update(session
);
1710 static void smbXsrv_session_remove_channel_done(struct tevent_req
*subreq
)
1712 struct smbXsrv_session
*session
=
1713 tevent_req_callback_data(subreq
,
1714 struct smbXsrv_session
);
1717 status
= smb2srv_session_shutdown_recv(subreq
);
1718 TALLOC_FREE(subreq
);
1719 if (!NT_STATUS_IS_OK(status
)) {
1720 DBG_ERR("smb2srv_session_shutdown_recv(%llu) failed: %s\n",
1721 (unsigned long long)session
->global
->session_wire_id
,
1725 status
= smbXsrv_session_logoff(session
);
1726 if (!NT_STATUS_IS_OK(status
)) {
1727 DBG_ERR("smbXsrv_session_logoff(%llu) failed: %s\n",
1728 (unsigned long long)session
->global
->session_wire_id
,
1732 TALLOC_FREE(session
);
1735 struct smb2srv_session_shutdown_state
{
1736 struct tevent_queue
*wait_queue
;
1739 static void smb2srv_session_shutdown_wait_done(struct tevent_req
*subreq
);
1741 struct tevent_req
*smb2srv_session_shutdown_send(TALLOC_CTX
*mem_ctx
,
1742 struct tevent_context
*ev
,
1743 struct smbXsrv_session
*session
,
1744 struct smbd_smb2_request
*current_req
)
1746 struct tevent_req
*req
;
1747 struct smb2srv_session_shutdown_state
*state
;
1748 struct tevent_req
*subreq
;
1749 struct smbXsrv_connection
*xconn
= NULL
;
1753 * Make sure that no new request will be able to use this session.
1755 session
->status
= NT_STATUS_USER_SESSION_DELETED
;
1757 req
= tevent_req_create(mem_ctx
, &state
,
1758 struct smb2srv_session_shutdown_state
);
1763 state
->wait_queue
= tevent_queue_create(state
, "smb2srv_session_shutdown_queue");
1764 if (tevent_req_nomem(state
->wait_queue
, req
)) {
1765 return tevent_req_post(req
, ev
);
1768 for (xconn
= session
->client
->connections
; xconn
!= NULL
; xconn
= xconn
->next
) {
1769 struct smbd_smb2_request
*preq
;
1771 for (preq
= xconn
->smb2
.requests
; preq
!= NULL
; preq
= preq
->next
) {
1772 if (preq
== current_req
) {
1773 /* Can't cancel current request. */
1776 if (preq
->session
!= session
) {
1777 /* Request on different session. */
1781 if (preq
->subreq
!= NULL
) {
1782 tevent_req_cancel(preq
->subreq
);
1786 * Now wait until the request is finished.
1788 * We don't set a callback, as we just want to block the
1789 * wait queue and the talloc_free() of the request will
1790 * remove the item from the wait queue.
1792 subreq
= tevent_queue_wait_send(preq
, ev
, state
->wait_queue
);
1793 if (tevent_req_nomem(subreq
, req
)) {
1794 return tevent_req_post(req
, ev
);
1799 len
= tevent_queue_length(state
->wait_queue
);
1801 tevent_req_done(req
);
1802 return tevent_req_post(req
, ev
);
1806 * Now we add our own waiter to the end of the queue,
1807 * this way we get notified when all pending requests are finished
1808 * and send to the socket.
1810 subreq
= tevent_queue_wait_send(state
, ev
, state
->wait_queue
);
1811 if (tevent_req_nomem(subreq
, req
)) {
1812 return tevent_req_post(req
, ev
);
1814 tevent_req_set_callback(subreq
, smb2srv_session_shutdown_wait_done
, req
);
1819 static void smb2srv_session_shutdown_wait_done(struct tevent_req
*subreq
)
1821 struct tevent_req
*req
=
1822 tevent_req_callback_data(subreq
,
1825 tevent_queue_wait_recv(subreq
);
1826 TALLOC_FREE(subreq
);
1828 tevent_req_done(req
);
1831 NTSTATUS
smb2srv_session_shutdown_recv(struct tevent_req
*req
)
1833 return tevent_req_simple_recv_ntstatus(req
);
1836 NTSTATUS
smbXsrv_session_logoff(struct smbXsrv_session
*session
)
1838 struct smbXsrv_session_table
*table
;
1839 struct db_record
*local_rec
= NULL
;
1840 struct db_record
*global_rec
= NULL
;
1841 struct smbd_server_connection
*sconn
= NULL
;
1843 NTSTATUS error
= NT_STATUS_OK
;
1845 if (session
->table
== NULL
) {
1846 return NT_STATUS_OK
;
1849 table
= session
->table
;
1850 session
->table
= NULL
;
1852 sconn
= session
->client
->sconn
;
1853 session
->client
= NULL
;
1854 session
->status
= NT_STATUS_USER_SESSION_DELETED
;
1857 * For SMB2 this is a bit redundant as files are also close
1858 * below via smb2srv_tcon_disconnect_all() -> ... ->
1859 * smbXsrv_tcon_disconnect() -> close_cnum() ->
1860 * file_close_conn().
1862 file_close_user(sconn
, session
->global
->session_wire_id
);
1864 if (session
->tcon_table
!= NULL
) {
1866 * Note: We only have a tcon_table for SMB2.
1868 status
= smb2srv_tcon_disconnect_all(session
);
1869 if (!NT_STATUS_IS_OK(status
)) {
1870 DBG_ERR("smbXsrv_session_logoff(0x%08x): "
1871 "smb2srv_tcon_disconnect_all() failed: %s\n",
1872 session
->global
->session_global_id
,
1878 invalidate_vuid(sconn
, session
->global
->session_wire_id
);
1880 global_rec
= session
->global
->db_rec
;
1881 session
->global
->db_rec
= NULL
;
1882 if (global_rec
== NULL
) {
1883 global_rec
= smbXsrv_session_global_fetch_locked(
1884 table
->global
.db_ctx
,
1885 session
->global
->session_global_id
,
1886 session
->global
/* TALLOC_CTX */);
1887 if (global_rec
== NULL
) {
1888 error
= NT_STATUS_INTERNAL_ERROR
;
1892 if (global_rec
!= NULL
) {
1893 status
= dbwrap_record_delete(global_rec
);
1894 if (!NT_STATUS_IS_OK(status
)) {
1895 TDB_DATA key
= dbwrap_record_get_key(global_rec
);
1897 DBG_ERR("smbXsrv_session_logoff(0x%08x): "
1898 "failed to delete global key '%s': %s\n",
1899 session
->global
->session_global_id
,
1905 TALLOC_FREE(global_rec
);
1907 local_rec
= session
->db_rec
;
1908 if (local_rec
== NULL
) {
1909 local_rec
= smbXsrv_session_local_fetch_locked(
1910 table
->local
.db_ctx
,
1912 session
/* TALLOC_CTX */);
1913 if (local_rec
== NULL
) {
1914 error
= NT_STATUS_INTERNAL_ERROR
;
1918 if (local_rec
!= NULL
) {
1919 status
= dbwrap_record_delete(local_rec
);
1920 if (!NT_STATUS_IS_OK(status
)) {
1921 TDB_DATA key
= dbwrap_record_get_key(local_rec
);
1923 DBG_ERR("smbXsrv_session_logoff(0x%08x): "
1924 "failed to delete local key '%s': %s\n",
1925 session
->global
->session_global_id
,
1930 table
->local
.num_sessions
-= 1;
1932 if (session
->db_rec
== NULL
) {
1933 TALLOC_FREE(local_rec
);
1935 session
->db_rec
= NULL
;
1940 struct smbXsrv_session_logoff_all_state
{
1941 NTSTATUS first_status
;
1945 static int smbXsrv_session_logoff_all_callback(struct db_record
*local_rec
,
1946 void *private_data
);
1948 NTSTATUS
smbXsrv_session_logoff_all(struct smbXsrv_client
*client
)
1950 struct smbXsrv_session_table
*table
= client
->session_table
;
1951 struct smbXsrv_session_logoff_all_state state
;
1955 if (table
== NULL
) {
1956 DBG_DEBUG("smbXsrv_session_logoff_all: "
1957 "empty session_table, nothing to do.\n");
1958 return NT_STATUS_OK
;
1963 status
= dbwrap_traverse(table
->local
.db_ctx
,
1964 smbXsrv_session_logoff_all_callback
,
1966 if (!NT_STATUS_IS_OK(status
)) {
1967 DBG_ERR("smbXsrv_session_logoff_all: "
1968 "dbwrap_traverse() failed: %s\n",
1973 if (!NT_STATUS_IS_OK(state
.first_status
)) {
1974 DBG_ERR("smbXsrv_session_logoff_all: "
1975 "count[%d] errors[%d] first[%s]\n",
1976 count
, state
.errors
,
1977 nt_errstr(state
.first_status
));
1978 return state
.first_status
;
1981 return NT_STATUS_OK
;
1984 static int smbXsrv_session_logoff_all_callback(struct db_record
*local_rec
,
1987 struct smbXsrv_session_logoff_all_state
*state
=
1988 (struct smbXsrv_session_logoff_all_state
*)private_data
;
1991 struct smbXsrv_session
*session
= NULL
;
1994 val
= dbwrap_record_get_value(local_rec
);
1995 if (val
.dsize
!= sizeof(ptr
)) {
1996 status
= NT_STATUS_INTERNAL_ERROR
;
1997 if (NT_STATUS_IS_OK(state
->first_status
)) {
1998 state
->first_status
= status
;
2004 memcpy(&ptr
, val
.dptr
, val
.dsize
);
2005 session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
2007 session
->db_rec
= local_rec
;
2008 status
= smbXsrv_session_clear_and_logoff(session
);
2009 session
->db_rec
= NULL
;
2010 if (!NT_STATUS_IS_OK(status
)) {
2011 if (NT_STATUS_IS_OK(state
->first_status
)) {
2012 state
->first_status
= status
;
2021 struct smbXsrv_session_local_trav_state
{
2023 int (*caller_cb
)(struct smbXsrv_session
*session
,
2028 static int smbXsrv_session_local_traverse_cb(struct db_record
*local_rec
,
2029 void *private_data
);
2031 NTSTATUS
smbXsrv_session_local_traverse(
2032 struct smbXsrv_client
*client
,
2033 int (*caller_cb
)(struct smbXsrv_session
*session
,
2037 struct smbXsrv_session_table
*table
= client
->session_table
;
2038 struct smbXsrv_session_local_trav_state state
;
2042 state
= (struct smbXsrv_session_local_trav_state
) {
2043 .status
= NT_STATUS_OK
,
2044 .caller_cb
= caller_cb
,
2045 .caller_data
= caller_data
,
2048 if (table
== NULL
) {
2049 DBG_DEBUG("empty session_table, nothing to do.\n");
2050 return NT_STATUS_OK
;
2053 status
= dbwrap_traverse(table
->local
.db_ctx
,
2054 smbXsrv_session_local_traverse_cb
,
2057 if (!NT_STATUS_IS_OK(status
)) {
2058 DBG_ERR("dbwrap_traverse() failed: %s\n", nt_errstr(status
));
2061 if (!NT_STATUS_IS_OK(state
.status
)) {
2062 DBG_ERR("count[%d] status[%s]\n",
2063 count
, nt_errstr(state
.status
));
2064 return state
.status
;
2067 return NT_STATUS_OK
;
2070 static int smbXsrv_session_local_traverse_cb(struct db_record
*local_rec
,
2073 struct smbXsrv_session_local_trav_state
*state
=
2074 (struct smbXsrv_session_local_trav_state
*)private_data
;
2077 struct smbXsrv_session
*session
= NULL
;
2080 val
= dbwrap_record_get_value(local_rec
);
2081 if (val
.dsize
!= sizeof(ptr
)) {
2082 state
->status
= NT_STATUS_INTERNAL_ERROR
;
2086 memcpy(&ptr
, val
.dptr
, val
.dsize
);
2087 session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
2089 session
->db_rec
= local_rec
;
2090 ret
= state
->caller_cb(session
, state
->caller_data
);
2091 session
->db_rec
= NULL
;
2096 struct smbXsrv_session_disconnect_xconn_state
{
2097 struct smbXsrv_connection
*xconn
;
2098 NTSTATUS first_status
;
2102 static int smbXsrv_session_disconnect_xconn_callback(struct db_record
*local_rec
,
2103 void *private_data
);
2105 NTSTATUS
smbXsrv_session_disconnect_xconn(struct smbXsrv_connection
*xconn
)
2107 struct smbXsrv_client
*client
= xconn
->client
;
2108 struct smbXsrv_session_table
*table
= client
->session_table
;
2109 struct smbXsrv_session_disconnect_xconn_state state
;
2113 if (table
== NULL
) {
2114 DBG_ERR("empty session_table, nothing to do.\n");
2115 return NT_STATUS_OK
;
2119 state
.xconn
= xconn
;
2121 status
= dbwrap_traverse(table
->local
.db_ctx
,
2122 smbXsrv_session_disconnect_xconn_callback
,
2124 if (!NT_STATUS_IS_OK(status
)) {
2125 DBG_ERR("dbwrap_traverse() failed: %s\n",
2130 if (!NT_STATUS_IS_OK(state
.first_status
)) {
2131 DBG_ERR("count[%d] errors[%d] first[%s]\n",
2132 count
, state
.errors
,
2133 nt_errstr(state
.first_status
));
2134 return state
.first_status
;
2137 return NT_STATUS_OK
;
2140 static int smbXsrv_session_disconnect_xconn_callback(struct db_record
*local_rec
,
2143 struct smbXsrv_session_disconnect_xconn_state
*state
=
2144 (struct smbXsrv_session_disconnect_xconn_state
*)private_data
;
2147 struct smbXsrv_session
*session
= NULL
;
2150 val
= dbwrap_record_get_value(local_rec
);
2151 if (val
.dsize
!= sizeof(ptr
)) {
2152 status
= NT_STATUS_INTERNAL_ERROR
;
2153 if (NT_STATUS_IS_OK(state
->first_status
)) {
2154 state
->first_status
= status
;
2160 memcpy(&ptr
, val
.dptr
, val
.dsize
);
2161 session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
2163 session
->db_rec
= local_rec
;
2164 status
= smbXsrv_session_remove_channel(session
, state
->xconn
);
2165 session
->db_rec
= NULL
;
2166 if (!NT_STATUS_IS_OK(status
)) {
2167 if (NT_STATUS_IS_OK(state
->first_status
)) {
2168 state
->first_status
= status
;
2176 NTSTATUS
smb1srv_session_table_init(struct smbXsrv_connection
*conn
)
2179 * Allow a range from 1..65534 with 65534 values.
2181 return smbXsrv_session_table_init(conn
, 1, UINT16_MAX
- 1,
2185 NTSTATUS
smb1srv_session_lookup(struct smbXsrv_connection
*conn
,
2186 uint16_t vuid
, NTTIME now
,
2187 struct smbXsrv_session
**session
)
2189 struct smbXsrv_session_table
*table
= conn
->client
->session_table
;
2190 uint32_t local_id
= vuid
;
2192 return smbXsrv_session_local_lookup(table
, conn
, local_id
, now
,
2196 NTSTATUS
smbXsrv_session_info_lookup(struct smbXsrv_client
*client
,
2197 uint64_t session_wire_id
,
2198 struct auth_session_info
**si
)
2200 struct smbXsrv_session_table
*table
= client
->session_table
;
2201 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
2202 struct smbXsrv_session_local_fetch_state state
= {
2204 .status
= NT_STATUS_INTERNAL_ERROR
,
2209 if (session_wire_id
== 0) {
2210 return NT_STATUS_USER_SESSION_DELETED
;
2213 if (table
== NULL
) {
2214 /* this might happen before the end of negprot */
2215 return NT_STATUS_USER_SESSION_DELETED
;
2218 if (table
->local
.db_ctx
== NULL
) {
2219 return NT_STATUS_INTERNAL_ERROR
;
2222 key
= smbXsrv_session_local_id_to_key(session_wire_id
, key_buf
);
2224 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
2225 smbXsrv_session_local_fetch_parser
,
2227 if (!NT_STATUS_IS_OK(status
)) {
2230 if (!NT_STATUS_IS_OK(state
.status
)) {
2231 return state
.status
;
2233 if (state
.session
->global
->auth_session_info
== NULL
) {
2234 return NT_STATUS_USER_SESSION_DELETED
;
2237 *si
= state
.session
->global
->auth_session_info
;
2238 return NT_STATUS_OK
;
2242 * In memory of get_valid_user_struct()
2244 * This function is similar to smbXsrv_session_local_lookup() and it's wrappers,
2245 * but it doesn't implement the state checks of
2246 * those. get_valid_smbXsrv_session() is NOT meant to be called to validate the
2247 * session wire-id of incoming SMB requests, it MUST only be used in later
2248 * internal processing where the session wire-id has already been validated.
2250 NTSTATUS
get_valid_smbXsrv_session(struct smbXsrv_client
*client
,
2251 uint64_t session_wire_id
,
2252 struct smbXsrv_session
**session
)
2254 struct smbXsrv_session_table
*table
= client
->session_table
;
2255 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
2256 struct smbXsrv_session_local_fetch_state state
= {
2258 .status
= NT_STATUS_INTERNAL_ERROR
,
2263 if (session_wire_id
== 0) {
2264 return NT_STATUS_USER_SESSION_DELETED
;
2267 if (table
== NULL
) {
2268 /* this might happen before the end of negprot */
2269 return NT_STATUS_USER_SESSION_DELETED
;
2272 if (table
->local
.db_ctx
== NULL
) {
2273 return NT_STATUS_INTERNAL_ERROR
;
2276 key
= smbXsrv_session_local_id_to_key(session_wire_id
, key_buf
);
2278 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
2279 smbXsrv_session_local_fetch_parser
,
2281 if (!NT_STATUS_IS_OK(status
)) {
2284 if (!NT_STATUS_IS_OK(state
.status
)) {
2285 return state
.status
;
2287 if (state
.session
->global
->auth_session_info
== NULL
) {
2288 return NT_STATUS_USER_SESSION_DELETED
;
2291 *session
= state
.session
;
2292 return NT_STATUS_OK
;
2295 NTSTATUS
smb2srv_session_lookup_global(struct smbXsrv_client
*client
,
2296 uint64_t session_wire_id
,
2297 TALLOC_CTX
*mem_ctx
,
2298 struct smbXsrv_session
**_session
)
2300 TALLOC_CTX
*frame
= talloc_stackframe();
2301 struct smbXsrv_session_table
*table
= client
->session_table
;
2302 uint32_t global_id
= session_wire_id
& UINT32_MAX
;
2303 uint64_t global_zeros
= session_wire_id
& 0xFFFFFFFF00000000LLU
;
2304 struct smbXsrv_session
*session
= NULL
;
2305 struct db_record
*global_rec
= NULL
;
2306 bool is_free
= false;
2309 if (global_id
== 0) {
2311 return NT_STATUS_USER_SESSION_DELETED
;
2313 if (global_zeros
!= 0) {
2315 return NT_STATUS_USER_SESSION_DELETED
;
2318 if (table
== NULL
) {
2319 /* this might happen before the end of negprot */
2321 return NT_STATUS_USER_SESSION_DELETED
;
2324 if (table
->global
.db_ctx
== NULL
) {
2326 return NT_STATUS_INTERNAL_ERROR
;
2329 session
= talloc_zero(mem_ctx
, struct smbXsrv_session
);
2330 if (session
== NULL
) {
2332 return NT_STATUS_NO_MEMORY
;
2334 talloc_steal(frame
, session
);
2336 session
->client
= client
;
2337 session
->status
= NT_STATUS_BAD_LOGON_SESSION_STATE
;
2338 session
->local_id
= global_id
;
2341 * This means smb2_get_new_nonce() will return
2342 * NT_STATUS_ENCRYPTION_FAILED.
2344 * But we initialize some random parts just in case...
2346 session
->nonce_high_max
= session
->nonce_high
= 0;
2347 generate_nonce_buffer((uint8_t *)&session
->nonce_high_random
,
2348 sizeof(session
->nonce_high_random
));
2349 generate_nonce_buffer((uint8_t *)&session
->nonce_low
,
2350 sizeof(session
->nonce_low
));
2352 global_rec
= smbXsrv_session_global_fetch_locked(table
->global
.db_ctx
,
2355 if (global_rec
== NULL
) {
2357 return NT_STATUS_INTERNAL_DB_ERROR
;
2360 smbXsrv_session_global_verify_record(global_rec
,
2368 return NT_STATUS_USER_SESSION_DELETED
;
2372 * We don't have channels on this session
2373 * and only the main signing key
2375 session
->global
->num_channels
= 0;
2376 status
= smb2_signing_key_sign_create(session
->global
,
2377 session
->global
->signing_algo
,
2378 NULL
, /* no master key */
2379 NULL
, /* derivations */
2380 &session
->global
->signing_key
);
2381 if (!NT_STATUS_IS_OK(status
)) {
2383 return NT_STATUS_NO_MEMORY
;
2385 session
->global
->signing_key
->blob
= session
->global
->signing_key_blob
;
2386 session
->global
->signing_flags
= 0;
2388 status
= smb2_signing_key_cipher_create(session
->global
,
2389 session
->global
->encryption_cipher
,
2390 NULL
, /* no master key */
2391 NULL
, /* derivations */
2392 &session
->global
->decryption_key
);
2393 if (!NT_STATUS_IS_OK(status
)) {
2395 return NT_STATUS_NO_MEMORY
;
2397 session
->global
->decryption_key
->blob
= session
->global
->decryption_key_blob
;
2398 session
->global
->encryption_flags
= 0;
2400 *_session
= talloc_move(mem_ctx
, &session
);
2402 return NT_STATUS_OK
;
2405 NTSTATUS
smb2srv_session_table_init(struct smbXsrv_connection
*conn
)
2408 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
2410 return smbXsrv_session_table_init(conn
, 1, UINT32_MAX
- 1,
2414 static NTSTATUS
smb2srv_session_lookup_raw(struct smbXsrv_session_table
*table
,
2415 /* conn: optional */
2416 struct smbXsrv_connection
*conn
,
2417 uint64_t session_id
, NTTIME now
,
2418 struct smbXsrv_session
**session
)
2420 uint32_t local_id
= session_id
& UINT32_MAX
;
2421 uint64_t local_zeros
= session_id
& 0xFFFFFFFF00000000LLU
;
2423 if (local_zeros
!= 0) {
2424 return NT_STATUS_USER_SESSION_DELETED
;
2427 return smbXsrv_session_local_lookup(table
, conn
, local_id
, now
,
2431 NTSTATUS
smb2srv_session_lookup_conn(struct smbXsrv_connection
*conn
,
2432 uint64_t session_id
, NTTIME now
,
2433 struct smbXsrv_session
**session
)
2435 struct smbXsrv_session_table
*table
= conn
->client
->session_table
;
2436 return smb2srv_session_lookup_raw(table
, conn
, session_id
, now
,
2440 NTSTATUS
smb2srv_session_lookup_client(struct smbXsrv_client
*client
,
2441 uint64_t session_id
, NTTIME now
,
2442 struct smbXsrv_session
**session
)
2444 struct smbXsrv_session_table
*table
= client
->session_table
;
2445 return smb2srv_session_lookup_raw(table
, NULL
, session_id
, now
,
2449 struct smbXsrv_session_global_traverse_state
{
2450 int (*fn
)(struct smbXsrv_session_global0
*, void *);
2454 static int smbXsrv_session_global_traverse_fn(struct db_record
*rec
, void *data
)
2457 struct smbXsrv_session_global_traverse_state
*state
=
2458 (struct smbXsrv_session_global_traverse_state
*)data
;
2459 TDB_DATA key
= dbwrap_record_get_key(rec
);
2460 TDB_DATA val
= dbwrap_record_get_value(rec
);
2461 DATA_BLOB blob
= data_blob_const(val
.dptr
, val
.dsize
);
2462 struct smbXsrv_session_globalB global_blob
;
2463 enum ndr_err_code ndr_err
;
2464 TALLOC_CTX
*frame
= talloc_stackframe();
2466 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
2467 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_globalB
);
2468 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
2469 DBG_WARNING("Invalid record in smbXsrv_session_global.tdb:"
2470 "key '%s' ndr_pull_struct_blob - %s\n",
2472 ndr_errstr(ndr_err
));
2476 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
2477 DBG_WARNING("Invalid record in smbXsrv_session_global.tdb:"
2478 "key '%s' unsupported version - %d\n",
2480 (int)global_blob
.version
);
2484 if (global_blob
.info
.info0
== NULL
) {
2485 DBG_WARNING("Invalid record in smbXsrv_tcon_global.tdb:"
2486 "key '%s' info0 NULL pointer\n",
2491 global_blob
.info
.info0
->db_rec
= rec
;
2492 ret
= state
->fn(global_blob
.info
.info0
, state
->private_data
);
2498 NTSTATUS
smbXsrv_session_global_traverse(
2499 int (*fn
)(struct smbXsrv_session_global0
*, void *),
2505 struct smbXsrv_session_global_traverse_state state
= {
2507 .private_data
= private_data
,
2511 status
= smbXsrv_session_global_init(NULL
);
2512 if (!NT_STATUS_IS_OK(status
)) {
2514 DBG_ERR("Failed to initialize session_global: %s\n",
2519 status
= dbwrap_traverse_read(smbXsrv_session_global_db_ctx
,
2520 smbXsrv_session_global_traverse_fn
,