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 "smbd/smbd.h"
25 #include "smbd/globals.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_rbt.h"
28 #include "dbwrap/dbwrap_open.h"
29 #include "dbwrap/dbwrap_watch.h"
32 #include "auth/gensec/gensec.h"
33 #include "../lib/tsocket/tsocket.h"
34 #include "../libcli/security/security.h"
36 #include "lib/util/util_tdb.h"
37 #include "librpc/gen_ndr/ndr_smbXsrv.h"
39 #include "lib/util/tevent_ntstatus.h"
40 #include "msg_channel.h"
42 struct smbXsrv_session_table
{
44 struct db_context
*db_ctx
;
47 uint32_t max_sessions
;
48 uint32_t num_sessions
;
51 struct db_context
*db_ctx
;
53 struct msg_channel
*close_channel
;
56 static struct db_context
*smbXsrv_session_global_db_ctx
= NULL
;
58 NTSTATUS
smbXsrv_session_global_init(void)
60 const char *global_path
= NULL
;
61 struct db_context
*db_ctx
= NULL
;
63 if (smbXsrv_session_global_db_ctx
!= NULL
) {
68 * This contains secret information like session keys!
70 global_path
= lock_path("smbXsrv_session_global.tdb");
72 db_ctx
= db_open(NULL
, global_path
,
76 TDB_INCOMPATIBLE_HASH
,
77 O_RDWR
| O_CREAT
, 0600,
82 status
= map_nt_error_from_unix_common(errno
);
87 smbXsrv_session_global_db_ctx
= db_ctx
;
94 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
95 * has the same result as integer comparison between the uint32_t
98 * TODO: implement string based key
101 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
103 static TDB_DATA
smbXsrv_session_global_id_to_key(uint32_t id
,
108 RSIVAL(key_buf
, 0, id
);
110 key
= make_tdb_data(key_buf
, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
);
116 static NTSTATUS
smbXsrv_session_global_key_to_id(TDB_DATA key
, uint32_t *id
)
119 return NT_STATUS_INVALID_PARAMETER
;
122 if (key
.dsize
!= SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
) {
123 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
126 *id
= RIVAL(key
.dptr
, 0);
132 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
134 static TDB_DATA
smbXsrv_session_local_id_to_key(uint32_t id
,
139 RSIVAL(key_buf
, 0, id
);
141 key
= make_tdb_data(key_buf
, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
);
146 static NTSTATUS
smbXsrv_session_local_key_to_id(TDB_DATA key
, uint32_t *id
)
149 return NT_STATUS_INVALID_PARAMETER
;
152 if (key
.dsize
!= SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
) {
153 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
156 *id
= RIVAL(key
.dptr
, 0);
161 static void smbXsrv_session_close_loop(struct tevent_req
*subreq
);
163 static NTSTATUS
smbXsrv_session_table_init(struct smbXsrv_connection
*conn
,
166 uint32_t max_sessions
)
168 struct smbXsrv_session_table
*table
;
170 struct tevent_req
*subreq
;
174 if (lowest_id
> highest_id
) {
175 return NT_STATUS_INTERNAL_ERROR
;
178 max_range
= highest_id
;
179 max_range
-= lowest_id
;
182 if (max_sessions
> max_range
) {
183 return NT_STATUS_INTERNAL_ERROR
;
186 table
= talloc_zero(conn
, struct smbXsrv_session_table
);
188 return NT_STATUS_NO_MEMORY
;
191 table
->local
.db_ctx
= db_open_rbt(table
);
192 if (table
->local
.db_ctx
== NULL
) {
194 return NT_STATUS_NO_MEMORY
;
196 table
->local
.lowest_id
= lowest_id
;
197 table
->local
.highest_id
= highest_id
;
198 table
->local
.max_sessions
= max_sessions
;
200 status
= smbXsrv_session_global_init();
201 if (!NT_STATUS_IS_OK(status
)) {
206 table
->global
.db_ctx
= smbXsrv_session_global_db_ctx
;
208 dbwrap_watch_db(table
->global
.db_ctx
, conn
->msg_ctx
);
210 ret
= msg_channel_init(table
, conn
->msg_ctx
,
211 MSG_SMBXSRV_SESSION_CLOSE
,
212 &table
->close_channel
);
214 status
= map_nt_error_from_unix_common(errno
);
219 subreq
= msg_read_send(table
, conn
->ev_ctx
, table
->close_channel
);
220 if (subreq
== NULL
) {
222 return NT_STATUS_NO_MEMORY
;
224 tevent_req_set_callback(subreq
, smbXsrv_session_close_loop
, conn
);
226 conn
->session_table
= table
;
230 static void smbXsrv_session_close_loop(struct tevent_req
*subreq
)
232 struct smbXsrv_connection
*conn
=
233 tevent_req_callback_data(subreq
,
234 struct smbXsrv_connection
);
235 struct smbXsrv_session_table
*table
= conn
->session_table
;
237 struct messaging_rec
*rec
= NULL
;
238 struct smbXsrv_session_closeB close_blob
;
239 enum ndr_err_code ndr_err
;
240 struct smbXsrv_session_close0
*close_info0
= NULL
;
241 struct smbXsrv_session
*session
= NULL
;
243 struct timeval tv
= timeval_current();
244 NTTIME now
= timeval_to_nttime(&tv
);
246 ret
= msg_read_recv(subreq
, talloc_tos(), &rec
);
252 ndr_err
= ndr_pull_struct_blob(&rec
->buf
, rec
, &close_blob
,
253 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_closeB
);
254 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
255 status
= ndr_map_error2ntstatus(ndr_err
);
256 DEBUG(1,("smbXsrv_session_close_loop: "
257 "ndr_pull_struct_blob - %s\n",
262 DEBUG(10,("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n"));
264 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
267 if (close_blob
.version
!= SMBXSRV_VERSION_0
) {
268 DEBUG(0,("smbXsrv_session_close_loop: "
269 "ignore invalid version %u\n", close_blob
.version
));
270 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
274 close_info0
= close_blob
.info
.info0
;
275 if (close_info0
== NULL
) {
276 DEBUG(0,("smbXsrv_session_close_loop: "
277 "ignore NULL info %u\n", close_blob
.version
));
278 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
282 status
= smb2srv_session_lookup(conn
, close_info0
->old_session_wire_id
,
284 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_SESSION_DELETED
)) {
285 DEBUG(4,("smbXsrv_session_close_loop: "
286 "old_session_wire_id %llu not found\n",
287 (unsigned long long)close_info0
->old_session_wire_id
));
289 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
293 if (!NT_STATUS_IS_OK(status
) &&
294 !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) &&
295 !NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_SESSION_EXPIRED
)) {
296 DEBUG(1,("smbXsrv_session_close_loop: "
297 "old_session_wire_id %llu - %s\n",
298 (unsigned long long)close_info0
->old_session_wire_id
,
301 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
306 if (session
->global
->session_global_id
!= close_info0
->old_session_global_id
) {
307 DEBUG(1,("smbXsrv_session_close_loop: "
308 "old_session_wire_id %llu - global %u != %u\n",
309 (unsigned long long)close_info0
->old_session_wire_id
,
310 session
->global
->session_global_id
,
311 close_info0
->old_session_global_id
));
313 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
318 if (session
->global
->creation_time
!= close_info0
->old_creation_time
) {
319 DEBUG(1,("smbXsrv_session_close_loop: "
320 "old_session_wire_id %llu - "
321 "creation %s (%llu) != %s (%llu)\n",
322 (unsigned long long)close_info0
->old_session_wire_id
,
323 nt_time_string(rec
, session
->global
->creation_time
),
324 (unsigned long long)session
->global
->creation_time
,
325 nt_time_string(rec
, close_info0
->old_creation_time
),
326 (unsigned long long)close_info0
->old_creation_time
));
328 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
334 * TODO: cancel all outstanding requests on the session
336 status
= smbXsrv_session_logoff(session
);
337 if (!NT_STATUS_IS_OK(status
)) {
338 DEBUG(0, ("smbXsrv_session_close_loop: "
339 "smbXsrv_session_logoff(%llu) failed: %s\n",
340 (unsigned long long)session
->global
->session_wire_id
,
343 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
346 TALLOC_FREE(session
);
351 subreq
= msg_read_send(table
, conn
->ev_ctx
, table
->close_channel
);
352 if (subreq
== NULL
) {
353 smbd_server_connection_terminate(conn
->sconn
,
354 "msg_read_send() failed");
357 tevent_req_set_callback(subreq
, smbXsrv_session_close_loop
, conn
);
360 struct smb1srv_session_local_allocate_state
{
361 const uint32_t lowest_id
;
362 const uint32_t highest_id
;
368 static int smb1srv_session_local_allocate_traverse(struct db_record
*rec
,
371 struct smb1srv_session_local_allocate_state
*state
=
372 (struct smb1srv_session_local_allocate_state
*)private_data
;
373 TDB_DATA key
= dbwrap_record_get_key(rec
);
377 status
= smbXsrv_session_local_key_to_id(key
, &id
);
378 if (!NT_STATUS_IS_OK(status
)) {
379 state
->status
= status
;
383 if (id
<= state
->last_id
) {
384 state
->status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
389 if (id
> state
->useable_id
) {
390 state
->status
= NT_STATUS_OK
;
394 if (state
->useable_id
== state
->highest_id
) {
395 state
->status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
399 state
->useable_id
+=1;
403 static NTSTATUS
smb1srv_session_local_allocate_id(struct db_context
*db
,
407 struct db_record
**_rec
,
410 struct smb1srv_session_local_allocate_state state
= {
411 .lowest_id
= lowest_id
,
412 .highest_id
= highest_id
,
414 .useable_id
= lowest_id
,
415 .status
= NT_STATUS_INTERNAL_ERROR
,
425 if (lowest_id
> highest_id
) {
426 return NT_STATUS_INSUFFICIENT_RESOURCES
;
430 * first we try randomly
432 range
= (highest_id
- lowest_id
) + 1;
434 for (i
= 0; i
< (range
/ 2); i
++) {
436 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
439 struct db_record
*rec
= NULL
;
441 id
= generate_random() % range
;
444 if (id
< lowest_id
) {
447 if (id
> highest_id
) {
451 key
= smbXsrv_session_local_id_to_key(id
, key_buf
);
453 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
455 return NT_STATUS_INSUFFICIENT_RESOURCES
;
458 val
= dbwrap_record_get_value(rec
);
459 if (val
.dsize
!= 0) {
470 * if the range is almost full,
471 * we traverse the whole table
472 * (this relies on sorted behavior of dbwrap_rbt)
474 status
= dbwrap_traverse_read(db
, smb1srv_session_local_allocate_traverse
,
476 if (NT_STATUS_IS_OK(status
)) {
477 if (NT_STATUS_IS_OK(state
.status
)) {
478 return NT_STATUS_INTERNAL_ERROR
;
481 if (!NT_STATUS_EQUAL(state
.status
, NT_STATUS_INTERNAL_ERROR
)) {
485 if (state
.useable_id
<= state
.highest_id
) {
486 state
.status
= NT_STATUS_OK
;
488 return NT_STATUS_INSUFFICIENT_RESOURCES
;
490 } else if (!NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_DB_CORRUPTION
)) {
492 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
494 * If we get anything else it is an error, because it
495 * means we did not manage to find a free slot in
498 return NT_STATUS_INSUFFICIENT_RESOURCES
;
501 if (NT_STATUS_IS_OK(state
.status
)) {
503 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
506 struct db_record
*rec
= NULL
;
508 id
= state
.useable_id
;
510 key
= smbXsrv_session_local_id_to_key(id
, key_buf
);
512 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
514 return NT_STATUS_INSUFFICIENT_RESOURCES
;
517 val
= dbwrap_record_get_value(rec
);
518 if (val
.dsize
!= 0) {
520 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
531 struct smbXsrv_session_local_fetch_state
{
532 struct smbXsrv_session
*session
;
536 static void smbXsrv_session_local_fetch_parser(TDB_DATA key
, TDB_DATA data
,
539 struct smbXsrv_session_local_fetch_state
*state
=
540 (struct smbXsrv_session_local_fetch_state
*)private_data
;
543 if (data
.dsize
!= sizeof(ptr
)) {
544 state
->status
= NT_STATUS_INTERNAL_DB_ERROR
;
548 memcpy(&ptr
, data
.dptr
, data
.dsize
);
549 state
->session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
550 state
->status
= NT_STATUS_OK
;
553 static NTSTATUS
smbXsrv_session_local_lookup(struct smbXsrv_session_table
*table
,
554 uint32_t session_local_id
,
556 struct smbXsrv_session
**_session
)
558 struct smbXsrv_session_local_fetch_state state
= {
560 .status
= NT_STATUS_INTERNAL_ERROR
,
562 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
568 if (session_local_id
== 0) {
569 return NT_STATUS_USER_SESSION_DELETED
;
573 /* this might happen before the end of negprot */
574 return NT_STATUS_USER_SESSION_DELETED
;
577 if (table
->local
.db_ctx
== NULL
) {
578 return NT_STATUS_INTERNAL_ERROR
;
581 key
= smbXsrv_session_local_id_to_key(session_local_id
, key_buf
);
583 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
584 smbXsrv_session_local_fetch_parser
,
586 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
587 return NT_STATUS_USER_SESSION_DELETED
;
588 } else if (!NT_STATUS_IS_OK(status
)) {
591 if (!NT_STATUS_IS_OK(state
.status
)) {
595 if (NT_STATUS_EQUAL(state
.session
->status
, NT_STATUS_USER_SESSION_DELETED
)) {
596 return NT_STATUS_USER_SESSION_DELETED
;
599 state
.session
->idle_time
= now
;
601 if (!NT_STATUS_IS_OK(state
.session
->status
)) {
602 *_session
= state
.session
;
603 return state
.session
->status
;
606 if (now
> state
.session
->global
->expiration_time
) {
607 state
.session
->status
= NT_STATUS_NETWORK_SESSION_EXPIRED
;
610 *_session
= state
.session
;
611 return state
.session
->status
;
614 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0
*global
)
619 static void smbXsrv_session_global_verify_record(struct db_record
*db_rec
,
623 struct smbXsrv_session_global0
**_g
);
625 static NTSTATUS
smbXsrv_session_global_allocate(struct db_context
*db
,
627 struct smbXsrv_session_global0
**_global
)
630 struct smbXsrv_session_global0
*global
= NULL
;
631 uint32_t last_free
= 0;
632 const uint32_t min_tries
= 3;
636 global
= talloc_zero(mem_ctx
, struct smbXsrv_session_global0
);
637 if (global
== NULL
) {
638 return NT_STATUS_NO_MEMORY
;
640 talloc_set_destructor(global
, smbXsrv_session_global_destructor
);
643 * Here we just randomly try the whole 32-bit space
645 * We use just 32-bit, because we want to reuse the
648 for (i
= 0; i
< UINT32_MAX
; i
++) {
649 bool is_free
= false;
650 bool was_free
= false;
652 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
655 if (i
>= min_tries
&& last_free
!= 0) {
658 id
= generate_random();
663 if (id
== UINT32_MAX
) {
667 key
= smbXsrv_session_global_id_to_key(id
, key_buf
);
669 global
->db_rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
670 if (global
->db_rec
== NULL
) {
672 return NT_STATUS_INSUFFICIENT_RESOURCES
;
675 smbXsrv_session_global_verify_record(global
->db_rec
,
681 TALLOC_FREE(global
->db_rec
);
685 if (!was_free
&& i
< min_tries
) {
687 * The session_id is free now,
688 * but was not free before.
690 * This happens if a smbd crashed
691 * and did not cleanup the record.
693 * If this is one of our first tries,
694 * then we try to find a real free one.
696 if (last_free
== 0) {
699 TALLOC_FREE(global
->db_rec
);
703 global
->session_global_id
= id
;
709 /* should not be reached */
711 return NT_STATUS_INTERNAL_ERROR
;
714 static void smbXsrv_session_global_verify_record(struct db_record
*db_rec
,
718 struct smbXsrv_session_global0
**_g
)
723 struct smbXsrv_session_globalB global_blob
;
724 enum ndr_err_code ndr_err
;
725 struct smbXsrv_session_global0
*global
= NULL
;
727 TALLOC_CTX
*frame
= talloc_stackframe();
738 key
= dbwrap_record_get_key(db_rec
);
740 val
= dbwrap_record_get_value(db_rec
);
741 if (val
.dsize
== 0) {
750 blob
= data_blob_const(val
.dptr
, val
.dsize
);
752 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
753 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_globalB
);
754 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
755 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
756 DEBUG(1,("smbXsrv_session_global_verify_record: "
757 "key '%s' ndr_pull_struct_blob - %s\n",
758 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
764 DEBUG(10,("smbXsrv_session_global_verify_record\n"));
766 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
769 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
770 DEBUG(0,("smbXsrv_session_global_verify_record: "
771 "key '%s' use unsupported version %u\n",
772 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
773 global_blob
.version
));
774 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
779 global
= global_blob
.info
.info0
;
781 exists
= serverid_exists(&global
->channels
[0].server_id
);
783 DEBUG(2,("smbXsrv_session_global_verify_record: "
784 "key '%s' server_id %s does not exist.\n",
785 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
786 server_id_str(frame
, &global
->channels
[0].server_id
)));
788 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
791 dbwrap_record_delete(db_rec
);
797 *_g
= talloc_move(mem_ctx
, &global
);
802 static NTSTATUS
smbXsrv_session_global_store(struct smbXsrv_session_global0
*global
)
804 struct smbXsrv_session_globalB global_blob
;
805 DATA_BLOB blob
= data_blob_null
;
809 enum ndr_err_code ndr_err
;
812 * TODO: if we use other versions than '0'
813 * we would add glue code here, that would be able to
814 * store the information in the old format.
817 if (global
->db_rec
== NULL
) {
818 return NT_STATUS_INTERNAL_ERROR
;
821 key
= dbwrap_record_get_key(global
->db_rec
);
822 val
= dbwrap_record_get_value(global
->db_rec
);
824 ZERO_STRUCT(global_blob
);
825 global_blob
.version
= smbXsrv_version_global_current();
826 if (val
.dsize
>= 8) {
827 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
829 global_blob
.seqnum
+= 1;
830 global_blob
.info
.info0
= global
;
832 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
833 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_session_globalB
);
834 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
835 status
= ndr_map_error2ntstatus(ndr_err
);
836 DEBUG(1,("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
837 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
839 TALLOC_FREE(global
->db_rec
);
843 val
= make_tdb_data(blob
.data
, blob
.length
);
844 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
845 if (!NT_STATUS_IS_OK(status
)) {
846 DEBUG(1,("smbXsrv_session_global_store: key '%s' store - %s\n",
847 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
849 TALLOC_FREE(global
->db_rec
);
854 DEBUG(10,("smbXsrv_session_global_store: key '%s' stored\n",
855 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
)));
856 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
859 TALLOC_FREE(global
->db_rec
);
864 struct smb2srv_session_close_previous_state
{
865 struct tevent_context
*ev
;
866 struct smbXsrv_connection
*connection
;
867 struct dom_sid
*current_sid
;
868 uint64_t current_session_id
;
869 struct db_record
*db_rec
;
872 static void smb2srv_session_close_previous_check(struct tevent_req
*req
);
873 static void smb2srv_session_close_previous_modified(struct tevent_req
*subreq
);
875 struct tevent_req
*smb2srv_session_close_previous_send(TALLOC_CTX
*mem_ctx
,
876 struct tevent_context
*ev
,
877 struct smbXsrv_connection
*conn
,
878 struct auth_session_info
*session_info
,
879 uint64_t previous_session_id
,
880 uint64_t current_session_id
)
882 struct tevent_req
*req
;
883 struct smb2srv_session_close_previous_state
*state
;
884 uint32_t global_id
= previous_session_id
& UINT32_MAX
;
885 uint64_t global_zeros
= previous_session_id
& 0xFFFFFFFF00000000LLU
;
886 struct smbXsrv_session_table
*table
= conn
->session_table
;
887 struct security_token
*current_token
= NULL
;
888 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
891 req
= tevent_req_create(mem_ctx
, &state
,
892 struct smb2srv_session_close_previous_state
);
897 state
->connection
= conn
;
898 state
->current_session_id
= current_session_id
;
900 if (global_zeros
!= 0) {
901 tevent_req_done(req
);
902 return tevent_req_post(req
, ev
);
905 if (session_info
== NULL
) {
906 tevent_req_done(req
);
907 return tevent_req_post(req
, ev
);
909 current_token
= session_info
->security_token
;
911 if (current_token
->num_sids
> PRIMARY_USER_SID_INDEX
) {
912 state
->current_sid
= ¤t_token
->sids
[PRIMARY_USER_SID_INDEX
];
915 if (state
->current_sid
== NULL
) {
916 tevent_req_done(req
);
917 return tevent_req_post(req
, ev
);
920 if (!security_token_has_nt_authenticated_users(current_token
)) {
922 tevent_req_done(req
);
923 return tevent_req_post(req
, ev
);
926 key
= smbXsrv_session_global_id_to_key(global_id
, key_buf
);
928 state
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
930 if (state
->db_rec
== NULL
) {
931 tevent_req_nterror(req
, NT_STATUS_UNSUCCESSFUL
);
932 return tevent_req_post(req
, ev
);
935 smb2srv_session_close_previous_check(req
);
936 if (!tevent_req_is_in_progress(req
)) {
937 return tevent_req_post(req
, ev
);
943 static void smb2srv_session_close_previous_check(struct tevent_req
*req
)
945 struct smb2srv_session_close_previous_state
*state
=
947 struct smb2srv_session_close_previous_state
);
948 struct smbXsrv_connection
*conn
= state
->connection
;
950 struct security_token
*previous_token
= NULL
;
951 struct smbXsrv_session_global0
*global
= NULL
;
952 enum ndr_err_code ndr_err
;
953 struct smbXsrv_session_close0 close_info0
;
954 struct smbXsrv_session_closeB close_blob
;
955 struct tevent_req
*subreq
= NULL
;
957 bool is_free
= false;
959 smbXsrv_session_global_verify_record(state
->db_rec
,
966 TALLOC_FREE(state
->db_rec
);
967 tevent_req_done(req
);
971 if (global
->auth_session_info
== NULL
) {
972 TALLOC_FREE(state
->db_rec
);
973 tevent_req_done(req
);
977 previous_token
= global
->auth_session_info
->security_token
;
979 if (!security_token_is_sid(previous_token
, state
->current_sid
)) {
980 TALLOC_FREE(state
->db_rec
);
981 tevent_req_done(req
);
985 subreq
= dbwrap_record_watch_send(state
, state
->ev
,
986 state
->db_rec
, conn
->msg_ctx
);
987 if (tevent_req_nomem(subreq
, req
)) {
988 TALLOC_FREE(state
->db_rec
);
991 tevent_req_set_callback(subreq
,
992 smb2srv_session_close_previous_modified
,
995 close_info0
.old_session_global_id
= global
->session_global_id
;
996 close_info0
.old_session_wire_id
= global
->session_wire_id
;
997 close_info0
.old_creation_time
= global
->creation_time
;
998 close_info0
.new_session_wire_id
= state
->current_session_id
;
1000 ZERO_STRUCT(close_blob
);
1001 close_blob
.version
= smbXsrv_version_global_current();
1002 close_blob
.info
.info0
= &close_info0
;
1004 ndr_err
= ndr_push_struct_blob(&blob
, state
, &close_blob
,
1005 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_session_closeB
);
1006 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1007 TALLOC_FREE(state
->db_rec
);
1008 status
= ndr_map_error2ntstatus(ndr_err
);
1009 DEBUG(1,("smb2srv_session_close_previous_check: "
1010 "old_session[%llu] new_session[%llu] ndr_push - %s\n",
1011 (unsigned long long)close_info0
.old_session_wire_id
,
1012 (unsigned long long)close_info0
.new_session_wire_id
,
1013 nt_errstr(status
)));
1014 tevent_req_nterror(req
, status
);
1018 status
= messaging_send(conn
->msg_ctx
,
1019 global
->channels
[0].server_id
,
1020 MSG_SMBXSRV_SESSION_CLOSE
, &blob
);
1021 TALLOC_FREE(state
->db_rec
);
1022 if (tevent_req_nterror(req
, status
)) {
1026 TALLOC_FREE(global
);
1030 static void smb2srv_session_close_previous_modified(struct tevent_req
*subreq
)
1032 struct tevent_req
*req
=
1033 tevent_req_callback_data(subreq
,
1035 struct smb2srv_session_close_previous_state
*state
=
1036 tevent_req_data(req
,
1037 struct smb2srv_session_close_previous_state
);
1040 status
= dbwrap_record_watch_recv(subreq
, state
, &state
->db_rec
);
1041 TALLOC_FREE(subreq
);
1042 if (tevent_req_nterror(req
, status
)) {
1046 smb2srv_session_close_previous_check(req
);
1049 NTSTATUS
smb2srv_session_close_previous_recv(struct tevent_req
*req
)
1053 if (tevent_req_is_nterror(req
, &status
)) {
1054 tevent_req_received(req
);
1058 tevent_req_received(req
);
1059 return NT_STATUS_OK
;
1062 static int smbXsrv_session_destructor(struct smbXsrv_session
*session
)
1065 struct smbd_smb2_request
*preq
= NULL
;
1067 if (session
->connection
!= NULL
) {
1068 preq
= session
->connection
->sconn
->smb2
.requests
;
1071 for (; preq
!= NULL
; preq
= preq
->next
) {
1072 if (preq
->session
!= session
) {
1076 preq
->session
= NULL
;
1078 * If we no longer have a session we can't
1079 * sign or encrypt replies.
1081 preq
->do_signing
= false;
1082 preq
->do_encryption
= false;
1085 status
= smbXsrv_session_logoff(session
);
1086 if (!NT_STATUS_IS_OK(status
)) {
1087 DEBUG(0, ("smbXsrv_session_destructor: "
1088 "smbXsrv_session_logoff() failed: %s\n",
1089 nt_errstr(status
)));
1092 TALLOC_FREE(session
->global
);
1097 NTSTATUS
smbXsrv_session_create(struct smbXsrv_connection
*conn
,
1099 struct smbXsrv_session
**_session
)
1101 struct smbXsrv_session_table
*table
= conn
->session_table
;
1102 struct db_record
*local_rec
= NULL
;
1103 struct smbXsrv_session
*session
= NULL
;
1106 struct smbXsrv_session_global0
*global
= NULL
;
1107 struct smbXsrv_channel_global0
*channels
= NULL
;
1110 if (table
->local
.num_sessions
>= table
->local
.max_sessions
) {
1111 return NT_STATUS_INSUFFICIENT_RESOURCES
;
1114 session
= talloc_zero(table
, struct smbXsrv_session
);
1115 if (session
== NULL
) {
1116 return NT_STATUS_NO_MEMORY
;
1118 session
->table
= table
;
1119 session
->idle_time
= now
;
1120 session
->status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1121 session
->connection
= conn
;
1123 status
= smbXsrv_session_global_allocate(table
->global
.db_ctx
,
1126 if (!NT_STATUS_IS_OK(status
)) {
1127 TALLOC_FREE(session
);
1130 session
->global
= global
;
1132 if (conn
->protocol
>= PROTOCOL_SMB2_02
) {
1133 uint64_t id
= global
->session_global_id
;
1134 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
1137 global
->connection_dialect
= conn
->smb2
.server
.dialect
;
1139 global
->session_wire_id
= id
;
1141 status
= smb2srv_tcon_table_init(session
);
1142 if (!NT_STATUS_IS_OK(status
)) {
1143 TALLOC_FREE(session
);
1147 session
->local_id
= global
->session_global_id
;
1149 key
= smbXsrv_session_local_id_to_key(session
->local_id
, key_buf
);
1151 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
1153 if (local_rec
== NULL
) {
1154 TALLOC_FREE(session
);
1155 return NT_STATUS_NO_MEMORY
;
1158 val
= dbwrap_record_get_value(local_rec
);
1159 if (val
.dsize
!= 0) {
1160 TALLOC_FREE(session
);
1161 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1165 status
= smb1srv_session_local_allocate_id(table
->local
.db_ctx
,
1166 table
->local
.lowest_id
,
1167 table
->local
.highest_id
,
1170 &session
->local_id
);
1171 if (!NT_STATUS_IS_OK(status
)) {
1172 TALLOC_FREE(session
);
1176 global
->session_wire_id
= session
->local_id
;
1179 global
->creation_time
= now
;
1180 global
->expiration_time
= GENSEC_EXPIRE_TIME_INFINITY
;
1182 global
->num_channels
= 1;
1183 channels
= talloc_zero_array(global
,
1184 struct smbXsrv_channel_global0
,
1185 global
->num_channels
);
1186 if (channels
== NULL
) {
1187 TALLOC_FREE(session
);
1188 return NT_STATUS_NO_MEMORY
;
1190 global
->channels
= channels
;
1192 channels
[0].server_id
= messaging_server_id(conn
->msg_ctx
);
1193 channels
[0].local_address
= tsocket_address_string(conn
->local_address
,
1195 if (channels
[0].local_address
== NULL
) {
1196 TALLOC_FREE(session
);
1197 return NT_STATUS_NO_MEMORY
;
1199 channels
[0].remote_address
= tsocket_address_string(conn
->remote_address
,
1201 if (channels
[0].remote_address
== NULL
) {
1202 TALLOC_FREE(session
);
1203 return NT_STATUS_NO_MEMORY
;
1205 channels
[0].remote_name
= talloc_strdup(channels
, conn
->remote_hostname
);
1206 if (channels
[0].remote_name
== NULL
) {
1207 TALLOC_FREE(session
);
1208 return NT_STATUS_NO_MEMORY
;
1210 channels
[0].signing_key
= data_blob_null
;
1213 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
1214 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
1215 TALLOC_FREE(local_rec
);
1216 if (!NT_STATUS_IS_OK(status
)) {
1217 TALLOC_FREE(session
);
1220 table
->local
.num_sessions
+= 1;
1222 talloc_set_destructor(session
, smbXsrv_session_destructor
);
1224 status
= smbXsrv_session_global_store(global
);
1225 if (!NT_STATUS_IS_OK(status
)) {
1226 DEBUG(0,("smbXsrv_session_create: "
1227 "global_id (0x%08x) store failed - %s\n",
1228 session
->global
->session_global_id
,
1229 nt_errstr(status
)));
1230 TALLOC_FREE(session
);
1235 struct smbXsrv_sessionB session_blob
;
1237 ZERO_STRUCT(session_blob
);
1238 session_blob
.version
= SMBXSRV_VERSION_0
;
1239 session_blob
.info
.info0
= session
;
1241 DEBUG(10,("smbXsrv_session_create: global_id (0x%08x) stored\n",
1242 session
->global
->session_global_id
));
1243 NDR_PRINT_DEBUG(smbXsrv_sessionB
, &session_blob
);
1246 *_session
= session
;
1247 return NT_STATUS_OK
;
1250 NTSTATUS
smbXsrv_session_update(struct smbXsrv_session
*session
)
1252 struct smbXsrv_session_table
*table
= session
->table
;
1254 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
1257 if (session
->global
->db_rec
!= NULL
) {
1258 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1259 "Called with db_rec != NULL'\n",
1260 session
->global
->session_global_id
));
1261 return NT_STATUS_INTERNAL_ERROR
;
1264 key
= smbXsrv_session_global_id_to_key(
1265 session
->global
->session_global_id
,
1268 session
->global
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
1269 session
->global
, key
);
1270 if (session
->global
->db_rec
== NULL
) {
1271 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1272 "Failed to lock global key '%s'\n",
1273 session
->global
->session_global_id
,
1274 hex_encode_talloc(talloc_tos(), key
.dptr
,
1276 return NT_STATUS_INTERNAL_DB_ERROR
;
1279 status
= smbXsrv_session_global_store(session
->global
);
1280 if (!NT_STATUS_IS_OK(status
)) {
1281 DEBUG(0,("smbXsrv_session_update: "
1282 "global_id (0x%08x) store failed - %s\n",
1283 session
->global
->session_global_id
,
1284 nt_errstr(status
)));
1289 struct smbXsrv_sessionB session_blob
;
1291 ZERO_STRUCT(session_blob
);
1292 session_blob
.version
= SMBXSRV_VERSION_0
;
1293 session_blob
.info
.info0
= session
;
1295 DEBUG(10,("smbXsrv_session_update: global_id (0x%08x) stored\n",
1296 session
->global
->session_global_id
));
1297 NDR_PRINT_DEBUG(smbXsrv_sessionB
, &session_blob
);
1300 return NT_STATUS_OK
;
1303 NTSTATUS
smbXsrv_session_logoff(struct smbXsrv_session
*session
)
1305 struct smbXsrv_session_table
*table
;
1306 struct db_record
*local_rec
= NULL
;
1307 struct db_record
*global_rec
= NULL
;
1308 struct smbXsrv_connection
*conn
;
1310 NTSTATUS error
= NT_STATUS_OK
;
1312 if (session
->table
== NULL
) {
1313 return NT_STATUS_OK
;
1316 table
= session
->table
;
1317 session
->table
= NULL
;
1319 conn
= session
->connection
;
1320 session
->connection
= NULL
;
1321 session
->status
= NT_STATUS_USER_SESSION_DELETED
;
1323 global_rec
= session
->global
->db_rec
;
1324 session
->global
->db_rec
= NULL
;
1325 if (global_rec
== NULL
) {
1326 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
1329 key
= smbXsrv_session_global_id_to_key(
1330 session
->global
->session_global_id
,
1333 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
1334 session
->global
, key
);
1335 if (global_rec
== NULL
) {
1336 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1337 "Failed to lock global key '%s'\n",
1338 session
->global
->session_global_id
,
1339 hex_encode_talloc(global_rec
, key
.dptr
,
1341 error
= NT_STATUS_INTERNAL_ERROR
;
1345 if (global_rec
!= NULL
) {
1346 status
= dbwrap_record_delete(global_rec
);
1347 if (!NT_STATUS_IS_OK(status
)) {
1348 TDB_DATA key
= dbwrap_record_get_key(global_rec
);
1350 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1351 "failed to delete global key '%s': %s\n",
1352 session
->global
->session_global_id
,
1353 hex_encode_talloc(global_rec
, key
.dptr
,
1355 nt_errstr(status
)));
1359 TALLOC_FREE(global_rec
);
1361 local_rec
= session
->db_rec
;
1362 if (local_rec
== NULL
) {
1363 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
1366 key
= smbXsrv_session_local_id_to_key(session
->local_id
,
1369 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
1371 if (local_rec
== NULL
) {
1372 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1373 "Failed to lock local key '%s'\n",
1374 session
->global
->session_global_id
,
1375 hex_encode_talloc(local_rec
, key
.dptr
,
1377 error
= NT_STATUS_INTERNAL_ERROR
;
1381 if (local_rec
!= NULL
) {
1382 status
= dbwrap_record_delete(local_rec
);
1383 if (!NT_STATUS_IS_OK(status
)) {
1384 TDB_DATA key
= dbwrap_record_get_key(local_rec
);
1386 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1387 "failed to delete local key '%s': %s\n",
1388 session
->global
->session_global_id
,
1389 hex_encode_talloc(local_rec
, key
.dptr
,
1391 nt_errstr(status
)));
1394 table
->local
.num_sessions
-= 1;
1396 if (session
->db_rec
== NULL
) {
1397 TALLOC_FREE(local_rec
);
1399 session
->db_rec
= NULL
;
1401 if (session
->compat
) {
1402 file_close_user(conn
->sconn
, session
->compat
->vuid
);
1405 if (conn
->protocol
>= PROTOCOL_SMB2_02
) {
1406 status
= smb2srv_tcon_disconnect_all(session
);
1407 if (!NT_STATUS_IS_OK(status
)) {
1408 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1409 "smb2srv_tcon_disconnect_all() failed: %s\n",
1410 session
->global
->session_global_id
,
1411 nt_errstr(status
)));
1416 if (session
->compat
) {
1417 invalidate_vuid(conn
->sconn
, session
->compat
->vuid
);
1418 session
->compat
= NULL
;
1424 struct smbXsrv_session_logoff_all_state
{
1425 NTSTATUS first_status
;
1429 static int smbXsrv_session_logoff_all_callback(struct db_record
*local_rec
,
1430 void *private_data
);
1432 NTSTATUS
smbXsrv_session_logoff_all(struct smbXsrv_connection
*conn
)
1434 struct smbXsrv_session_table
*table
= conn
->session_table
;
1435 struct smbXsrv_session_logoff_all_state state
;
1439 if (table
== NULL
) {
1440 DEBUG(10, ("smbXsrv_session_logoff_all: "
1441 "empty session_table, nothing to do.\n"));
1442 return NT_STATUS_OK
;
1447 status
= dbwrap_traverse(table
->local
.db_ctx
,
1448 smbXsrv_session_logoff_all_callback
,
1450 if (!NT_STATUS_IS_OK(status
)) {
1451 DEBUG(0, ("smbXsrv_session_logoff_all: "
1452 "dbwrap_traverse() failed: %s\n",
1453 nt_errstr(status
)));
1457 if (!NT_STATUS_IS_OK(state
.first_status
)) {
1458 DEBUG(0, ("smbXsrv_session_logoff_all: "
1459 "count[%d] errors[%d] first[%s]\n",
1460 count
, state
.errors
,
1461 nt_errstr(state
.first_status
)));
1462 return state
.first_status
;
1465 return NT_STATUS_OK
;
1468 static int smbXsrv_session_logoff_all_callback(struct db_record
*local_rec
,
1471 struct smbXsrv_session_logoff_all_state
*state
=
1472 (struct smbXsrv_session_logoff_all_state
*)private_data
;
1475 struct smbXsrv_session
*session
= NULL
;
1476 struct smbd_smb2_request
*preq
= NULL
;
1479 val
= dbwrap_record_get_value(local_rec
);
1480 if (val
.dsize
!= sizeof(ptr
)) {
1481 status
= NT_STATUS_INTERNAL_ERROR
;
1482 if (NT_STATUS_IS_OK(state
->first_status
)) {
1483 state
->first_status
= status
;
1489 memcpy(&ptr
, val
.dptr
, val
.dsize
);
1490 session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
1492 session
->db_rec
= local_rec
;
1494 if (session
->connection
!= NULL
) {
1495 preq
= session
->connection
->sconn
->smb2
.requests
;
1498 for (; preq
!= NULL
; preq
= preq
->next
) {
1499 if (preq
->session
!= session
) {
1503 preq
->session
= NULL
;
1505 * If we no longer have a session we can't
1506 * sign or encrypt replies.
1508 preq
->do_signing
= false;
1509 preq
->do_encryption
= false;
1512 status
= smbXsrv_session_logoff(session
);
1513 if (!NT_STATUS_IS_OK(status
)) {
1514 if (NT_STATUS_IS_OK(state
->first_status
)) {
1515 state
->first_status
= status
;
1524 NTSTATUS
smb1srv_session_table_init(struct smbXsrv_connection
*conn
)
1527 * Allow a range from 1..65534 with 65534 values.
1529 return smbXsrv_session_table_init(conn
, 1, UINT16_MAX
- 1,
1533 NTSTATUS
smb1srv_session_lookup(struct smbXsrv_connection
*conn
,
1534 uint16_t vuid
, NTTIME now
,
1535 struct smbXsrv_session
**session
)
1537 struct smbXsrv_session_table
*table
= conn
->session_table
;
1538 uint32_t local_id
= vuid
;
1540 return smbXsrv_session_local_lookup(table
, local_id
, now
, session
);
1543 NTSTATUS
smb2srv_session_table_init(struct smbXsrv_connection
*conn
)
1546 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1548 return smbXsrv_session_table_init(conn
, 1, UINT32_MAX
- 1,
1552 NTSTATUS
smb2srv_session_lookup(struct smbXsrv_connection
*conn
,
1553 uint64_t session_id
, NTTIME now
,
1554 struct smbXsrv_session
**session
)
1556 struct smbXsrv_session_table
*table
= conn
->session_table
;
1557 uint32_t local_id
= session_id
& UINT32_MAX
;
1558 uint64_t local_zeros
= session_id
& 0xFFFFFFFF00000000LLU
;
1560 if (local_zeros
!= 0) {
1561 return NT_STATUS_USER_SESSION_DELETED
;
1564 return smbXsrv_session_local_lookup(table
, local_id
, now
, session
);
1567 struct smbXsrv_session_global_traverse_state
{
1568 int (*fn
)(struct smbXsrv_session_global0
*, void *);
1572 static int smbXsrv_session_global_traverse_fn(struct db_record
*rec
, void *data
)
1575 struct smbXsrv_session_global_traverse_state
*state
=
1576 (struct smbXsrv_session_global_traverse_state
*)data
;
1577 TDB_DATA key
= dbwrap_record_get_key(rec
);
1578 TDB_DATA val
= dbwrap_record_get_value(rec
);
1579 DATA_BLOB blob
= data_blob_const(val
.dptr
, val
.dsize
);
1580 struct smbXsrv_session_globalB global_blob
;
1581 enum ndr_err_code ndr_err
;
1582 TALLOC_CTX
*frame
= talloc_stackframe();
1584 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
1585 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_globalB
);
1586 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1587 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1588 "key '%s' ndr_pull_struct_blob - %s\n",
1589 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1590 ndr_errstr(ndr_err
)));
1594 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
1595 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1596 "key '%s' unsuported version - %d\n",
1597 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1598 (int)global_blob
.version
));
1602 global_blob
.info
.info0
->db_rec
= rec
;
1603 ret
= state
->fn(global_blob
.info
.info0
, state
->private_data
);
1609 NTSTATUS
smbXsrv_session_global_traverse(
1610 int (*fn
)(struct smbXsrv_session_global0
*, void *),
1616 struct smbXsrv_session_global_traverse_state state
= {
1618 .private_data
= private_data
,
1622 status
= smbXsrv_session_global_init();
1623 if (!NT_STATUS_IS_OK(status
)) {
1625 DEBUG(0, ("Failed to initialize session_global: %s\n",
1626 nt_errstr(status
)));
1630 status
= dbwrap_traverse_read(smbXsrv_session_global_db_ctx
,
1631 smbXsrv_session_global_traverse_fn
,