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"
41 struct smbXsrv_session_table
{
43 struct db_context
*db_ctx
;
46 uint32_t max_sessions
;
47 uint32_t num_sessions
;
50 struct db_context
*db_ctx
;
54 static struct db_context
*smbXsrv_session_global_db_ctx
= NULL
;
56 NTSTATUS
smbXsrv_session_global_init(void)
58 char *global_path
= NULL
;
59 struct db_context
*db_ctx
= NULL
;
61 if (smbXsrv_session_global_db_ctx
!= NULL
) {
66 * This contains secret information like session keys!
68 global_path
= lock_path("smbXsrv_session_global.tdb");
69 if (global_path
== NULL
) {
70 return NT_STATUS_NO_MEMORY
;
73 db_ctx
= db_open(NULL
, global_path
,
77 TDB_INCOMPATIBLE_HASH
,
78 O_RDWR
| O_CREAT
, 0600,
81 TALLOC_FREE(global_path
);
85 status
= map_nt_error_from_unix_common(errno
);
90 smbXsrv_session_global_db_ctx
= db_ctx
;
97 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
98 * has the same result as integer comparison between the uint32_t
101 * TODO: implement string based key
104 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
106 static TDB_DATA
smbXsrv_session_global_id_to_key(uint32_t id
,
111 RSIVAL(key_buf
, 0, id
);
113 key
= make_tdb_data(key_buf
, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
);
119 static NTSTATUS
smbXsrv_session_global_key_to_id(TDB_DATA key
, uint32_t *id
)
122 return NT_STATUS_INVALID_PARAMETER
;
125 if (key
.dsize
!= SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
) {
126 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
129 *id
= RIVAL(key
.dptr
, 0);
135 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
137 static TDB_DATA
smbXsrv_session_local_id_to_key(uint32_t id
,
142 RSIVAL(key_buf
, 0, id
);
144 key
= make_tdb_data(key_buf
, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
);
149 static NTSTATUS
smbXsrv_session_local_key_to_id(TDB_DATA key
, uint32_t *id
)
152 return NT_STATUS_INVALID_PARAMETER
;
155 if (key
.dsize
!= SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
) {
156 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
159 *id
= RIVAL(key
.dptr
, 0);
164 static void smbXsrv_session_close_loop(struct tevent_req
*subreq
);
166 static NTSTATUS
smbXsrv_session_table_init(struct smbXsrv_connection
*conn
,
169 uint32_t max_sessions
)
171 struct smbXsrv_client
*client
= conn
->client
;
172 struct smbXsrv_session_table
*table
;
174 struct tevent_req
*subreq
;
177 if (lowest_id
> highest_id
) {
178 return NT_STATUS_INTERNAL_ERROR
;
181 max_range
= highest_id
;
182 max_range
-= lowest_id
;
185 if (max_sessions
> max_range
) {
186 return NT_STATUS_INTERNAL_ERROR
;
189 table
= talloc_zero(client
, struct smbXsrv_session_table
);
191 return NT_STATUS_NO_MEMORY
;
194 table
->local
.db_ctx
= db_open_rbt(table
);
195 if (table
->local
.db_ctx
== NULL
) {
197 return NT_STATUS_NO_MEMORY
;
199 table
->local
.lowest_id
= lowest_id
;
200 table
->local
.highest_id
= highest_id
;
201 table
->local
.max_sessions
= max_sessions
;
203 status
= smbXsrv_session_global_init();
204 if (!NT_STATUS_IS_OK(status
)) {
209 table
->global
.db_ctx
= smbXsrv_session_global_db_ctx
;
211 dbwrap_watch_db(table
->global
.db_ctx
, client
->msg_ctx
);
213 subreq
= messaging_read_send(table
, client
->ev_ctx
, client
->msg_ctx
,
214 MSG_SMBXSRV_SESSION_CLOSE
);
215 if (subreq
== NULL
) {
217 return NT_STATUS_NO_MEMORY
;
219 tevent_req_set_callback(subreq
, smbXsrv_session_close_loop
, client
);
221 client
->session_table
= table
;
225 static void smbXsrv_session_close_shutdown_done(struct tevent_req
*subreq
);
227 static void smbXsrv_session_close_loop(struct tevent_req
*subreq
)
229 struct smbXsrv_client
*client
=
230 tevent_req_callback_data(subreq
,
231 struct smbXsrv_client
);
232 struct smbXsrv_session_table
*table
= client
->session_table
;
234 struct messaging_rec
*rec
= NULL
;
235 struct smbXsrv_session_closeB close_blob
;
236 enum ndr_err_code ndr_err
;
237 struct smbXsrv_session_close0
*close_info0
= NULL
;
238 struct smbXsrv_session
*session
= NULL
;
240 struct timeval tv
= timeval_current();
241 NTTIME now
= timeval_to_nttime(&tv
);
243 ret
= messaging_read_recv(subreq
, talloc_tos(), &rec
);
249 ndr_err
= ndr_pull_struct_blob(&rec
->buf
, rec
, &close_blob
,
250 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_closeB
);
251 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
252 status
= ndr_map_error2ntstatus(ndr_err
);
253 DEBUG(1,("smbXsrv_session_close_loop: "
254 "ndr_pull_struct_blob - %s\n",
259 DEBUG(10,("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n"));
261 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
264 if (close_blob
.version
!= SMBXSRV_VERSION_0
) {
265 DEBUG(0,("smbXsrv_session_close_loop: "
266 "ignore invalid version %u\n", close_blob
.version
));
267 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
271 close_info0
= close_blob
.info
.info0
;
272 if (close_info0
== NULL
) {
273 DEBUG(0,("smbXsrv_session_close_loop: "
274 "ignore NULL info %u\n", close_blob
.version
));
275 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
279 status
= smb2srv_session_lookup_client(client
,
280 close_info0
->old_session_wire_id
,
282 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_SESSION_DELETED
)) {
283 DEBUG(4,("smbXsrv_session_close_loop: "
284 "old_session_wire_id %llu not found\n",
285 (unsigned long long)close_info0
->old_session_wire_id
));
287 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
291 if (!NT_STATUS_IS_OK(status
) &&
292 !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) &&
293 !NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_SESSION_EXPIRED
)) {
294 DEBUG(1,("smbXsrv_session_close_loop: "
295 "old_session_wire_id %llu - %s\n",
296 (unsigned long long)close_info0
->old_session_wire_id
,
299 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
304 if (session
->global
->session_global_id
!= close_info0
->old_session_global_id
) {
305 DEBUG(1,("smbXsrv_session_close_loop: "
306 "old_session_wire_id %llu - global %u != %u\n",
307 (unsigned long long)close_info0
->old_session_wire_id
,
308 session
->global
->session_global_id
,
309 close_info0
->old_session_global_id
));
311 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
316 if (session
->global
->creation_time
!= close_info0
->old_creation_time
) {
317 DEBUG(1,("smbXsrv_session_close_loop: "
318 "old_session_wire_id %llu - "
319 "creation %s (%llu) != %s (%llu)\n",
320 (unsigned long long)close_info0
->old_session_wire_id
,
321 nt_time_string(rec
, session
->global
->creation_time
),
322 (unsigned long long)session
->global
->creation_time
,
323 nt_time_string(rec
, close_info0
->old_creation_time
),
324 (unsigned long long)close_info0
->old_creation_time
));
326 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
331 subreq
= smb2srv_session_shutdown_send(session
, client
->ev_ctx
,
333 if (subreq
== NULL
) {
334 status
= NT_STATUS_NO_MEMORY
;
335 DEBUG(0, ("smbXsrv_session_close_loop: "
336 "smb2srv_session_shutdown_send(%llu) failed: %s\n",
337 (unsigned long long)session
->global
->session_wire_id
,
340 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
344 tevent_req_set_callback(subreq
,
345 smbXsrv_session_close_shutdown_done
,
351 subreq
= messaging_read_send(table
, client
->ev_ctx
, client
->msg_ctx
,
352 MSG_SMBXSRV_SESSION_CLOSE
);
353 if (subreq
== NULL
) {
355 r
= "messaging_read_send(MSG_SMBXSRV_SESSION_CLOSE) failed";
356 exit_server_cleanly(r
);
359 tevent_req_set_callback(subreq
, smbXsrv_session_close_loop
, client
);
362 static void smbXsrv_session_close_shutdown_done(struct tevent_req
*subreq
)
364 struct smbXsrv_session
*session
=
365 tevent_req_callback_data(subreq
,
366 struct smbXsrv_session
);
369 status
= smb2srv_session_shutdown_recv(subreq
);
371 if (!NT_STATUS_IS_OK(status
)) {
372 DEBUG(0, ("smbXsrv_session_close_loop: "
373 "smb2srv_session_shutdown_recv(%llu) failed: %s\n",
374 (unsigned long long)session
->global
->session_wire_id
,
378 status
= smbXsrv_session_logoff(session
);
379 if (!NT_STATUS_IS_OK(status
)) {
380 DEBUG(0, ("smbXsrv_session_close_loop: "
381 "smbXsrv_session_logoff(%llu) failed: %s\n",
382 (unsigned long long)session
->global
->session_wire_id
,
386 TALLOC_FREE(session
);
389 struct smb1srv_session_local_allocate_state
{
390 const uint32_t lowest_id
;
391 const uint32_t highest_id
;
397 static int smb1srv_session_local_allocate_traverse(struct db_record
*rec
,
400 struct smb1srv_session_local_allocate_state
*state
=
401 (struct smb1srv_session_local_allocate_state
*)private_data
;
402 TDB_DATA key
= dbwrap_record_get_key(rec
);
406 status
= smbXsrv_session_local_key_to_id(key
, &id
);
407 if (!NT_STATUS_IS_OK(status
)) {
408 state
->status
= status
;
412 if (id
<= state
->last_id
) {
413 state
->status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
418 if (id
> state
->useable_id
) {
419 state
->status
= NT_STATUS_OK
;
423 if (state
->useable_id
== state
->highest_id
) {
424 state
->status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
428 state
->useable_id
+=1;
432 static NTSTATUS
smb1srv_session_local_allocate_id(struct db_context
*db
,
436 struct db_record
**_rec
,
439 struct smb1srv_session_local_allocate_state state
= {
440 .lowest_id
= lowest_id
,
441 .highest_id
= highest_id
,
443 .useable_id
= lowest_id
,
444 .status
= NT_STATUS_INTERNAL_ERROR
,
454 if (lowest_id
> highest_id
) {
455 return NT_STATUS_INSUFFICIENT_RESOURCES
;
459 * first we try randomly
461 range
= (highest_id
- lowest_id
) + 1;
463 for (i
= 0; i
< (range
/ 2); i
++) {
465 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
468 struct db_record
*rec
= NULL
;
470 id
= generate_random() % range
;
473 if (id
< lowest_id
) {
476 if (id
> highest_id
) {
480 key
= smbXsrv_session_local_id_to_key(id
, key_buf
);
482 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
484 return NT_STATUS_INSUFFICIENT_RESOURCES
;
487 val
= dbwrap_record_get_value(rec
);
488 if (val
.dsize
!= 0) {
499 * if the range is almost full,
500 * we traverse the whole table
501 * (this relies on sorted behavior of dbwrap_rbt)
503 status
= dbwrap_traverse_read(db
, smb1srv_session_local_allocate_traverse
,
505 if (NT_STATUS_IS_OK(status
)) {
506 if (NT_STATUS_IS_OK(state
.status
)) {
507 return NT_STATUS_INTERNAL_ERROR
;
510 if (!NT_STATUS_EQUAL(state
.status
, NT_STATUS_INTERNAL_ERROR
)) {
514 if (state
.useable_id
<= state
.highest_id
) {
515 state
.status
= NT_STATUS_OK
;
517 return NT_STATUS_INSUFFICIENT_RESOURCES
;
519 } else if (!NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_DB_CORRUPTION
)) {
521 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
523 * If we get anything else it is an error, because it
524 * means we did not manage to find a free slot in
527 return NT_STATUS_INSUFFICIENT_RESOURCES
;
530 if (NT_STATUS_IS_OK(state
.status
)) {
532 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
535 struct db_record
*rec
= NULL
;
537 id
= state
.useable_id
;
539 key
= smbXsrv_session_local_id_to_key(id
, key_buf
);
541 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
543 return NT_STATUS_INSUFFICIENT_RESOURCES
;
546 val
= dbwrap_record_get_value(rec
);
547 if (val
.dsize
!= 0) {
549 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
560 struct smbXsrv_session_local_fetch_state
{
561 struct smbXsrv_session
*session
;
565 static void smbXsrv_session_local_fetch_parser(TDB_DATA key
, TDB_DATA data
,
568 struct smbXsrv_session_local_fetch_state
*state
=
569 (struct smbXsrv_session_local_fetch_state
*)private_data
;
572 if (data
.dsize
!= sizeof(ptr
)) {
573 state
->status
= NT_STATUS_INTERNAL_DB_ERROR
;
577 memcpy(&ptr
, data
.dptr
, data
.dsize
);
578 state
->session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
579 state
->status
= NT_STATUS_OK
;
582 static NTSTATUS
smbXsrv_session_local_lookup(struct smbXsrv_session_table
*table
,
584 struct smbXsrv_connection
*conn
,
585 uint32_t session_local_id
,
587 struct smbXsrv_session
**_session
)
589 struct smbXsrv_session_local_fetch_state state
= {
591 .status
= NT_STATUS_INTERNAL_ERROR
,
593 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
599 if (session_local_id
== 0) {
600 return NT_STATUS_USER_SESSION_DELETED
;
604 /* this might happen before the end of negprot */
605 return NT_STATUS_USER_SESSION_DELETED
;
608 if (table
->local
.db_ctx
== NULL
) {
609 return NT_STATUS_INTERNAL_ERROR
;
612 key
= smbXsrv_session_local_id_to_key(session_local_id
, key_buf
);
614 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
615 smbXsrv_session_local_fetch_parser
,
617 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
618 return NT_STATUS_USER_SESSION_DELETED
;
619 } else if (!NT_STATUS_IS_OK(status
)) {
622 if (!NT_STATUS_IS_OK(state
.status
)) {
626 if (NT_STATUS_EQUAL(state
.session
->status
, NT_STATUS_USER_SESSION_DELETED
)) {
627 return NT_STATUS_USER_SESSION_DELETED
;
631 * If a connection is specified check if the session is
632 * valid on the channel.
635 struct smbXsrv_channel_global0
*c
= NULL
;
637 status
= smbXsrv_session_find_channel(state
.session
, conn
, &c
);
638 if (!NT_STATUS_IS_OK(status
)) {
643 state
.session
->idle_time
= now
;
645 if (!NT_STATUS_IS_OK(state
.session
->status
)) {
646 *_session
= state
.session
;
647 return state
.session
->status
;
650 if (now
> state
.session
->global
->expiration_time
) {
651 state
.session
->status
= NT_STATUS_NETWORK_SESSION_EXPIRED
;
654 *_session
= state
.session
;
655 return state
.session
->status
;
658 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0
*global
)
663 static void smbXsrv_session_global_verify_record(struct db_record
*db_rec
,
667 struct smbXsrv_session_global0
**_g
);
669 static NTSTATUS
smbXsrv_session_global_allocate(struct db_context
*db
,
671 struct smbXsrv_session_global0
**_global
)
674 struct smbXsrv_session_global0
*global
= NULL
;
675 uint32_t last_free
= 0;
676 const uint32_t min_tries
= 3;
680 global
= talloc_zero(mem_ctx
, struct smbXsrv_session_global0
);
681 if (global
== NULL
) {
682 return NT_STATUS_NO_MEMORY
;
684 talloc_set_destructor(global
, smbXsrv_session_global_destructor
);
687 * Here we just randomly try the whole 32-bit space
689 * We use just 32-bit, because we want to reuse the
692 for (i
= 0; i
< UINT32_MAX
; i
++) {
693 bool is_free
= false;
694 bool was_free
= false;
696 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
699 if (i
>= min_tries
&& last_free
!= 0) {
702 id
= generate_random();
707 if (id
== UINT32_MAX
) {
711 key
= smbXsrv_session_global_id_to_key(id
, key_buf
);
713 global
->db_rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
714 if (global
->db_rec
== NULL
) {
716 return NT_STATUS_INSUFFICIENT_RESOURCES
;
719 smbXsrv_session_global_verify_record(global
->db_rec
,
725 TALLOC_FREE(global
->db_rec
);
729 if (!was_free
&& i
< min_tries
) {
731 * The session_id is free now,
732 * but was not free before.
734 * This happens if a smbd crashed
735 * and did not cleanup the record.
737 * If this is one of our first tries,
738 * then we try to find a real free one.
740 if (last_free
== 0) {
743 TALLOC_FREE(global
->db_rec
);
747 global
->session_global_id
= id
;
753 /* should not be reached */
755 return NT_STATUS_INTERNAL_ERROR
;
758 static void smbXsrv_session_global_verify_record(struct db_record
*db_rec
,
762 struct smbXsrv_session_global0
**_g
)
767 struct smbXsrv_session_globalB global_blob
;
768 enum ndr_err_code ndr_err
;
769 struct smbXsrv_session_global0
*global
= NULL
;
771 TALLOC_CTX
*frame
= talloc_stackframe();
782 key
= dbwrap_record_get_key(db_rec
);
784 val
= dbwrap_record_get_value(db_rec
);
785 if (val
.dsize
== 0) {
794 blob
= data_blob_const(val
.dptr
, val
.dsize
);
796 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
797 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_globalB
);
798 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
799 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
800 DEBUG(1,("smbXsrv_session_global_verify_record: "
801 "key '%s' ndr_pull_struct_blob - %s\n",
802 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
808 DEBUG(10,("smbXsrv_session_global_verify_record\n"));
810 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
813 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
814 DEBUG(0,("smbXsrv_session_global_verify_record: "
815 "key '%s' use unsupported version %u\n",
816 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
817 global_blob
.version
));
818 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
823 global
= global_blob
.info
.info0
;
825 exists
= serverid_exists(&global
->channels
[0].server_id
);
827 struct server_id_buf idbuf
;
828 DEBUG(2,("smbXsrv_session_global_verify_record: "
829 "key '%s' server_id %s does not exist.\n",
830 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
831 server_id_str_buf(global
->channels
[0].server_id
,
834 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
837 dbwrap_record_delete(db_rec
);
843 *_g
= talloc_move(mem_ctx
, &global
);
848 static NTSTATUS
smbXsrv_session_global_store(struct smbXsrv_session_global0
*global
)
850 struct smbXsrv_session_globalB global_blob
;
851 DATA_BLOB blob
= data_blob_null
;
855 enum ndr_err_code ndr_err
;
858 * TODO: if we use other versions than '0'
859 * we would add glue code here, that would be able to
860 * store the information in the old format.
863 if (global
->db_rec
== NULL
) {
864 return NT_STATUS_INTERNAL_ERROR
;
867 key
= dbwrap_record_get_key(global
->db_rec
);
868 val
= dbwrap_record_get_value(global
->db_rec
);
870 ZERO_STRUCT(global_blob
);
871 global_blob
.version
= smbXsrv_version_global_current();
872 if (val
.dsize
>= 8) {
873 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
875 global_blob
.seqnum
+= 1;
876 global_blob
.info
.info0
= global
;
878 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
879 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_session_globalB
);
880 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
881 status
= ndr_map_error2ntstatus(ndr_err
);
882 DEBUG(1,("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
883 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
885 TALLOC_FREE(global
->db_rec
);
889 val
= make_tdb_data(blob
.data
, blob
.length
);
890 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
891 if (!NT_STATUS_IS_OK(status
)) {
892 DEBUG(1,("smbXsrv_session_global_store: key '%s' store - %s\n",
893 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
895 TALLOC_FREE(global
->db_rec
);
900 DEBUG(10,("smbXsrv_session_global_store: key '%s' stored\n",
901 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
)));
902 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
905 TALLOC_FREE(global
->db_rec
);
910 struct smb2srv_session_close_previous_state
{
911 struct tevent_context
*ev
;
912 struct smbXsrv_connection
*connection
;
913 struct dom_sid
*current_sid
;
914 uint64_t current_session_id
;
915 struct db_record
*db_rec
;
918 static void smb2srv_session_close_previous_check(struct tevent_req
*req
);
919 static void smb2srv_session_close_previous_modified(struct tevent_req
*subreq
);
921 struct tevent_req
*smb2srv_session_close_previous_send(TALLOC_CTX
*mem_ctx
,
922 struct tevent_context
*ev
,
923 struct smbXsrv_connection
*conn
,
924 struct auth_session_info
*session_info
,
925 uint64_t previous_session_id
,
926 uint64_t current_session_id
)
928 struct tevent_req
*req
;
929 struct smb2srv_session_close_previous_state
*state
;
930 uint32_t global_id
= previous_session_id
& UINT32_MAX
;
931 uint64_t global_zeros
= previous_session_id
& 0xFFFFFFFF00000000LLU
;
932 struct smbXsrv_session_table
*table
= conn
->client
->session_table
;
933 struct security_token
*current_token
= NULL
;
934 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
937 req
= tevent_req_create(mem_ctx
, &state
,
938 struct smb2srv_session_close_previous_state
);
943 state
->connection
= conn
;
944 state
->current_session_id
= current_session_id
;
946 if (global_zeros
!= 0) {
947 tevent_req_done(req
);
948 return tevent_req_post(req
, ev
);
951 if (session_info
== NULL
) {
952 tevent_req_done(req
);
953 return tevent_req_post(req
, ev
);
955 current_token
= session_info
->security_token
;
957 if (current_token
->num_sids
> PRIMARY_USER_SID_INDEX
) {
958 state
->current_sid
= ¤t_token
->sids
[PRIMARY_USER_SID_INDEX
];
961 if (state
->current_sid
== NULL
) {
962 tevent_req_done(req
);
963 return tevent_req_post(req
, ev
);
966 if (!security_token_has_nt_authenticated_users(current_token
)) {
968 tevent_req_done(req
);
969 return tevent_req_post(req
, ev
);
972 key
= smbXsrv_session_global_id_to_key(global_id
, key_buf
);
974 state
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
976 if (state
->db_rec
== NULL
) {
977 tevent_req_nterror(req
, NT_STATUS_UNSUCCESSFUL
);
978 return tevent_req_post(req
, ev
);
981 smb2srv_session_close_previous_check(req
);
982 if (!tevent_req_is_in_progress(req
)) {
983 return tevent_req_post(req
, ev
);
989 static void smb2srv_session_close_previous_check(struct tevent_req
*req
)
991 struct smb2srv_session_close_previous_state
*state
=
993 struct smb2srv_session_close_previous_state
);
994 struct smbXsrv_connection
*conn
= state
->connection
;
996 struct security_token
*previous_token
= NULL
;
997 struct smbXsrv_session_global0
*global
= NULL
;
998 enum ndr_err_code ndr_err
;
999 struct smbXsrv_session_close0 close_info0
;
1000 struct smbXsrv_session_closeB close_blob
;
1001 struct tevent_req
*subreq
= NULL
;
1003 bool is_free
= false;
1005 smbXsrv_session_global_verify_record(state
->db_rec
,
1012 TALLOC_FREE(state
->db_rec
);
1013 tevent_req_done(req
);
1017 if (global
->auth_session_info
== NULL
) {
1018 TALLOC_FREE(state
->db_rec
);
1019 tevent_req_done(req
);
1023 previous_token
= global
->auth_session_info
->security_token
;
1025 if (!security_token_is_sid(previous_token
, state
->current_sid
)) {
1026 TALLOC_FREE(state
->db_rec
);
1027 tevent_req_done(req
);
1031 subreq
= dbwrap_record_watch_send(state
, state
->ev
,
1032 state
->db_rec
, conn
->msg_ctx
);
1033 if (tevent_req_nomem(subreq
, req
)) {
1034 TALLOC_FREE(state
->db_rec
);
1037 tevent_req_set_callback(subreq
,
1038 smb2srv_session_close_previous_modified
,
1041 close_info0
.old_session_global_id
= global
->session_global_id
;
1042 close_info0
.old_session_wire_id
= global
->session_wire_id
;
1043 close_info0
.old_creation_time
= global
->creation_time
;
1044 close_info0
.new_session_wire_id
= state
->current_session_id
;
1046 ZERO_STRUCT(close_blob
);
1047 close_blob
.version
= smbXsrv_version_global_current();
1048 close_blob
.info
.info0
= &close_info0
;
1050 ndr_err
= ndr_push_struct_blob(&blob
, state
, &close_blob
,
1051 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_session_closeB
);
1052 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1053 TALLOC_FREE(state
->db_rec
);
1054 status
= ndr_map_error2ntstatus(ndr_err
);
1055 DEBUG(1,("smb2srv_session_close_previous_check: "
1056 "old_session[%llu] new_session[%llu] ndr_push - %s\n",
1057 (unsigned long long)close_info0
.old_session_wire_id
,
1058 (unsigned long long)close_info0
.new_session_wire_id
,
1059 nt_errstr(status
)));
1060 tevent_req_nterror(req
, status
);
1064 status
= messaging_send(conn
->msg_ctx
,
1065 global
->channels
[0].server_id
,
1066 MSG_SMBXSRV_SESSION_CLOSE
, &blob
);
1067 TALLOC_FREE(state
->db_rec
);
1068 if (tevent_req_nterror(req
, status
)) {
1072 TALLOC_FREE(global
);
1076 static void smb2srv_session_close_previous_modified(struct tevent_req
*subreq
)
1078 struct tevent_req
*req
=
1079 tevent_req_callback_data(subreq
,
1081 struct smb2srv_session_close_previous_state
*state
=
1082 tevent_req_data(req
,
1083 struct smb2srv_session_close_previous_state
);
1086 status
= dbwrap_record_watch_recv(subreq
, state
, &state
->db_rec
);
1087 TALLOC_FREE(subreq
);
1088 if (tevent_req_nterror(req
, status
)) {
1092 smb2srv_session_close_previous_check(req
);
1095 NTSTATUS
smb2srv_session_close_previous_recv(struct tevent_req
*req
)
1099 if (tevent_req_is_nterror(req
, &status
)) {
1100 tevent_req_received(req
);
1104 tevent_req_received(req
);
1105 return NT_STATUS_OK
;
1108 static NTSTATUS
smbXsrv_session_clear_and_logoff(struct smbXsrv_session
*session
)
1111 struct smbXsrv_connection
*xconn
= NULL
;
1113 if (session
->client
!= NULL
) {
1114 xconn
= session
->client
->connections
;
1117 for (; xconn
!= NULL
; xconn
= xconn
->next
) {
1118 struct smbd_smb2_request
*preq
;
1120 for (preq
= xconn
->smb2
.requests
; preq
!= NULL
; preq
= preq
->next
) {
1121 if (preq
->session
!= session
) {
1125 preq
->session
= NULL
;
1127 * If we no longer have a session we can't
1128 * sign or encrypt replies.
1130 preq
->do_signing
= false;
1131 preq
->do_encryption
= false;
1132 preq
->preauth
= NULL
;
1136 status
= smbXsrv_session_logoff(session
);
1140 static int smbXsrv_session_destructor(struct smbXsrv_session
*session
)
1144 status
= smbXsrv_session_clear_and_logoff(session
);
1145 if (!NT_STATUS_IS_OK(status
)) {
1146 DEBUG(0, ("smbXsrv_session_destructor: "
1147 "smbXsrv_session_logoff() failed: %s\n",
1148 nt_errstr(status
)));
1151 TALLOC_FREE(session
->global
);
1156 NTSTATUS
smbXsrv_session_create(struct smbXsrv_connection
*conn
,
1158 struct smbXsrv_session
**_session
)
1160 struct smbXsrv_session_table
*table
= conn
->client
->session_table
;
1161 struct db_record
*local_rec
= NULL
;
1162 struct smbXsrv_session
*session
= NULL
;
1165 struct smbXsrv_session_global0
*global
= NULL
;
1166 struct smbXsrv_channel_global0
*channel
= NULL
;
1169 if (table
->local
.num_sessions
>= table
->local
.max_sessions
) {
1170 return NT_STATUS_INSUFFICIENT_RESOURCES
;
1173 session
= talloc_zero(table
, struct smbXsrv_session
);
1174 if (session
== NULL
) {
1175 return NT_STATUS_NO_MEMORY
;
1177 session
->table
= table
;
1178 session
->idle_time
= now
;
1179 session
->status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1180 session
->client
= conn
->client
;
1182 status
= smbXsrv_session_global_allocate(table
->global
.db_ctx
,
1185 if (!NT_STATUS_IS_OK(status
)) {
1186 TALLOC_FREE(session
);
1189 session
->global
= global
;
1191 if (conn
->protocol
>= PROTOCOL_SMB2_02
) {
1192 uint64_t id
= global
->session_global_id
;
1193 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
1196 global
->connection_dialect
= conn
->smb2
.server
.dialect
;
1198 global
->session_wire_id
= id
;
1200 status
= smb2srv_tcon_table_init(session
);
1201 if (!NT_STATUS_IS_OK(status
)) {
1202 TALLOC_FREE(session
);
1206 session
->local_id
= global
->session_global_id
;
1208 key
= smbXsrv_session_local_id_to_key(session
->local_id
, key_buf
);
1210 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
1212 if (local_rec
== NULL
) {
1213 TALLOC_FREE(session
);
1214 return NT_STATUS_NO_MEMORY
;
1217 val
= dbwrap_record_get_value(local_rec
);
1218 if (val
.dsize
!= 0) {
1219 TALLOC_FREE(session
);
1220 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1224 status
= smb1srv_session_local_allocate_id(table
->local
.db_ctx
,
1225 table
->local
.lowest_id
,
1226 table
->local
.highest_id
,
1229 &session
->local_id
);
1230 if (!NT_STATUS_IS_OK(status
)) {
1231 TALLOC_FREE(session
);
1235 global
->session_wire_id
= session
->local_id
;
1238 global
->creation_time
= now
;
1239 global
->expiration_time
= GENSEC_EXPIRE_TIME_INFINITY
;
1241 status
= smbXsrv_session_add_channel(session
, conn
, &channel
);
1242 if (!NT_STATUS_IS_OK(status
)) {
1243 TALLOC_FREE(session
);
1248 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
1249 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
1250 TALLOC_FREE(local_rec
);
1251 if (!NT_STATUS_IS_OK(status
)) {
1252 TALLOC_FREE(session
);
1255 table
->local
.num_sessions
+= 1;
1257 talloc_set_destructor(session
, smbXsrv_session_destructor
);
1259 status
= smbXsrv_session_global_store(global
);
1260 if (!NT_STATUS_IS_OK(status
)) {
1261 DEBUG(0,("smbXsrv_session_create: "
1262 "global_id (0x%08x) store failed - %s\n",
1263 session
->global
->session_global_id
,
1264 nt_errstr(status
)));
1265 TALLOC_FREE(session
);
1270 struct smbXsrv_sessionB session_blob
;
1272 ZERO_STRUCT(session_blob
);
1273 session_blob
.version
= SMBXSRV_VERSION_0
;
1274 session_blob
.info
.info0
= session
;
1276 DEBUG(10,("smbXsrv_session_create: global_id (0x%08x) stored\n",
1277 session
->global
->session_global_id
));
1278 NDR_PRINT_DEBUG(smbXsrv_sessionB
, &session_blob
);
1281 *_session
= session
;
1282 return NT_STATUS_OK
;
1285 NTSTATUS
smbXsrv_session_add_channel(struct smbXsrv_session
*session
,
1286 struct smbXsrv_connection
*conn
,
1287 struct smbXsrv_channel_global0
**_c
)
1289 struct smbXsrv_session_global0
*global
= session
->global
;
1290 struct smbXsrv_channel_global0
*c
= NULL
;
1292 if (global
->num_channels
> 31) {
1294 * Windows 2012 and 2012R2 allow up to 32 channels
1296 return NT_STATUS_INSUFFICIENT_RESOURCES
;
1299 c
= talloc_realloc(global
,
1301 struct smbXsrv_channel_global0
,
1302 global
->num_channels
+ 1);
1304 return NT_STATUS_NO_MEMORY
;
1306 global
->channels
= c
;
1308 c
= &global
->channels
[global
->num_channels
];
1311 c
->server_id
= messaging_server_id(conn
->msg_ctx
);
1312 c
->local_address
= tsocket_address_string(conn
->local_address
,
1314 if (c
->local_address
== NULL
) {
1315 return NT_STATUS_NO_MEMORY
;
1317 c
->remote_address
= tsocket_address_string(conn
->remote_address
,
1319 if (c
->remote_address
== NULL
) {
1320 return NT_STATUS_NO_MEMORY
;
1322 c
->remote_name
= talloc_strdup(global
->channels
,
1323 conn
->remote_hostname
);
1324 if (c
->remote_name
== NULL
) {
1325 return NT_STATUS_NO_MEMORY
;
1327 c
->connection
= conn
;
1329 global
->num_channels
+= 1;
1332 return NT_STATUS_OK
;
1335 NTSTATUS
smbXsrv_session_update(struct smbXsrv_session
*session
)
1337 struct smbXsrv_session_table
*table
= session
->table
;
1339 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
1342 if (session
->global
->db_rec
!= NULL
) {
1343 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1344 "Called with db_rec != NULL'\n",
1345 session
->global
->session_global_id
));
1346 return NT_STATUS_INTERNAL_ERROR
;
1349 key
= smbXsrv_session_global_id_to_key(
1350 session
->global
->session_global_id
,
1353 session
->global
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
1354 session
->global
, key
);
1355 if (session
->global
->db_rec
== NULL
) {
1356 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1357 "Failed to lock global key '%s'\n",
1358 session
->global
->session_global_id
,
1359 hex_encode_talloc(talloc_tos(), key
.dptr
,
1361 return NT_STATUS_INTERNAL_DB_ERROR
;
1364 status
= smbXsrv_session_global_store(session
->global
);
1365 if (!NT_STATUS_IS_OK(status
)) {
1366 DEBUG(0,("smbXsrv_session_update: "
1367 "global_id (0x%08x) store failed - %s\n",
1368 session
->global
->session_global_id
,
1369 nt_errstr(status
)));
1374 struct smbXsrv_sessionB session_blob
;
1376 ZERO_STRUCT(session_blob
);
1377 session_blob
.version
= SMBXSRV_VERSION_0
;
1378 session_blob
.info
.info0
= session
;
1380 DEBUG(10,("smbXsrv_session_update: global_id (0x%08x) stored\n",
1381 session
->global
->session_global_id
));
1382 NDR_PRINT_DEBUG(smbXsrv_sessionB
, &session_blob
);
1385 return NT_STATUS_OK
;
1388 NTSTATUS
smbXsrv_session_find_channel(const struct smbXsrv_session
*session
,
1389 const struct smbXsrv_connection
*conn
,
1390 struct smbXsrv_channel_global0
**_c
)
1394 for (i
=0; i
< session
->global
->num_channels
; i
++) {
1395 struct smbXsrv_channel_global0
*c
= &session
->global
->channels
[i
];
1397 if (c
->connection
== conn
) {
1399 return NT_STATUS_OK
;
1403 return NT_STATUS_USER_SESSION_DELETED
;
1406 NTSTATUS
smbXsrv_session_find_auth(const struct smbXsrv_session
*session
,
1407 const struct smbXsrv_connection
*conn
,
1409 struct smbXsrv_session_auth0
**_a
)
1411 struct smbXsrv_session_auth0
*a
;
1413 for (a
= session
->pending_auth
; a
!= NULL
; a
= a
->next
) {
1414 if (a
->connection
== conn
) {
1419 return NT_STATUS_OK
;
1423 return NT_STATUS_USER_SESSION_DELETED
;
1426 static int smbXsrv_session_auth0_destructor(struct smbXsrv_session_auth0
*a
)
1428 if (a
->session
== NULL
) {
1432 DLIST_REMOVE(a
->session
->pending_auth
, a
);
1437 NTSTATUS
smbXsrv_session_create_auth(struct smbXsrv_session
*session
,
1438 struct smbXsrv_connection
*conn
,
1441 uint8_t in_security_mode
,
1442 struct smbXsrv_session_auth0
**_a
)
1444 struct smbXsrv_session_auth0
*a
;
1447 status
= smbXsrv_session_find_auth(session
, conn
, 0, &a
);
1448 if (NT_STATUS_IS_OK(status
)) {
1449 return NT_STATUS_INTERNAL_ERROR
;
1452 a
= talloc_zero(session
, struct smbXsrv_session_auth0
);
1454 return NT_STATUS_NO_MEMORY
;
1456 a
->session
= session
;
1457 a
->connection
= conn
;
1458 a
->in_flags
= in_flags
;
1459 a
->in_security_mode
= in_security_mode
;
1460 a
->creation_time
= now
;
1463 if (conn
->protocol
>= PROTOCOL_SMB3_10
) {
1464 a
->preauth
= talloc(a
, struct smbXsrv_preauth
);
1465 if (a
->preauth
== NULL
) {
1466 TALLOC_FREE(session
);
1467 return NT_STATUS_NO_MEMORY
;
1469 *a
->preauth
= conn
->smb2
.preauth
;
1472 talloc_set_destructor(a
, smbXsrv_session_auth0_destructor
);
1473 DLIST_ADD_END(session
->pending_auth
, a
, NULL
);
1476 return NT_STATUS_OK
;
1479 struct smb2srv_session_shutdown_state
{
1480 struct tevent_queue
*wait_queue
;
1483 static void smb2srv_session_shutdown_wait_done(struct tevent_req
*subreq
);
1485 struct tevent_req
*smb2srv_session_shutdown_send(TALLOC_CTX
*mem_ctx
,
1486 struct tevent_context
*ev
,
1487 struct smbXsrv_session
*session
,
1488 struct smbd_smb2_request
*current_req
)
1490 struct tevent_req
*req
;
1491 struct smb2srv_session_shutdown_state
*state
;
1492 struct tevent_req
*subreq
;
1493 struct smbXsrv_connection
*xconn
= NULL
;
1497 * Make sure that no new request will be able to use this session.
1499 session
->status
= NT_STATUS_USER_SESSION_DELETED
;
1501 req
= tevent_req_create(mem_ctx
, &state
,
1502 struct smb2srv_session_shutdown_state
);
1507 state
->wait_queue
= tevent_queue_create(state
, "smb2srv_session_shutdown_queue");
1508 if (tevent_req_nomem(state
->wait_queue
, req
)) {
1509 return tevent_req_post(req
, ev
);
1512 for (xconn
= session
->client
->connections
; xconn
!= NULL
; xconn
= xconn
->next
) {
1513 struct smbd_smb2_request
*preq
;
1515 for (preq
= xconn
->smb2
.requests
; preq
!= NULL
; preq
= preq
->next
) {
1516 if (preq
== current_req
) {
1517 /* Can't cancel current request. */
1520 if (preq
->session
!= session
) {
1521 /* Request on different session. */
1525 if (!NT_STATUS_IS_OK(xconn
->transport
.status
)) {
1526 preq
->session
= NULL
;
1528 * If we no longer have a session we can't
1529 * sign or encrypt replies.
1531 preq
->do_signing
= false;
1532 preq
->do_encryption
= false;
1533 preq
->preauth
= NULL
;
1535 if (preq
->subreq
!= NULL
) {
1536 tevent_req_cancel(preq
->subreq
);
1542 * Never cancel anything in a compound
1543 * request. Way too hard to deal with
1546 if (!preq
->compound_related
&& preq
->subreq
!= NULL
) {
1547 tevent_req_cancel(preq
->subreq
);
1551 * Now wait until the request is finished.
1553 * We don't set a callback, as we just want to block the
1554 * wait queue and the talloc_free() of the request will
1555 * remove the item from the wait queue.
1557 subreq
= tevent_queue_wait_send(preq
, ev
, state
->wait_queue
);
1558 if (tevent_req_nomem(subreq
, req
)) {
1559 return tevent_req_post(req
, ev
);
1564 len
= tevent_queue_length(state
->wait_queue
);
1566 tevent_req_done(req
);
1567 return tevent_req_post(req
, ev
);
1571 * Now we add our own waiter to the end of the queue,
1572 * this way we get notified when all pending requests are finished
1573 * and send to the socket.
1575 subreq
= tevent_queue_wait_send(state
, ev
, state
->wait_queue
);
1576 if (tevent_req_nomem(subreq
, req
)) {
1577 return tevent_req_post(req
, ev
);
1579 tevent_req_set_callback(subreq
, smb2srv_session_shutdown_wait_done
, req
);
1584 static void smb2srv_session_shutdown_wait_done(struct tevent_req
*subreq
)
1586 struct tevent_req
*req
=
1587 tevent_req_callback_data(subreq
,
1590 tevent_queue_wait_recv(subreq
);
1591 TALLOC_FREE(subreq
);
1593 tevent_req_done(req
);
1596 NTSTATUS
smb2srv_session_shutdown_recv(struct tevent_req
*req
)
1598 return tevent_req_simple_recv_ntstatus(req
);
1601 NTSTATUS
smbXsrv_session_logoff(struct smbXsrv_session
*session
)
1603 struct smbXsrv_session_table
*table
;
1604 struct db_record
*local_rec
= NULL
;
1605 struct db_record
*global_rec
= NULL
;
1606 struct smbd_server_connection
*sconn
= NULL
;
1608 NTSTATUS error
= NT_STATUS_OK
;
1610 if (session
->table
== NULL
) {
1611 return NT_STATUS_OK
;
1614 table
= session
->table
;
1615 session
->table
= NULL
;
1617 sconn
= session
->client
->sconn
;
1618 session
->client
= NULL
;
1619 session
->status
= NT_STATUS_USER_SESSION_DELETED
;
1621 global_rec
= session
->global
->db_rec
;
1622 session
->global
->db_rec
= NULL
;
1623 if (global_rec
== NULL
) {
1624 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
1627 key
= smbXsrv_session_global_id_to_key(
1628 session
->global
->session_global_id
,
1631 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
1632 session
->global
, key
);
1633 if (global_rec
== NULL
) {
1634 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1635 "Failed to lock global key '%s'\n",
1636 session
->global
->session_global_id
,
1637 hex_encode_talloc(global_rec
, key
.dptr
,
1639 error
= NT_STATUS_INTERNAL_ERROR
;
1643 if (global_rec
!= NULL
) {
1644 status
= dbwrap_record_delete(global_rec
);
1645 if (!NT_STATUS_IS_OK(status
)) {
1646 TDB_DATA key
= dbwrap_record_get_key(global_rec
);
1648 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1649 "failed to delete global key '%s': %s\n",
1650 session
->global
->session_global_id
,
1651 hex_encode_talloc(global_rec
, key
.dptr
,
1653 nt_errstr(status
)));
1657 TALLOC_FREE(global_rec
);
1659 local_rec
= session
->db_rec
;
1660 if (local_rec
== NULL
) {
1661 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
1664 key
= smbXsrv_session_local_id_to_key(session
->local_id
,
1667 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
1669 if (local_rec
== NULL
) {
1670 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1671 "Failed to lock local key '%s'\n",
1672 session
->global
->session_global_id
,
1673 hex_encode_talloc(local_rec
, key
.dptr
,
1675 error
= NT_STATUS_INTERNAL_ERROR
;
1679 if (local_rec
!= NULL
) {
1680 status
= dbwrap_record_delete(local_rec
);
1681 if (!NT_STATUS_IS_OK(status
)) {
1682 TDB_DATA key
= dbwrap_record_get_key(local_rec
);
1684 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1685 "failed to delete local key '%s': %s\n",
1686 session
->global
->session_global_id
,
1687 hex_encode_talloc(local_rec
, key
.dptr
,
1689 nt_errstr(status
)));
1692 table
->local
.num_sessions
-= 1;
1694 if (session
->db_rec
== NULL
) {
1695 TALLOC_FREE(local_rec
);
1697 session
->db_rec
= NULL
;
1699 if (session
->compat
) {
1700 file_close_user(sconn
, session
->compat
->vuid
);
1703 if (session
->tcon_table
!= NULL
) {
1705 * Note: We only have a tcon_table for SMB2.
1707 status
= smb2srv_tcon_disconnect_all(session
);
1708 if (!NT_STATUS_IS_OK(status
)) {
1709 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1710 "smb2srv_tcon_disconnect_all() failed: %s\n",
1711 session
->global
->session_global_id
,
1712 nt_errstr(status
)));
1717 if (session
->compat
) {
1718 invalidate_vuid(sconn
, session
->compat
->vuid
);
1719 session
->compat
= NULL
;
1725 struct smbXsrv_session_logoff_all_state
{
1726 NTSTATUS first_status
;
1730 static int smbXsrv_session_logoff_all_callback(struct db_record
*local_rec
,
1731 void *private_data
);
1733 NTSTATUS
smbXsrv_session_logoff_all(struct smbXsrv_connection
*conn
)
1735 struct smbXsrv_session_table
*table
= conn
->client
->session_table
;
1736 struct smbXsrv_session_logoff_all_state state
;
1740 if (table
== NULL
) {
1741 DEBUG(10, ("smbXsrv_session_logoff_all: "
1742 "empty session_table, nothing to do.\n"));
1743 return NT_STATUS_OK
;
1748 status
= dbwrap_traverse(table
->local
.db_ctx
,
1749 smbXsrv_session_logoff_all_callback
,
1751 if (!NT_STATUS_IS_OK(status
)) {
1752 DEBUG(0, ("smbXsrv_session_logoff_all: "
1753 "dbwrap_traverse() failed: %s\n",
1754 nt_errstr(status
)));
1758 if (!NT_STATUS_IS_OK(state
.first_status
)) {
1759 DEBUG(0, ("smbXsrv_session_logoff_all: "
1760 "count[%d] errors[%d] first[%s]\n",
1761 count
, state
.errors
,
1762 nt_errstr(state
.first_status
)));
1763 return state
.first_status
;
1766 return NT_STATUS_OK
;
1769 static int smbXsrv_session_logoff_all_callback(struct db_record
*local_rec
,
1772 struct smbXsrv_session_logoff_all_state
*state
=
1773 (struct smbXsrv_session_logoff_all_state
*)private_data
;
1776 struct smbXsrv_session
*session
= NULL
;
1779 val
= dbwrap_record_get_value(local_rec
);
1780 if (val
.dsize
!= sizeof(ptr
)) {
1781 status
= NT_STATUS_INTERNAL_ERROR
;
1782 if (NT_STATUS_IS_OK(state
->first_status
)) {
1783 state
->first_status
= status
;
1789 memcpy(&ptr
, val
.dptr
, val
.dsize
);
1790 session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
1792 session
->db_rec
= local_rec
;
1794 status
= smbXsrv_session_clear_and_logoff(session
);
1795 if (!NT_STATUS_IS_OK(status
)) {
1796 if (NT_STATUS_IS_OK(state
->first_status
)) {
1797 state
->first_status
= status
;
1806 NTSTATUS
smb1srv_session_table_init(struct smbXsrv_connection
*conn
)
1809 * Allow a range from 1..65534 with 65534 values.
1811 return smbXsrv_session_table_init(conn
, 1, UINT16_MAX
- 1,
1815 NTSTATUS
smb1srv_session_lookup(struct smbXsrv_connection
*conn
,
1816 uint16_t vuid
, NTTIME now
,
1817 struct smbXsrv_session
**session
)
1819 struct smbXsrv_session_table
*table
= conn
->client
->session_table
;
1820 uint32_t local_id
= vuid
;
1822 return smbXsrv_session_local_lookup(table
, conn
, local_id
, now
,
1826 NTSTATUS
smb2srv_session_table_init(struct smbXsrv_connection
*conn
)
1829 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1831 return smbXsrv_session_table_init(conn
, 1, UINT32_MAX
- 1,
1835 static NTSTATUS
smb2srv_session_lookup_raw(struct smbXsrv_session_table
*table
,
1836 /* conn: optional */
1837 struct smbXsrv_connection
*conn
,
1838 uint64_t session_id
, NTTIME now
,
1839 struct smbXsrv_session
**session
)
1841 uint32_t local_id
= session_id
& UINT32_MAX
;
1842 uint64_t local_zeros
= session_id
& 0xFFFFFFFF00000000LLU
;
1844 if (local_zeros
!= 0) {
1845 return NT_STATUS_USER_SESSION_DELETED
;
1848 return smbXsrv_session_local_lookup(table
, conn
, local_id
, now
,
1852 NTSTATUS
smb2srv_session_lookup_conn(struct smbXsrv_connection
*conn
,
1853 uint64_t session_id
, NTTIME now
,
1854 struct smbXsrv_session
**session
)
1856 struct smbXsrv_session_table
*table
= conn
->client
->session_table
;
1857 return smb2srv_session_lookup_raw(table
, conn
, session_id
, now
,
1861 NTSTATUS
smb2srv_session_lookup_client(struct smbXsrv_client
*client
,
1862 uint64_t session_id
, NTTIME now
,
1863 struct smbXsrv_session
**session
)
1865 struct smbXsrv_session_table
*table
= client
->session_table
;
1866 return smb2srv_session_lookup_raw(table
, NULL
, session_id
, now
,
1870 struct smbXsrv_session_global_traverse_state
{
1871 int (*fn
)(struct smbXsrv_session_global0
*, void *);
1875 static int smbXsrv_session_global_traverse_fn(struct db_record
*rec
, void *data
)
1878 struct smbXsrv_session_global_traverse_state
*state
=
1879 (struct smbXsrv_session_global_traverse_state
*)data
;
1880 TDB_DATA key
= dbwrap_record_get_key(rec
);
1881 TDB_DATA val
= dbwrap_record_get_value(rec
);
1882 DATA_BLOB blob
= data_blob_const(val
.dptr
, val
.dsize
);
1883 struct smbXsrv_session_globalB global_blob
;
1884 enum ndr_err_code ndr_err
;
1885 TALLOC_CTX
*frame
= talloc_stackframe();
1887 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
1888 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_globalB
);
1889 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1890 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1891 "key '%s' ndr_pull_struct_blob - %s\n",
1892 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1893 ndr_errstr(ndr_err
)));
1897 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
1898 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1899 "key '%s' unsuported version - %d\n",
1900 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1901 (int)global_blob
.version
));
1905 global_blob
.info
.info0
->db_rec
= rec
;
1906 ret
= state
->fn(global_blob
.info
.info0
, state
->private_data
);
1912 NTSTATUS
smbXsrv_session_global_traverse(
1913 int (*fn
)(struct smbXsrv_session_global0
*, void *),
1919 struct smbXsrv_session_global_traverse_state state
= {
1921 .private_data
= private_data
,
1925 status
= smbXsrv_session_global_init();
1926 if (!NT_STATUS_IS_OK(status
)) {
1928 DEBUG(0, ("Failed to initialize session_global: %s\n",
1929 nt_errstr(status
)));
1933 status
= dbwrap_traverse_read(smbXsrv_session_global_db_ctx
,
1934 smbXsrv_session_global_traverse_fn
,