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 const 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");
70 db_ctx
= db_open(NULL
, global_path
,
74 TDB_INCOMPATIBLE_HASH
,
75 O_RDWR
| O_CREAT
, 0600,
81 status
= map_nt_error_from_unix_common(errno
);
86 smbXsrv_session_global_db_ctx
= db_ctx
;
93 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
94 * has the same result as integer comparison between the uint32_t
97 * TODO: implement string based key
100 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
102 static TDB_DATA
smbXsrv_session_global_id_to_key(uint32_t id
,
107 RSIVAL(key_buf
, 0, id
);
109 key
= make_tdb_data(key_buf
, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
);
115 static NTSTATUS
smbXsrv_session_global_key_to_id(TDB_DATA key
, uint32_t *id
)
118 return NT_STATUS_INVALID_PARAMETER
;
121 if (key
.dsize
!= SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
) {
122 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
125 *id
= RIVAL(key
.dptr
, 0);
131 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
133 static TDB_DATA
smbXsrv_session_local_id_to_key(uint32_t id
,
138 RSIVAL(key_buf
, 0, id
);
140 key
= make_tdb_data(key_buf
, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
);
145 static NTSTATUS
smbXsrv_session_local_key_to_id(TDB_DATA key
, uint32_t *id
)
148 return NT_STATUS_INVALID_PARAMETER
;
151 if (key
.dsize
!= SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
) {
152 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
155 *id
= RIVAL(key
.dptr
, 0);
160 static void smbXsrv_session_close_loop(struct tevent_req
*subreq
);
162 static NTSTATUS
smbXsrv_session_table_init(struct smbXsrv_connection
*conn
,
165 uint32_t max_sessions
)
167 struct smbXsrv_session_table
*table
;
169 struct tevent_req
*subreq
;
172 if (lowest_id
> highest_id
) {
173 return NT_STATUS_INTERNAL_ERROR
;
176 max_range
= highest_id
;
177 max_range
-= lowest_id
;
180 if (max_sessions
> max_range
) {
181 return NT_STATUS_INTERNAL_ERROR
;
184 table
= talloc_zero(conn
, struct smbXsrv_session_table
);
186 return NT_STATUS_NO_MEMORY
;
189 table
->local
.db_ctx
= db_open_rbt(table
);
190 if (table
->local
.db_ctx
== NULL
) {
192 return NT_STATUS_NO_MEMORY
;
194 table
->local
.lowest_id
= lowest_id
;
195 table
->local
.highest_id
= highest_id
;
196 table
->local
.max_sessions
= max_sessions
;
198 status
= smbXsrv_session_global_init();
199 if (!NT_STATUS_IS_OK(status
)) {
204 table
->global
.db_ctx
= smbXsrv_session_global_db_ctx
;
206 dbwrap_watch_db(table
->global
.db_ctx
, conn
->msg_ctx
);
208 subreq
= messaging_read_send(table
, conn
->ev_ctx
, conn
->msg_ctx
,
209 MSG_SMBXSRV_SESSION_CLOSE
);
210 if (subreq
== NULL
) {
212 return NT_STATUS_NO_MEMORY
;
214 tevent_req_set_callback(subreq
, smbXsrv_session_close_loop
, conn
);
216 conn
->session_table
= table
;
220 static void smbXsrv_session_close_loop(struct tevent_req
*subreq
)
222 struct smbXsrv_connection
*conn
=
223 tevent_req_callback_data(subreq
,
224 struct smbXsrv_connection
);
225 struct smbXsrv_session_table
*table
= conn
->session_table
;
227 struct messaging_rec
*rec
= NULL
;
228 struct smbXsrv_session_closeB close_blob
;
229 enum ndr_err_code ndr_err
;
230 struct smbXsrv_session_close0
*close_info0
= NULL
;
231 struct smbXsrv_session
*session
= NULL
;
233 struct timeval tv
= timeval_current();
234 NTTIME now
= timeval_to_nttime(&tv
);
236 ret
= messaging_read_recv(subreq
, talloc_tos(), &rec
);
242 ndr_err
= ndr_pull_struct_blob(&rec
->buf
, rec
, &close_blob
,
243 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_closeB
);
244 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
245 status
= ndr_map_error2ntstatus(ndr_err
);
246 DEBUG(1,("smbXsrv_session_close_loop: "
247 "ndr_pull_struct_blob - %s\n",
252 DEBUG(10,("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n"));
254 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
257 if (close_blob
.version
!= SMBXSRV_VERSION_0
) {
258 DEBUG(0,("smbXsrv_session_close_loop: "
259 "ignore invalid version %u\n", close_blob
.version
));
260 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
264 close_info0
= close_blob
.info
.info0
;
265 if (close_info0
== NULL
) {
266 DEBUG(0,("smbXsrv_session_close_loop: "
267 "ignore NULL info %u\n", close_blob
.version
));
268 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
272 status
= smb2srv_session_lookup(conn
, close_info0
->old_session_wire_id
,
274 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_SESSION_DELETED
)) {
275 DEBUG(4,("smbXsrv_session_close_loop: "
276 "old_session_wire_id %llu not found\n",
277 (unsigned long long)close_info0
->old_session_wire_id
));
279 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
283 if (!NT_STATUS_IS_OK(status
) &&
284 !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) &&
285 !NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_SESSION_EXPIRED
)) {
286 DEBUG(1,("smbXsrv_session_close_loop: "
287 "old_session_wire_id %llu - %s\n",
288 (unsigned long long)close_info0
->old_session_wire_id
,
291 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
296 if (session
->global
->session_global_id
!= close_info0
->old_session_global_id
) {
297 DEBUG(1,("smbXsrv_session_close_loop: "
298 "old_session_wire_id %llu - global %u != %u\n",
299 (unsigned long long)close_info0
->old_session_wire_id
,
300 session
->global
->session_global_id
,
301 close_info0
->old_session_global_id
));
303 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
308 if (session
->global
->creation_time
!= close_info0
->old_creation_time
) {
309 DEBUG(1,("smbXsrv_session_close_loop: "
310 "old_session_wire_id %llu - "
311 "creation %s (%llu) != %s (%llu)\n",
312 (unsigned long long)close_info0
->old_session_wire_id
,
313 nt_time_string(rec
, session
->global
->creation_time
),
314 (unsigned long long)session
->global
->creation_time
,
315 nt_time_string(rec
, close_info0
->old_creation_time
),
316 (unsigned long long)close_info0
->old_creation_time
));
318 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
324 * TODO: cancel all outstanding requests on the session
326 status
= smbXsrv_session_logoff(session
);
327 if (!NT_STATUS_IS_OK(status
)) {
328 DEBUG(0, ("smbXsrv_session_close_loop: "
329 "smbXsrv_session_logoff(%llu) failed: %s\n",
330 (unsigned long long)session
->global
->session_wire_id
,
333 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
336 TALLOC_FREE(session
);
341 subreq
= messaging_read_send(table
, conn
->ev_ctx
, conn
->msg_ctx
,
342 MSG_SMBXSRV_SESSION_CLOSE
);
343 if (subreq
== NULL
) {
344 smbd_server_connection_terminate(conn
->sconn
,
345 "msg_read_send() failed");
348 tevent_req_set_callback(subreq
, smbXsrv_session_close_loop
, conn
);
351 struct smb1srv_session_local_allocate_state
{
352 const uint32_t lowest_id
;
353 const uint32_t highest_id
;
359 static int smb1srv_session_local_allocate_traverse(struct db_record
*rec
,
362 struct smb1srv_session_local_allocate_state
*state
=
363 (struct smb1srv_session_local_allocate_state
*)private_data
;
364 TDB_DATA key
= dbwrap_record_get_key(rec
);
368 status
= smbXsrv_session_local_key_to_id(key
, &id
);
369 if (!NT_STATUS_IS_OK(status
)) {
370 state
->status
= status
;
374 if (id
<= state
->last_id
) {
375 state
->status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
380 if (id
> state
->useable_id
) {
381 state
->status
= NT_STATUS_OK
;
385 if (state
->useable_id
== state
->highest_id
) {
386 state
->status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
390 state
->useable_id
+=1;
394 static NTSTATUS
smb1srv_session_local_allocate_id(struct db_context
*db
,
398 struct db_record
**_rec
,
401 struct smb1srv_session_local_allocate_state state
= {
402 .lowest_id
= lowest_id
,
403 .highest_id
= highest_id
,
405 .useable_id
= lowest_id
,
406 .status
= NT_STATUS_INTERNAL_ERROR
,
416 if (lowest_id
> highest_id
) {
417 return NT_STATUS_INSUFFICIENT_RESOURCES
;
421 * first we try randomly
423 range
= (highest_id
- lowest_id
) + 1;
425 for (i
= 0; i
< (range
/ 2); i
++) {
427 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
430 struct db_record
*rec
= NULL
;
432 id
= generate_random() % range
;
435 if (id
< lowest_id
) {
438 if (id
> highest_id
) {
442 key
= smbXsrv_session_local_id_to_key(id
, key_buf
);
444 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
446 return NT_STATUS_INSUFFICIENT_RESOURCES
;
449 val
= dbwrap_record_get_value(rec
);
450 if (val
.dsize
!= 0) {
461 * if the range is almost full,
462 * we traverse the whole table
463 * (this relies on sorted behavior of dbwrap_rbt)
465 status
= dbwrap_traverse_read(db
, smb1srv_session_local_allocate_traverse
,
467 if (NT_STATUS_IS_OK(status
)) {
468 if (NT_STATUS_IS_OK(state
.status
)) {
469 return NT_STATUS_INTERNAL_ERROR
;
472 if (!NT_STATUS_EQUAL(state
.status
, NT_STATUS_INTERNAL_ERROR
)) {
476 if (state
.useable_id
<= state
.highest_id
) {
477 state
.status
= NT_STATUS_OK
;
479 return NT_STATUS_INSUFFICIENT_RESOURCES
;
481 } else if (!NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_DB_CORRUPTION
)) {
483 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
485 * If we get anything else it is an error, because it
486 * means we did not manage to find a free slot in
489 return NT_STATUS_INSUFFICIENT_RESOURCES
;
492 if (NT_STATUS_IS_OK(state
.status
)) {
494 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
497 struct db_record
*rec
= NULL
;
499 id
= state
.useable_id
;
501 key
= smbXsrv_session_local_id_to_key(id
, key_buf
);
503 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
505 return NT_STATUS_INSUFFICIENT_RESOURCES
;
508 val
= dbwrap_record_get_value(rec
);
509 if (val
.dsize
!= 0) {
511 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
522 struct smbXsrv_session_local_fetch_state
{
523 struct smbXsrv_session
*session
;
527 static void smbXsrv_session_local_fetch_parser(TDB_DATA key
, TDB_DATA data
,
530 struct smbXsrv_session_local_fetch_state
*state
=
531 (struct smbXsrv_session_local_fetch_state
*)private_data
;
534 if (data
.dsize
!= sizeof(ptr
)) {
535 state
->status
= NT_STATUS_INTERNAL_DB_ERROR
;
539 memcpy(&ptr
, data
.dptr
, data
.dsize
);
540 state
->session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
541 state
->status
= NT_STATUS_OK
;
544 static NTSTATUS
smbXsrv_session_local_lookup(struct smbXsrv_session_table
*table
,
545 uint32_t session_local_id
,
547 struct smbXsrv_session
**_session
)
549 struct smbXsrv_session_local_fetch_state state
= {
551 .status
= NT_STATUS_INTERNAL_ERROR
,
553 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
559 if (session_local_id
== 0) {
560 return NT_STATUS_USER_SESSION_DELETED
;
564 /* this might happen before the end of negprot */
565 return NT_STATUS_USER_SESSION_DELETED
;
568 if (table
->local
.db_ctx
== NULL
) {
569 return NT_STATUS_INTERNAL_ERROR
;
572 key
= smbXsrv_session_local_id_to_key(session_local_id
, key_buf
);
574 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
575 smbXsrv_session_local_fetch_parser
,
577 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
578 return NT_STATUS_USER_SESSION_DELETED
;
579 } else if (!NT_STATUS_IS_OK(status
)) {
582 if (!NT_STATUS_IS_OK(state
.status
)) {
586 if (NT_STATUS_EQUAL(state
.session
->status
, NT_STATUS_USER_SESSION_DELETED
)) {
587 return NT_STATUS_USER_SESSION_DELETED
;
590 state
.session
->idle_time
= now
;
592 if (!NT_STATUS_IS_OK(state
.session
->status
)) {
593 *_session
= state
.session
;
594 return state
.session
->status
;
597 if (now
> state
.session
->global
->expiration_time
) {
598 state
.session
->status
= NT_STATUS_NETWORK_SESSION_EXPIRED
;
601 *_session
= state
.session
;
602 return state
.session
->status
;
605 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0
*global
)
610 static void smbXsrv_session_global_verify_record(struct db_record
*db_rec
,
614 struct smbXsrv_session_global0
**_g
);
616 static NTSTATUS
smbXsrv_session_global_allocate(struct db_context
*db
,
618 struct smbXsrv_session_global0
**_global
)
621 struct smbXsrv_session_global0
*global
= NULL
;
622 uint32_t last_free
= 0;
623 const uint32_t min_tries
= 3;
627 global
= talloc_zero(mem_ctx
, struct smbXsrv_session_global0
);
628 if (global
== NULL
) {
629 return NT_STATUS_NO_MEMORY
;
631 talloc_set_destructor(global
, smbXsrv_session_global_destructor
);
634 * Here we just randomly try the whole 32-bit space
636 * We use just 32-bit, because we want to reuse the
639 for (i
= 0; i
< UINT32_MAX
; i
++) {
640 bool is_free
= false;
641 bool was_free
= false;
643 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
646 if (i
>= min_tries
&& last_free
!= 0) {
649 id
= generate_random();
654 if (id
== UINT32_MAX
) {
658 key
= smbXsrv_session_global_id_to_key(id
, key_buf
);
660 global
->db_rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
661 if (global
->db_rec
== NULL
) {
663 return NT_STATUS_INSUFFICIENT_RESOURCES
;
666 smbXsrv_session_global_verify_record(global
->db_rec
,
672 TALLOC_FREE(global
->db_rec
);
676 if (!was_free
&& i
< min_tries
) {
678 * The session_id is free now,
679 * but was not free before.
681 * This happens if a smbd crashed
682 * and did not cleanup the record.
684 * If this is one of our first tries,
685 * then we try to find a real free one.
687 if (last_free
== 0) {
690 TALLOC_FREE(global
->db_rec
);
694 global
->session_global_id
= id
;
700 /* should not be reached */
702 return NT_STATUS_INTERNAL_ERROR
;
705 static void smbXsrv_session_global_verify_record(struct db_record
*db_rec
,
709 struct smbXsrv_session_global0
**_g
)
714 struct smbXsrv_session_globalB global_blob
;
715 enum ndr_err_code ndr_err
;
716 struct smbXsrv_session_global0
*global
= NULL
;
718 TALLOC_CTX
*frame
= talloc_stackframe();
729 key
= dbwrap_record_get_key(db_rec
);
731 val
= dbwrap_record_get_value(db_rec
);
732 if (val
.dsize
== 0) {
741 blob
= data_blob_const(val
.dptr
, val
.dsize
);
743 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
744 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_globalB
);
745 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
746 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
747 DEBUG(1,("smbXsrv_session_global_verify_record: "
748 "key '%s' ndr_pull_struct_blob - %s\n",
749 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
755 DEBUG(10,("smbXsrv_session_global_verify_record\n"));
757 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
760 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
761 DEBUG(0,("smbXsrv_session_global_verify_record: "
762 "key '%s' use unsupported version %u\n",
763 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
764 global_blob
.version
));
765 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
770 global
= global_blob
.info
.info0
;
772 exists
= serverid_exists(&global
->channels
[0].server_id
);
774 DEBUG(2,("smbXsrv_session_global_verify_record: "
775 "key '%s' server_id %s does not exist.\n",
776 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
777 server_id_str(frame
, &global
->channels
[0].server_id
)));
779 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
782 dbwrap_record_delete(db_rec
);
788 *_g
= talloc_move(mem_ctx
, &global
);
793 static NTSTATUS
smbXsrv_session_global_store(struct smbXsrv_session_global0
*global
)
795 struct smbXsrv_session_globalB global_blob
;
796 DATA_BLOB blob
= data_blob_null
;
800 enum ndr_err_code ndr_err
;
803 * TODO: if we use other versions than '0'
804 * we would add glue code here, that would be able to
805 * store the information in the old format.
808 if (global
->db_rec
== NULL
) {
809 return NT_STATUS_INTERNAL_ERROR
;
812 key
= dbwrap_record_get_key(global
->db_rec
);
813 val
= dbwrap_record_get_value(global
->db_rec
);
815 ZERO_STRUCT(global_blob
);
816 global_blob
.version
= smbXsrv_version_global_current();
817 if (val
.dsize
>= 8) {
818 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
820 global_blob
.seqnum
+= 1;
821 global_blob
.info
.info0
= global
;
823 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
824 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_session_globalB
);
825 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
826 status
= ndr_map_error2ntstatus(ndr_err
);
827 DEBUG(1,("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
828 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
830 TALLOC_FREE(global
->db_rec
);
834 val
= make_tdb_data(blob
.data
, blob
.length
);
835 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
836 if (!NT_STATUS_IS_OK(status
)) {
837 DEBUG(1,("smbXsrv_session_global_store: key '%s' store - %s\n",
838 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
840 TALLOC_FREE(global
->db_rec
);
845 DEBUG(10,("smbXsrv_session_global_store: key '%s' stored\n",
846 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
)));
847 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
850 TALLOC_FREE(global
->db_rec
);
855 struct smb2srv_session_close_previous_state
{
856 struct tevent_context
*ev
;
857 struct smbXsrv_connection
*connection
;
858 struct dom_sid
*current_sid
;
859 uint64_t current_session_id
;
860 struct db_record
*db_rec
;
863 static void smb2srv_session_close_previous_check(struct tevent_req
*req
);
864 static void smb2srv_session_close_previous_modified(struct tevent_req
*subreq
);
866 struct tevent_req
*smb2srv_session_close_previous_send(TALLOC_CTX
*mem_ctx
,
867 struct tevent_context
*ev
,
868 struct smbXsrv_connection
*conn
,
869 struct auth_session_info
*session_info
,
870 uint64_t previous_session_id
,
871 uint64_t current_session_id
)
873 struct tevent_req
*req
;
874 struct smb2srv_session_close_previous_state
*state
;
875 uint32_t global_id
= previous_session_id
& UINT32_MAX
;
876 uint64_t global_zeros
= previous_session_id
& 0xFFFFFFFF00000000LLU
;
877 struct smbXsrv_session_table
*table
= conn
->session_table
;
878 struct security_token
*current_token
= NULL
;
879 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
882 req
= tevent_req_create(mem_ctx
, &state
,
883 struct smb2srv_session_close_previous_state
);
888 state
->connection
= conn
;
889 state
->current_session_id
= current_session_id
;
891 if (global_zeros
!= 0) {
892 tevent_req_done(req
);
893 return tevent_req_post(req
, ev
);
896 if (session_info
== NULL
) {
897 tevent_req_done(req
);
898 return tevent_req_post(req
, ev
);
900 current_token
= session_info
->security_token
;
902 if (current_token
->num_sids
> PRIMARY_USER_SID_INDEX
) {
903 state
->current_sid
= ¤t_token
->sids
[PRIMARY_USER_SID_INDEX
];
906 if (state
->current_sid
== NULL
) {
907 tevent_req_done(req
);
908 return tevent_req_post(req
, ev
);
911 if (!security_token_has_nt_authenticated_users(current_token
)) {
913 tevent_req_done(req
);
914 return tevent_req_post(req
, ev
);
917 key
= smbXsrv_session_global_id_to_key(global_id
, key_buf
);
919 state
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
921 if (state
->db_rec
== NULL
) {
922 tevent_req_nterror(req
, NT_STATUS_UNSUCCESSFUL
);
923 return tevent_req_post(req
, ev
);
926 smb2srv_session_close_previous_check(req
);
927 if (!tevent_req_is_in_progress(req
)) {
928 return tevent_req_post(req
, ev
);
934 static void smb2srv_session_close_previous_check(struct tevent_req
*req
)
936 struct smb2srv_session_close_previous_state
*state
=
938 struct smb2srv_session_close_previous_state
);
939 struct smbXsrv_connection
*conn
= state
->connection
;
941 struct security_token
*previous_token
= NULL
;
942 struct smbXsrv_session_global0
*global
= NULL
;
943 enum ndr_err_code ndr_err
;
944 struct smbXsrv_session_close0 close_info0
;
945 struct smbXsrv_session_closeB close_blob
;
946 struct tevent_req
*subreq
= NULL
;
948 bool is_free
= false;
950 smbXsrv_session_global_verify_record(state
->db_rec
,
957 TALLOC_FREE(state
->db_rec
);
958 tevent_req_done(req
);
962 if (global
->auth_session_info
== NULL
) {
963 TALLOC_FREE(state
->db_rec
);
964 tevent_req_done(req
);
968 previous_token
= global
->auth_session_info
->security_token
;
970 if (!security_token_is_sid(previous_token
, state
->current_sid
)) {
971 TALLOC_FREE(state
->db_rec
);
972 tevent_req_done(req
);
976 subreq
= dbwrap_record_watch_send(state
, state
->ev
,
977 state
->db_rec
, conn
->msg_ctx
);
978 if (tevent_req_nomem(subreq
, req
)) {
979 TALLOC_FREE(state
->db_rec
);
982 tevent_req_set_callback(subreq
,
983 smb2srv_session_close_previous_modified
,
986 close_info0
.old_session_global_id
= global
->session_global_id
;
987 close_info0
.old_session_wire_id
= global
->session_wire_id
;
988 close_info0
.old_creation_time
= global
->creation_time
;
989 close_info0
.new_session_wire_id
= state
->current_session_id
;
991 ZERO_STRUCT(close_blob
);
992 close_blob
.version
= smbXsrv_version_global_current();
993 close_blob
.info
.info0
= &close_info0
;
995 ndr_err
= ndr_push_struct_blob(&blob
, state
, &close_blob
,
996 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_session_closeB
);
997 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
998 TALLOC_FREE(state
->db_rec
);
999 status
= ndr_map_error2ntstatus(ndr_err
);
1000 DEBUG(1,("smb2srv_session_close_previous_check: "
1001 "old_session[%llu] new_session[%llu] ndr_push - %s\n",
1002 (unsigned long long)close_info0
.old_session_wire_id
,
1003 (unsigned long long)close_info0
.new_session_wire_id
,
1004 nt_errstr(status
)));
1005 tevent_req_nterror(req
, status
);
1009 status
= messaging_send(conn
->msg_ctx
,
1010 global
->channels
[0].server_id
,
1011 MSG_SMBXSRV_SESSION_CLOSE
, &blob
);
1012 TALLOC_FREE(state
->db_rec
);
1013 if (tevent_req_nterror(req
, status
)) {
1017 TALLOC_FREE(global
);
1021 static void smb2srv_session_close_previous_modified(struct tevent_req
*subreq
)
1023 struct tevent_req
*req
=
1024 tevent_req_callback_data(subreq
,
1026 struct smb2srv_session_close_previous_state
*state
=
1027 tevent_req_data(req
,
1028 struct smb2srv_session_close_previous_state
);
1031 status
= dbwrap_record_watch_recv(subreq
, state
, &state
->db_rec
);
1032 TALLOC_FREE(subreq
);
1033 if (tevent_req_nterror(req
, status
)) {
1037 smb2srv_session_close_previous_check(req
);
1040 NTSTATUS
smb2srv_session_close_previous_recv(struct tevent_req
*req
)
1044 if (tevent_req_is_nterror(req
, &status
)) {
1045 tevent_req_received(req
);
1049 tevent_req_received(req
);
1050 return NT_STATUS_OK
;
1053 static int smbXsrv_session_destructor(struct smbXsrv_session
*session
)
1057 status
= smbXsrv_session_logoff(session
);
1058 if (!NT_STATUS_IS_OK(status
)) {
1059 DEBUG(0, ("smbXsrv_session_destructor: "
1060 "smbXsrv_session_logoff() failed: %s\n",
1061 nt_errstr(status
)));
1064 TALLOC_FREE(session
->global
);
1069 NTSTATUS
smbXsrv_session_create(struct smbXsrv_connection
*conn
,
1071 struct smbXsrv_session
**_session
)
1073 struct smbXsrv_session_table
*table
= conn
->session_table
;
1074 struct db_record
*local_rec
= NULL
;
1075 struct smbXsrv_session
*session
= NULL
;
1078 struct smbXsrv_session_global0
*global
= NULL
;
1079 struct smbXsrv_channel_global0
*channels
= NULL
;
1082 if (table
->local
.num_sessions
>= table
->local
.max_sessions
) {
1083 return NT_STATUS_INSUFFICIENT_RESOURCES
;
1086 session
= talloc_zero(table
, struct smbXsrv_session
);
1087 if (session
== NULL
) {
1088 return NT_STATUS_NO_MEMORY
;
1090 session
->table
= table
;
1091 session
->idle_time
= now
;
1092 session
->status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1093 session
->connection
= conn
;
1095 status
= smbXsrv_session_global_allocate(table
->global
.db_ctx
,
1098 if (!NT_STATUS_IS_OK(status
)) {
1099 TALLOC_FREE(session
);
1102 session
->global
= global
;
1104 if (conn
->protocol
>= PROTOCOL_SMB2_02
) {
1105 uint64_t id
= global
->session_global_id
;
1106 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
1109 global
->connection_dialect
= conn
->smb2
.server
.dialect
;
1111 global
->session_wire_id
= id
;
1113 status
= smb2srv_tcon_table_init(session
);
1114 if (!NT_STATUS_IS_OK(status
)) {
1115 TALLOC_FREE(session
);
1119 session
->local_id
= global
->session_global_id
;
1121 key
= smbXsrv_session_local_id_to_key(session
->local_id
, key_buf
);
1123 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
1125 if (local_rec
== NULL
) {
1126 TALLOC_FREE(session
);
1127 return NT_STATUS_NO_MEMORY
;
1130 val
= dbwrap_record_get_value(local_rec
);
1131 if (val
.dsize
!= 0) {
1132 TALLOC_FREE(session
);
1133 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1137 status
= smb1srv_session_local_allocate_id(table
->local
.db_ctx
,
1138 table
->local
.lowest_id
,
1139 table
->local
.highest_id
,
1142 &session
->local_id
);
1143 if (!NT_STATUS_IS_OK(status
)) {
1144 TALLOC_FREE(session
);
1148 global
->session_wire_id
= session
->local_id
;
1151 global
->creation_time
= now
;
1152 global
->expiration_time
= GENSEC_EXPIRE_TIME_INFINITY
;
1154 global
->num_channels
= 1;
1155 channels
= talloc_zero_array(global
,
1156 struct smbXsrv_channel_global0
,
1157 global
->num_channels
);
1158 if (channels
== NULL
) {
1159 TALLOC_FREE(session
);
1160 return NT_STATUS_NO_MEMORY
;
1162 global
->channels
= channels
;
1164 channels
[0].server_id
= messaging_server_id(conn
->msg_ctx
);
1165 channels
[0].local_address
= tsocket_address_string(conn
->local_address
,
1167 if (channels
[0].local_address
== NULL
) {
1168 TALLOC_FREE(session
);
1169 return NT_STATUS_NO_MEMORY
;
1171 channels
[0].remote_address
= tsocket_address_string(conn
->remote_address
,
1173 if (channels
[0].remote_address
== NULL
) {
1174 TALLOC_FREE(session
);
1175 return NT_STATUS_NO_MEMORY
;
1177 channels
[0].remote_name
= talloc_strdup(channels
, conn
->remote_hostname
);
1178 if (channels
[0].remote_name
== NULL
) {
1179 TALLOC_FREE(session
);
1180 return NT_STATUS_NO_MEMORY
;
1182 channels
[0].signing_key
= data_blob_null
;
1185 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
1186 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
1187 TALLOC_FREE(local_rec
);
1188 if (!NT_STATUS_IS_OK(status
)) {
1189 TALLOC_FREE(session
);
1192 table
->local
.num_sessions
+= 1;
1194 talloc_set_destructor(session
, smbXsrv_session_destructor
);
1196 status
= smbXsrv_session_global_store(global
);
1197 if (!NT_STATUS_IS_OK(status
)) {
1198 DEBUG(0,("smbXsrv_session_create: "
1199 "global_id (0x%08x) store failed - %s\n",
1200 session
->global
->session_global_id
,
1201 nt_errstr(status
)));
1202 TALLOC_FREE(session
);
1207 struct smbXsrv_sessionB session_blob
;
1209 ZERO_STRUCT(session_blob
);
1210 session_blob
.version
= SMBXSRV_VERSION_0
;
1211 session_blob
.info
.info0
= session
;
1213 DEBUG(10,("smbXsrv_session_create: global_id (0x%08x) stored\n",
1214 session
->global
->session_global_id
));
1215 NDR_PRINT_DEBUG(smbXsrv_sessionB
, &session_blob
);
1218 *_session
= session
;
1219 return NT_STATUS_OK
;
1222 NTSTATUS
smbXsrv_session_update(struct smbXsrv_session
*session
)
1224 struct smbXsrv_session_table
*table
= session
->table
;
1226 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
1229 if (session
->global
->db_rec
!= NULL
) {
1230 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1231 "Called with db_rec != NULL'\n",
1232 session
->global
->session_global_id
));
1233 return NT_STATUS_INTERNAL_ERROR
;
1236 key
= smbXsrv_session_global_id_to_key(
1237 session
->global
->session_global_id
,
1240 session
->global
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
1241 session
->global
, key
);
1242 if (session
->global
->db_rec
== NULL
) {
1243 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1244 "Failed to lock global key '%s'\n",
1245 session
->global
->session_global_id
,
1246 hex_encode_talloc(talloc_tos(), key
.dptr
,
1248 return NT_STATUS_INTERNAL_DB_ERROR
;
1251 status
= smbXsrv_session_global_store(session
->global
);
1252 if (!NT_STATUS_IS_OK(status
)) {
1253 DEBUG(0,("smbXsrv_session_update: "
1254 "global_id (0x%08x) store failed - %s\n",
1255 session
->global
->session_global_id
,
1256 nt_errstr(status
)));
1261 struct smbXsrv_sessionB session_blob
;
1263 ZERO_STRUCT(session_blob
);
1264 session_blob
.version
= SMBXSRV_VERSION_0
;
1265 session_blob
.info
.info0
= session
;
1267 DEBUG(10,("smbXsrv_session_update: global_id (0x%08x) stored\n",
1268 session
->global
->session_global_id
));
1269 NDR_PRINT_DEBUG(smbXsrv_sessionB
, &session_blob
);
1272 return NT_STATUS_OK
;
1275 NTSTATUS
smbXsrv_session_logoff(struct smbXsrv_session
*session
)
1277 struct smbXsrv_session_table
*table
;
1278 struct db_record
*local_rec
= NULL
;
1279 struct db_record
*global_rec
= NULL
;
1280 struct smbXsrv_connection
*conn
;
1282 NTSTATUS error
= NT_STATUS_OK
;
1284 if (session
->table
== NULL
) {
1285 return NT_STATUS_OK
;
1288 table
= session
->table
;
1289 session
->table
= NULL
;
1291 conn
= session
->connection
;
1292 session
->connection
= NULL
;
1293 session
->status
= NT_STATUS_USER_SESSION_DELETED
;
1295 global_rec
= session
->global
->db_rec
;
1296 session
->global
->db_rec
= NULL
;
1297 if (global_rec
== NULL
) {
1298 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
1301 key
= smbXsrv_session_global_id_to_key(
1302 session
->global
->session_global_id
,
1305 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
1306 session
->global
, key
);
1307 if (global_rec
== NULL
) {
1308 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1309 "Failed to lock global key '%s'\n",
1310 session
->global
->session_global_id
,
1311 hex_encode_talloc(global_rec
, key
.dptr
,
1313 error
= NT_STATUS_INTERNAL_ERROR
;
1317 if (global_rec
!= NULL
) {
1318 status
= dbwrap_record_delete(global_rec
);
1319 if (!NT_STATUS_IS_OK(status
)) {
1320 TDB_DATA key
= dbwrap_record_get_key(global_rec
);
1322 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1323 "failed to delete global key '%s': %s\n",
1324 session
->global
->session_global_id
,
1325 hex_encode_talloc(global_rec
, key
.dptr
,
1327 nt_errstr(status
)));
1331 TALLOC_FREE(global_rec
);
1333 local_rec
= session
->db_rec
;
1334 if (local_rec
== NULL
) {
1335 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
1338 key
= smbXsrv_session_local_id_to_key(session
->local_id
,
1341 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
1343 if (local_rec
== NULL
) {
1344 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1345 "Failed to lock local key '%s'\n",
1346 session
->global
->session_global_id
,
1347 hex_encode_talloc(local_rec
, key
.dptr
,
1349 error
= NT_STATUS_INTERNAL_ERROR
;
1353 if (local_rec
!= NULL
) {
1354 status
= dbwrap_record_delete(local_rec
);
1355 if (!NT_STATUS_IS_OK(status
)) {
1356 TDB_DATA key
= dbwrap_record_get_key(local_rec
);
1358 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1359 "failed to delete local key '%s': %s\n",
1360 session
->global
->session_global_id
,
1361 hex_encode_talloc(local_rec
, key
.dptr
,
1363 nt_errstr(status
)));
1366 table
->local
.num_sessions
-= 1;
1368 if (session
->db_rec
== NULL
) {
1369 TALLOC_FREE(local_rec
);
1371 session
->db_rec
= NULL
;
1373 if (session
->compat
) {
1374 file_close_user(conn
->sconn
, session
->compat
->vuid
);
1377 if (conn
->protocol
>= PROTOCOL_SMB2_02
) {
1378 status
= smb2srv_tcon_disconnect_all(session
);
1379 if (!NT_STATUS_IS_OK(status
)) {
1380 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1381 "smb2srv_tcon_disconnect_all() failed: %s\n",
1382 session
->global
->session_global_id
,
1383 nt_errstr(status
)));
1388 if (session
->compat
) {
1389 invalidate_vuid(conn
->sconn
, session
->compat
->vuid
);
1390 session
->compat
= NULL
;
1396 struct smbXsrv_session_logoff_all_state
{
1397 NTSTATUS first_status
;
1401 static int smbXsrv_session_logoff_all_callback(struct db_record
*local_rec
,
1402 void *private_data
);
1404 NTSTATUS
smbXsrv_session_logoff_all(struct smbXsrv_connection
*conn
)
1406 struct smbXsrv_session_table
*table
= conn
->session_table
;
1407 struct smbXsrv_session_logoff_all_state state
;
1411 if (table
== NULL
) {
1412 DEBUG(10, ("smbXsrv_session_logoff_all: "
1413 "empty session_table, nothing to do.\n"));
1414 return NT_STATUS_OK
;
1419 status
= dbwrap_traverse(table
->local
.db_ctx
,
1420 smbXsrv_session_logoff_all_callback
,
1422 if (!NT_STATUS_IS_OK(status
)) {
1423 DEBUG(0, ("smbXsrv_session_logoff_all: "
1424 "dbwrap_traverse() failed: %s\n",
1425 nt_errstr(status
)));
1429 if (!NT_STATUS_IS_OK(state
.first_status
)) {
1430 DEBUG(0, ("smbXsrv_session_logoff_all: "
1431 "count[%d] errors[%d] first[%s]\n",
1432 count
, state
.errors
,
1433 nt_errstr(state
.first_status
)));
1434 return state
.first_status
;
1437 return NT_STATUS_OK
;
1440 static int smbXsrv_session_logoff_all_callback(struct db_record
*local_rec
,
1443 struct smbXsrv_session_logoff_all_state
*state
=
1444 (struct smbXsrv_session_logoff_all_state
*)private_data
;
1447 struct smbXsrv_session
*session
= NULL
;
1450 val
= dbwrap_record_get_value(local_rec
);
1451 if (val
.dsize
!= sizeof(ptr
)) {
1452 status
= NT_STATUS_INTERNAL_ERROR
;
1453 if (NT_STATUS_IS_OK(state
->first_status
)) {
1454 state
->first_status
= status
;
1460 memcpy(&ptr
, val
.dptr
, val
.dsize
);
1461 session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
1463 session
->db_rec
= local_rec
;
1464 status
= smbXsrv_session_logoff(session
);
1465 if (!NT_STATUS_IS_OK(status
)) {
1466 if (NT_STATUS_IS_OK(state
->first_status
)) {
1467 state
->first_status
= status
;
1476 NTSTATUS
smb1srv_session_table_init(struct smbXsrv_connection
*conn
)
1479 * Allow a range from 1..65534 with 65534 values.
1481 return smbXsrv_session_table_init(conn
, 1, UINT16_MAX
- 1,
1485 NTSTATUS
smb1srv_session_lookup(struct smbXsrv_connection
*conn
,
1486 uint16_t vuid
, NTTIME now
,
1487 struct smbXsrv_session
**session
)
1489 struct smbXsrv_session_table
*table
= conn
->session_table
;
1490 uint32_t local_id
= vuid
;
1492 return smbXsrv_session_local_lookup(table
, local_id
, now
, session
);
1495 NTSTATUS
smb2srv_session_table_init(struct smbXsrv_connection
*conn
)
1498 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1500 return smbXsrv_session_table_init(conn
, 1, UINT32_MAX
- 1,
1504 NTSTATUS
smb2srv_session_lookup(struct smbXsrv_connection
*conn
,
1505 uint64_t session_id
, NTTIME now
,
1506 struct smbXsrv_session
**session
)
1508 struct smbXsrv_session_table
*table
= conn
->session_table
;
1509 uint32_t local_id
= session_id
& UINT32_MAX
;
1510 uint64_t local_zeros
= session_id
& 0xFFFFFFFF00000000LLU
;
1512 if (local_zeros
!= 0) {
1513 return NT_STATUS_USER_SESSION_DELETED
;
1516 return smbXsrv_session_local_lookup(table
, local_id
, now
, session
);
1519 struct smbXsrv_session_global_traverse_state
{
1520 int (*fn
)(struct smbXsrv_session_global0
*, void *);
1524 static int smbXsrv_session_global_traverse_fn(struct db_record
*rec
, void *data
)
1527 struct smbXsrv_session_global_traverse_state
*state
=
1528 (struct smbXsrv_session_global_traverse_state
*)data
;
1529 TDB_DATA key
= dbwrap_record_get_key(rec
);
1530 TDB_DATA val
= dbwrap_record_get_value(rec
);
1531 DATA_BLOB blob
= data_blob_const(val
.dptr
, val
.dsize
);
1532 struct smbXsrv_session_globalB global_blob
;
1533 enum ndr_err_code ndr_err
;
1534 TALLOC_CTX
*frame
= talloc_stackframe();
1536 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
1537 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_globalB
);
1538 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1539 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1540 "key '%s' ndr_pull_struct_blob - %s\n",
1541 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1542 ndr_errstr(ndr_err
)));
1546 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
1547 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1548 "key '%s' unsuported version - %d\n",
1549 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1550 (int)global_blob
.version
));
1554 global_blob
.info
.info0
->db_rec
= rec
;
1555 ret
= state
->fn(global_blob
.info
.info0
, state
->private_data
);
1561 NTSTATUS
smbXsrv_session_global_traverse(
1562 int (*fn
)(struct smbXsrv_session_global0
*, void *),
1568 struct smbXsrv_session_global_traverse_state state
= {
1570 .private_data
= private_data
,
1574 status
= smbXsrv_session_global_init();
1575 if (!NT_STATUS_IS_OK(status
)) {
1577 DEBUG(0, ("Failed to initialize session_global: %s\n",
1578 nt_errstr(status
)));
1582 status
= dbwrap_traverse_read(smbXsrv_session_global_db_ctx
,
1583 smbXsrv_session_global_traverse_fn
,