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,
80 status
= map_nt_error_from_unix_common(errno
);
85 smbXsrv_session_global_db_ctx
= db_ctx
;
92 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
93 * has the same result as integer comparison between the uint32_t
96 * TODO: implement string based key
99 #define SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
101 static TDB_DATA
smbXsrv_session_global_id_to_key(uint32_t id
,
106 RSIVAL(key_buf
, 0, id
);
108 key
= make_tdb_data(key_buf
, SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
);
114 static NTSTATUS
smbXsrv_session_global_key_to_id(TDB_DATA key
, uint32_t *id
)
117 return NT_STATUS_INVALID_PARAMETER
;
120 if (key
.dsize
!= SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
) {
121 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
124 *id
= RIVAL(key
.dptr
, 0);
130 #define SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
132 static TDB_DATA
smbXsrv_session_local_id_to_key(uint32_t id
,
137 RSIVAL(key_buf
, 0, id
);
139 key
= make_tdb_data(key_buf
, SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
);
144 static NTSTATUS
smbXsrv_session_local_key_to_id(TDB_DATA key
, uint32_t *id
)
147 return NT_STATUS_INVALID_PARAMETER
;
150 if (key
.dsize
!= SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
) {
151 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
154 *id
= RIVAL(key
.dptr
, 0);
159 static void smbXsrv_session_close_loop(struct tevent_req
*subreq
);
161 static NTSTATUS
smbXsrv_session_table_init(struct smbXsrv_connection
*conn
,
164 uint32_t max_sessions
)
166 struct smbXsrv_session_table
*table
;
168 struct tevent_req
*subreq
;
171 if (lowest_id
> highest_id
) {
172 return NT_STATUS_INTERNAL_ERROR
;
175 max_range
= highest_id
;
176 max_range
-= lowest_id
;
179 if (max_sessions
> max_range
) {
180 return NT_STATUS_INTERNAL_ERROR
;
183 table
= talloc_zero(conn
, struct smbXsrv_session_table
);
185 return NT_STATUS_NO_MEMORY
;
188 table
->local
.db_ctx
= db_open_rbt(table
);
189 if (table
->local
.db_ctx
== NULL
) {
191 return NT_STATUS_NO_MEMORY
;
193 table
->local
.lowest_id
= lowest_id
;
194 table
->local
.highest_id
= highest_id
;
195 table
->local
.max_sessions
= max_sessions
;
197 status
= smbXsrv_session_global_init();
198 if (!NT_STATUS_IS_OK(status
)) {
203 table
->global
.db_ctx
= smbXsrv_session_global_db_ctx
;
205 dbwrap_watch_db(table
->global
.db_ctx
, conn
->msg_ctx
);
207 subreq
= messaging_read_send(table
, conn
->ev_ctx
, conn
->msg_ctx
,
208 MSG_SMBXSRV_SESSION_CLOSE
);
209 if (subreq
== NULL
) {
211 return NT_STATUS_NO_MEMORY
;
213 tevent_req_set_callback(subreq
, smbXsrv_session_close_loop
, conn
);
215 conn
->session_table
= table
;
219 static void smbXsrv_session_close_loop(struct tevent_req
*subreq
)
221 struct smbXsrv_connection
*conn
=
222 tevent_req_callback_data(subreq
,
223 struct smbXsrv_connection
);
224 struct smbXsrv_session_table
*table
= conn
->session_table
;
226 struct messaging_rec
*rec
= NULL
;
227 struct smbXsrv_session_closeB close_blob
;
228 enum ndr_err_code ndr_err
;
229 struct smbXsrv_session_close0
*close_info0
= NULL
;
230 struct smbXsrv_session
*session
= NULL
;
232 struct timeval tv
= timeval_current();
233 NTTIME now
= timeval_to_nttime(&tv
);
235 ret
= messaging_read_recv(subreq
, talloc_tos(), &rec
);
241 ndr_err
= ndr_pull_struct_blob(&rec
->buf
, rec
, &close_blob
,
242 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_closeB
);
243 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
244 status
= ndr_map_error2ntstatus(ndr_err
);
245 DEBUG(1,("smbXsrv_session_close_loop: "
246 "ndr_pull_struct_blob - %s\n",
251 DEBUG(10,("smbXsrv_session_close_loop: MSG_SMBXSRV_SESSION_CLOSE\n"));
253 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
256 if (close_blob
.version
!= SMBXSRV_VERSION_0
) {
257 DEBUG(0,("smbXsrv_session_close_loop: "
258 "ignore invalid version %u\n", close_blob
.version
));
259 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
263 close_info0
= close_blob
.info
.info0
;
264 if (close_info0
== NULL
) {
265 DEBUG(0,("smbXsrv_session_close_loop: "
266 "ignore NULL info %u\n", close_blob
.version
));
267 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
271 status
= smb2srv_session_lookup(conn
, close_info0
->old_session_wire_id
,
273 if (NT_STATUS_EQUAL(status
, NT_STATUS_USER_SESSION_DELETED
)) {
274 DEBUG(4,("smbXsrv_session_close_loop: "
275 "old_session_wire_id %llu not found\n",
276 (unsigned long long)close_info0
->old_session_wire_id
));
278 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
282 if (!NT_STATUS_IS_OK(status
) &&
283 !NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
) &&
284 !NT_STATUS_EQUAL(status
, NT_STATUS_NETWORK_SESSION_EXPIRED
)) {
285 DEBUG(1,("smbXsrv_session_close_loop: "
286 "old_session_wire_id %llu - %s\n",
287 (unsigned long long)close_info0
->old_session_wire_id
,
290 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
295 if (session
->global
->session_global_id
!= close_info0
->old_session_global_id
) {
296 DEBUG(1,("smbXsrv_session_close_loop: "
297 "old_session_wire_id %llu - global %u != %u\n",
298 (unsigned long long)close_info0
->old_session_wire_id
,
299 session
->global
->session_global_id
,
300 close_info0
->old_session_global_id
));
302 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
307 if (session
->global
->creation_time
!= close_info0
->old_creation_time
) {
308 DEBUG(1,("smbXsrv_session_close_loop: "
309 "old_session_wire_id %llu - "
310 "creation %s (%llu) != %s (%llu)\n",
311 (unsigned long long)close_info0
->old_session_wire_id
,
312 nt_time_string(rec
, session
->global
->creation_time
),
313 (unsigned long long)session
->global
->creation_time
,
314 nt_time_string(rec
, close_info0
->old_creation_time
),
315 (unsigned long long)close_info0
->old_creation_time
));
317 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
323 * TODO: cancel all outstanding requests on the session
325 status
= smbXsrv_session_logoff(session
);
326 if (!NT_STATUS_IS_OK(status
)) {
327 DEBUG(0, ("smbXsrv_session_close_loop: "
328 "smbXsrv_session_logoff(%llu) failed: %s\n",
329 (unsigned long long)session
->global
->session_wire_id
,
332 NDR_PRINT_DEBUG(smbXsrv_session_closeB
, &close_blob
);
335 TALLOC_FREE(session
);
340 subreq
= messaging_read_send(table
, conn
->ev_ctx
, conn
->msg_ctx
,
341 MSG_SMBXSRV_SESSION_CLOSE
);
342 if (subreq
== NULL
) {
343 smbd_server_connection_terminate(conn
->sconn
,
344 "msg_read_send() failed");
347 tevent_req_set_callback(subreq
, smbXsrv_session_close_loop
, conn
);
350 struct smb1srv_session_local_allocate_state
{
351 const uint32_t lowest_id
;
352 const uint32_t highest_id
;
358 static int smb1srv_session_local_allocate_traverse(struct db_record
*rec
,
361 struct smb1srv_session_local_allocate_state
*state
=
362 (struct smb1srv_session_local_allocate_state
*)private_data
;
363 TDB_DATA key
= dbwrap_record_get_key(rec
);
367 status
= smbXsrv_session_local_key_to_id(key
, &id
);
368 if (!NT_STATUS_IS_OK(status
)) {
369 state
->status
= status
;
373 if (id
<= state
->last_id
) {
374 state
->status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
379 if (id
> state
->useable_id
) {
380 state
->status
= NT_STATUS_OK
;
384 if (state
->useable_id
== state
->highest_id
) {
385 state
->status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
389 state
->useable_id
+=1;
393 static NTSTATUS
smb1srv_session_local_allocate_id(struct db_context
*db
,
397 struct db_record
**_rec
,
400 struct smb1srv_session_local_allocate_state state
= {
401 .lowest_id
= lowest_id
,
402 .highest_id
= highest_id
,
404 .useable_id
= lowest_id
,
405 .status
= NT_STATUS_INTERNAL_ERROR
,
415 if (lowest_id
> highest_id
) {
416 return NT_STATUS_INSUFFICIENT_RESOURCES
;
420 * first we try randomly
422 range
= (highest_id
- lowest_id
) + 1;
424 for (i
= 0; i
< (range
/ 2); i
++) {
426 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
429 struct db_record
*rec
= NULL
;
431 id
= generate_random() % range
;
434 if (id
< lowest_id
) {
437 if (id
> highest_id
) {
441 key
= smbXsrv_session_local_id_to_key(id
, key_buf
);
443 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
445 return NT_STATUS_INSUFFICIENT_RESOURCES
;
448 val
= dbwrap_record_get_value(rec
);
449 if (val
.dsize
!= 0) {
460 * if the range is almost full,
461 * we traverse the whole table
462 * (this relies on sorted behavior of dbwrap_rbt)
464 status
= dbwrap_traverse_read(db
, smb1srv_session_local_allocate_traverse
,
466 if (NT_STATUS_IS_OK(status
)) {
467 if (NT_STATUS_IS_OK(state
.status
)) {
468 return NT_STATUS_INTERNAL_ERROR
;
471 if (!NT_STATUS_EQUAL(state
.status
, NT_STATUS_INTERNAL_ERROR
)) {
475 if (state
.useable_id
<= state
.highest_id
) {
476 state
.status
= NT_STATUS_OK
;
478 return NT_STATUS_INSUFFICIENT_RESOURCES
;
480 } else if (!NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_DB_CORRUPTION
)) {
482 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
484 * If we get anything else it is an error, because it
485 * means we did not manage to find a free slot in
488 return NT_STATUS_INSUFFICIENT_RESOURCES
;
491 if (NT_STATUS_IS_OK(state
.status
)) {
493 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
496 struct db_record
*rec
= NULL
;
498 id
= state
.useable_id
;
500 key
= smbXsrv_session_local_id_to_key(id
, key_buf
);
502 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
504 return NT_STATUS_INSUFFICIENT_RESOURCES
;
507 val
= dbwrap_record_get_value(rec
);
508 if (val
.dsize
!= 0) {
510 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
521 struct smbXsrv_session_local_fetch_state
{
522 struct smbXsrv_session
*session
;
526 static void smbXsrv_session_local_fetch_parser(TDB_DATA key
, TDB_DATA data
,
529 struct smbXsrv_session_local_fetch_state
*state
=
530 (struct smbXsrv_session_local_fetch_state
*)private_data
;
533 if (data
.dsize
!= sizeof(ptr
)) {
534 state
->status
= NT_STATUS_INTERNAL_DB_ERROR
;
538 memcpy(&ptr
, data
.dptr
, data
.dsize
);
539 state
->session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
540 state
->status
= NT_STATUS_OK
;
543 static NTSTATUS
smbXsrv_session_local_lookup(struct smbXsrv_session_table
*table
,
544 uint32_t session_local_id
,
546 struct smbXsrv_session
**_session
)
548 struct smbXsrv_session_local_fetch_state state
= {
550 .status
= NT_STATUS_INTERNAL_ERROR
,
552 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
558 if (session_local_id
== 0) {
559 return NT_STATUS_USER_SESSION_DELETED
;
563 /* this might happen before the end of negprot */
564 return NT_STATUS_USER_SESSION_DELETED
;
567 if (table
->local
.db_ctx
== NULL
) {
568 return NT_STATUS_INTERNAL_ERROR
;
571 key
= smbXsrv_session_local_id_to_key(session_local_id
, key_buf
);
573 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
574 smbXsrv_session_local_fetch_parser
,
576 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
577 return NT_STATUS_USER_SESSION_DELETED
;
578 } else if (!NT_STATUS_IS_OK(status
)) {
581 if (!NT_STATUS_IS_OK(state
.status
)) {
585 if (NT_STATUS_EQUAL(state
.session
->status
, NT_STATUS_USER_SESSION_DELETED
)) {
586 return NT_STATUS_USER_SESSION_DELETED
;
589 state
.session
->idle_time
= now
;
591 if (!NT_STATUS_IS_OK(state
.session
->status
)) {
592 *_session
= state
.session
;
593 return state
.session
->status
;
596 if (now
> state
.session
->global
->expiration_time
) {
597 state
.session
->status
= NT_STATUS_NETWORK_SESSION_EXPIRED
;
600 *_session
= state
.session
;
601 return state
.session
->status
;
604 static int smbXsrv_session_global_destructor(struct smbXsrv_session_global0
*global
)
609 static void smbXsrv_session_global_verify_record(struct db_record
*db_rec
,
613 struct smbXsrv_session_global0
**_g
);
615 static NTSTATUS
smbXsrv_session_global_allocate(struct db_context
*db
,
617 struct smbXsrv_session_global0
**_global
)
620 struct smbXsrv_session_global0
*global
= NULL
;
621 uint32_t last_free
= 0;
622 const uint32_t min_tries
= 3;
626 global
= talloc_zero(mem_ctx
, struct smbXsrv_session_global0
);
627 if (global
== NULL
) {
628 return NT_STATUS_NO_MEMORY
;
630 talloc_set_destructor(global
, smbXsrv_session_global_destructor
);
633 * Here we just randomly try the whole 32-bit space
635 * We use just 32-bit, because we want to reuse the
638 for (i
= 0; i
< UINT32_MAX
; i
++) {
639 bool is_free
= false;
640 bool was_free
= false;
642 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
645 if (i
>= min_tries
&& last_free
!= 0) {
648 id
= generate_random();
653 if (id
== UINT32_MAX
) {
657 key
= smbXsrv_session_global_id_to_key(id
, key_buf
);
659 global
->db_rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
660 if (global
->db_rec
== NULL
) {
662 return NT_STATUS_INSUFFICIENT_RESOURCES
;
665 smbXsrv_session_global_verify_record(global
->db_rec
,
671 TALLOC_FREE(global
->db_rec
);
675 if (!was_free
&& i
< min_tries
) {
677 * The session_id is free now,
678 * but was not free before.
680 * This happens if a smbd crashed
681 * and did not cleanup the record.
683 * If this is one of our first tries,
684 * then we try to find a real free one.
686 if (last_free
== 0) {
689 TALLOC_FREE(global
->db_rec
);
693 global
->session_global_id
= id
;
699 /* should not be reached */
701 return NT_STATUS_INTERNAL_ERROR
;
704 static void smbXsrv_session_global_verify_record(struct db_record
*db_rec
,
708 struct smbXsrv_session_global0
**_g
)
713 struct smbXsrv_session_globalB global_blob
;
714 enum ndr_err_code ndr_err
;
715 struct smbXsrv_session_global0
*global
= NULL
;
717 TALLOC_CTX
*frame
= talloc_stackframe();
728 key
= dbwrap_record_get_key(db_rec
);
730 val
= dbwrap_record_get_value(db_rec
);
731 if (val
.dsize
== 0) {
740 blob
= data_blob_const(val
.dptr
, val
.dsize
);
742 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
743 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_globalB
);
744 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
745 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
746 DEBUG(1,("smbXsrv_session_global_verify_record: "
747 "key '%s' ndr_pull_struct_blob - %s\n",
748 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
754 DEBUG(10,("smbXsrv_session_global_verify_record\n"));
756 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
759 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
760 DEBUG(0,("smbXsrv_session_global_verify_record: "
761 "key '%s' use unsupported version %u\n",
762 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
763 global_blob
.version
));
764 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
769 global
= global_blob
.info
.info0
;
771 exists
= serverid_exists(&global
->channels
[0].server_id
);
773 DEBUG(2,("smbXsrv_session_global_verify_record: "
774 "key '%s' server_id %s does not exist.\n",
775 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
776 server_id_str(frame
, &global
->channels
[0].server_id
)));
778 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
781 dbwrap_record_delete(db_rec
);
787 *_g
= talloc_move(mem_ctx
, &global
);
792 static NTSTATUS
smbXsrv_session_global_store(struct smbXsrv_session_global0
*global
)
794 struct smbXsrv_session_globalB global_blob
;
795 DATA_BLOB blob
= data_blob_null
;
799 enum ndr_err_code ndr_err
;
802 * TODO: if we use other versions than '0'
803 * we would add glue code here, that would be able to
804 * store the information in the old format.
807 if (global
->db_rec
== NULL
) {
808 return NT_STATUS_INTERNAL_ERROR
;
811 key
= dbwrap_record_get_key(global
->db_rec
);
812 val
= dbwrap_record_get_value(global
->db_rec
);
814 ZERO_STRUCT(global_blob
);
815 global_blob
.version
= smbXsrv_version_global_current();
816 if (val
.dsize
>= 8) {
817 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
819 global_blob
.seqnum
+= 1;
820 global_blob
.info
.info0
= global
;
822 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
823 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_session_globalB
);
824 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
825 status
= ndr_map_error2ntstatus(ndr_err
);
826 DEBUG(1,("smbXsrv_session_global_store: key '%s' ndr_push - %s\n",
827 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
829 TALLOC_FREE(global
->db_rec
);
833 val
= make_tdb_data(blob
.data
, blob
.length
);
834 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
835 if (!NT_STATUS_IS_OK(status
)) {
836 DEBUG(1,("smbXsrv_session_global_store: key '%s' store - %s\n",
837 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
839 TALLOC_FREE(global
->db_rec
);
844 DEBUG(10,("smbXsrv_session_global_store: key '%s' stored\n",
845 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
)));
846 NDR_PRINT_DEBUG(smbXsrv_session_globalB
, &global_blob
);
849 TALLOC_FREE(global
->db_rec
);
854 struct smb2srv_session_close_previous_state
{
855 struct tevent_context
*ev
;
856 struct smbXsrv_connection
*connection
;
857 struct dom_sid
*current_sid
;
858 uint64_t current_session_id
;
859 struct db_record
*db_rec
;
862 static void smb2srv_session_close_previous_check(struct tevent_req
*req
);
863 static void smb2srv_session_close_previous_modified(struct tevent_req
*subreq
);
865 struct tevent_req
*smb2srv_session_close_previous_send(TALLOC_CTX
*mem_ctx
,
866 struct tevent_context
*ev
,
867 struct smbXsrv_connection
*conn
,
868 struct auth_session_info
*session_info
,
869 uint64_t previous_session_id
,
870 uint64_t current_session_id
)
872 struct tevent_req
*req
;
873 struct smb2srv_session_close_previous_state
*state
;
874 uint32_t global_id
= previous_session_id
& UINT32_MAX
;
875 uint64_t global_zeros
= previous_session_id
& 0xFFFFFFFF00000000LLU
;
876 struct smbXsrv_session_table
*table
= conn
->session_table
;
877 struct security_token
*current_token
= NULL
;
878 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
881 req
= tevent_req_create(mem_ctx
, &state
,
882 struct smb2srv_session_close_previous_state
);
887 state
->connection
= conn
;
888 state
->current_session_id
= current_session_id
;
890 if (global_zeros
!= 0) {
891 tevent_req_done(req
);
892 return tevent_req_post(req
, ev
);
895 if (session_info
== NULL
) {
896 tevent_req_done(req
);
897 return tevent_req_post(req
, ev
);
899 current_token
= session_info
->security_token
;
901 if (current_token
->num_sids
> PRIMARY_USER_SID_INDEX
) {
902 state
->current_sid
= ¤t_token
->sids
[PRIMARY_USER_SID_INDEX
];
905 if (state
->current_sid
== NULL
) {
906 tevent_req_done(req
);
907 return tevent_req_post(req
, ev
);
910 if (!security_token_has_nt_authenticated_users(current_token
)) {
912 tevent_req_done(req
);
913 return tevent_req_post(req
, ev
);
916 key
= smbXsrv_session_global_id_to_key(global_id
, key_buf
);
918 state
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
920 if (state
->db_rec
== NULL
) {
921 tevent_req_nterror(req
, NT_STATUS_UNSUCCESSFUL
);
922 return tevent_req_post(req
, ev
);
925 smb2srv_session_close_previous_check(req
);
926 if (!tevent_req_is_in_progress(req
)) {
927 return tevent_req_post(req
, ev
);
933 static void smb2srv_session_close_previous_check(struct tevent_req
*req
)
935 struct smb2srv_session_close_previous_state
*state
=
937 struct smb2srv_session_close_previous_state
);
938 struct smbXsrv_connection
*conn
= state
->connection
;
940 struct security_token
*previous_token
= NULL
;
941 struct smbXsrv_session_global0
*global
= NULL
;
942 enum ndr_err_code ndr_err
;
943 struct smbXsrv_session_close0 close_info0
;
944 struct smbXsrv_session_closeB close_blob
;
945 struct tevent_req
*subreq
= NULL
;
947 bool is_free
= false;
949 smbXsrv_session_global_verify_record(state
->db_rec
,
956 TALLOC_FREE(state
->db_rec
);
957 tevent_req_done(req
);
961 if (global
->auth_session_info
== NULL
) {
962 TALLOC_FREE(state
->db_rec
);
963 tevent_req_done(req
);
967 previous_token
= global
->auth_session_info
->security_token
;
969 if (!security_token_is_sid(previous_token
, state
->current_sid
)) {
970 TALLOC_FREE(state
->db_rec
);
971 tevent_req_done(req
);
975 subreq
= dbwrap_record_watch_send(state
, state
->ev
,
976 state
->db_rec
, conn
->msg_ctx
);
977 if (tevent_req_nomem(subreq
, req
)) {
978 TALLOC_FREE(state
->db_rec
);
981 tevent_req_set_callback(subreq
,
982 smb2srv_session_close_previous_modified
,
985 close_info0
.old_session_global_id
= global
->session_global_id
;
986 close_info0
.old_session_wire_id
= global
->session_wire_id
;
987 close_info0
.old_creation_time
= global
->creation_time
;
988 close_info0
.new_session_wire_id
= state
->current_session_id
;
990 ZERO_STRUCT(close_blob
);
991 close_blob
.version
= smbXsrv_version_global_current();
992 close_blob
.info
.info0
= &close_info0
;
994 ndr_err
= ndr_push_struct_blob(&blob
, state
, &close_blob
,
995 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_session_closeB
);
996 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
997 TALLOC_FREE(state
->db_rec
);
998 status
= ndr_map_error2ntstatus(ndr_err
);
999 DEBUG(1,("smb2srv_session_close_previous_check: "
1000 "old_session[%llu] new_session[%llu] ndr_push - %s\n",
1001 (unsigned long long)close_info0
.old_session_wire_id
,
1002 (unsigned long long)close_info0
.new_session_wire_id
,
1003 nt_errstr(status
)));
1004 tevent_req_nterror(req
, status
);
1008 status
= messaging_send(conn
->msg_ctx
,
1009 global
->channels
[0].server_id
,
1010 MSG_SMBXSRV_SESSION_CLOSE
, &blob
);
1011 TALLOC_FREE(state
->db_rec
);
1012 if (tevent_req_nterror(req
, status
)) {
1016 TALLOC_FREE(global
);
1020 static void smb2srv_session_close_previous_modified(struct tevent_req
*subreq
)
1022 struct tevent_req
*req
=
1023 tevent_req_callback_data(subreq
,
1025 struct smb2srv_session_close_previous_state
*state
=
1026 tevent_req_data(req
,
1027 struct smb2srv_session_close_previous_state
);
1030 status
= dbwrap_record_watch_recv(subreq
, state
, &state
->db_rec
);
1031 TALLOC_FREE(subreq
);
1032 if (tevent_req_nterror(req
, status
)) {
1036 smb2srv_session_close_previous_check(req
);
1039 NTSTATUS
smb2srv_session_close_previous_recv(struct tevent_req
*req
)
1043 if (tevent_req_is_nterror(req
, &status
)) {
1044 tevent_req_received(req
);
1048 tevent_req_received(req
);
1049 return NT_STATUS_OK
;
1052 static int smbXsrv_session_destructor(struct smbXsrv_session
*session
)
1056 status
= smbXsrv_session_logoff(session
);
1057 if (!NT_STATUS_IS_OK(status
)) {
1058 DEBUG(0, ("smbXsrv_session_destructor: "
1059 "smbXsrv_session_logoff() failed: %s\n",
1060 nt_errstr(status
)));
1063 TALLOC_FREE(session
->global
);
1068 NTSTATUS
smbXsrv_session_create(struct smbXsrv_connection
*conn
,
1070 struct smbXsrv_session
**_session
)
1072 struct smbXsrv_session_table
*table
= conn
->session_table
;
1073 struct db_record
*local_rec
= NULL
;
1074 struct smbXsrv_session
*session
= NULL
;
1077 struct smbXsrv_session_global0
*global
= NULL
;
1078 struct smbXsrv_channel_global0
*channels
= NULL
;
1081 if (table
->local
.num_sessions
>= table
->local
.max_sessions
) {
1082 return NT_STATUS_INSUFFICIENT_RESOURCES
;
1085 session
= talloc_zero(table
, struct smbXsrv_session
);
1086 if (session
== NULL
) {
1087 return NT_STATUS_NO_MEMORY
;
1089 session
->table
= table
;
1090 session
->idle_time
= now
;
1091 session
->status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
1092 session
->connection
= conn
;
1094 status
= smbXsrv_session_global_allocate(table
->global
.db_ctx
,
1097 if (!NT_STATUS_IS_OK(status
)) {
1098 TALLOC_FREE(session
);
1101 session
->global
= global
;
1103 if (conn
->protocol
>= PROTOCOL_SMB2_02
) {
1104 uint64_t id
= global
->session_global_id
;
1105 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
1108 global
->connection_dialect
= conn
->smb2
.server
.dialect
;
1110 global
->session_wire_id
= id
;
1112 status
= smb2srv_tcon_table_init(session
);
1113 if (!NT_STATUS_IS_OK(status
)) {
1114 TALLOC_FREE(session
);
1118 session
->local_id
= global
->session_global_id
;
1120 key
= smbXsrv_session_local_id_to_key(session
->local_id
, key_buf
);
1122 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
1124 if (local_rec
== NULL
) {
1125 TALLOC_FREE(session
);
1126 return NT_STATUS_NO_MEMORY
;
1129 val
= dbwrap_record_get_value(local_rec
);
1130 if (val
.dsize
!= 0) {
1131 TALLOC_FREE(session
);
1132 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
1136 status
= smb1srv_session_local_allocate_id(table
->local
.db_ctx
,
1137 table
->local
.lowest_id
,
1138 table
->local
.highest_id
,
1141 &session
->local_id
);
1142 if (!NT_STATUS_IS_OK(status
)) {
1143 TALLOC_FREE(session
);
1147 global
->session_wire_id
= session
->local_id
;
1150 global
->creation_time
= now
;
1151 global
->expiration_time
= GENSEC_EXPIRE_TIME_INFINITY
;
1153 global
->num_channels
= 1;
1154 channels
= talloc_zero_array(global
,
1155 struct smbXsrv_channel_global0
,
1156 global
->num_channels
);
1157 if (channels
== NULL
) {
1158 TALLOC_FREE(session
);
1159 return NT_STATUS_NO_MEMORY
;
1161 global
->channels
= channels
;
1163 channels
[0].server_id
= messaging_server_id(conn
->msg_ctx
);
1164 channels
[0].local_address
= tsocket_address_string(conn
->local_address
,
1166 if (channels
[0].local_address
== NULL
) {
1167 TALLOC_FREE(session
);
1168 return NT_STATUS_NO_MEMORY
;
1170 channels
[0].remote_address
= tsocket_address_string(conn
->remote_address
,
1172 if (channels
[0].remote_address
== NULL
) {
1173 TALLOC_FREE(session
);
1174 return NT_STATUS_NO_MEMORY
;
1176 channels
[0].remote_name
= talloc_strdup(channels
, conn
->remote_hostname
);
1177 if (channels
[0].remote_name
== NULL
) {
1178 TALLOC_FREE(session
);
1179 return NT_STATUS_NO_MEMORY
;
1181 channels
[0].signing_key
= data_blob_null
;
1184 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
1185 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
1186 TALLOC_FREE(local_rec
);
1187 if (!NT_STATUS_IS_OK(status
)) {
1188 TALLOC_FREE(session
);
1191 table
->local
.num_sessions
+= 1;
1193 talloc_set_destructor(session
, smbXsrv_session_destructor
);
1195 status
= smbXsrv_session_global_store(global
);
1196 if (!NT_STATUS_IS_OK(status
)) {
1197 DEBUG(0,("smbXsrv_session_create: "
1198 "global_id (0x%08x) store failed - %s\n",
1199 session
->global
->session_global_id
,
1200 nt_errstr(status
)));
1201 TALLOC_FREE(session
);
1206 struct smbXsrv_sessionB session_blob
;
1208 ZERO_STRUCT(session_blob
);
1209 session_blob
.version
= SMBXSRV_VERSION_0
;
1210 session_blob
.info
.info0
= session
;
1212 DEBUG(10,("smbXsrv_session_create: global_id (0x%08x) stored\n",
1213 session
->global
->session_global_id
));
1214 NDR_PRINT_DEBUG(smbXsrv_sessionB
, &session_blob
);
1217 *_session
= session
;
1218 return NT_STATUS_OK
;
1221 NTSTATUS
smbXsrv_session_update(struct smbXsrv_session
*session
)
1223 struct smbXsrv_session_table
*table
= session
->table
;
1225 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
1228 if (session
->global
->db_rec
!= NULL
) {
1229 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1230 "Called with db_rec != NULL'\n",
1231 session
->global
->session_global_id
));
1232 return NT_STATUS_INTERNAL_ERROR
;
1235 key
= smbXsrv_session_global_id_to_key(
1236 session
->global
->session_global_id
,
1239 session
->global
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
1240 session
->global
, key
);
1241 if (session
->global
->db_rec
== NULL
) {
1242 DEBUG(0, ("smbXsrv_session_update(0x%08x): "
1243 "Failed to lock global key '%s'\n",
1244 session
->global
->session_global_id
,
1245 hex_encode_talloc(talloc_tos(), key
.dptr
,
1247 return NT_STATUS_INTERNAL_DB_ERROR
;
1250 status
= smbXsrv_session_global_store(session
->global
);
1251 if (!NT_STATUS_IS_OK(status
)) {
1252 DEBUG(0,("smbXsrv_session_update: "
1253 "global_id (0x%08x) store failed - %s\n",
1254 session
->global
->session_global_id
,
1255 nt_errstr(status
)));
1260 struct smbXsrv_sessionB session_blob
;
1262 ZERO_STRUCT(session_blob
);
1263 session_blob
.version
= SMBXSRV_VERSION_0
;
1264 session_blob
.info
.info0
= session
;
1266 DEBUG(10,("smbXsrv_session_update: global_id (0x%08x) stored\n",
1267 session
->global
->session_global_id
));
1268 NDR_PRINT_DEBUG(smbXsrv_sessionB
, &session_blob
);
1271 return NT_STATUS_OK
;
1274 NTSTATUS
smbXsrv_session_logoff(struct smbXsrv_session
*session
)
1276 struct smbXsrv_session_table
*table
;
1277 struct db_record
*local_rec
= NULL
;
1278 struct db_record
*global_rec
= NULL
;
1279 struct smbXsrv_connection
*conn
;
1281 NTSTATUS error
= NT_STATUS_OK
;
1283 if (session
->table
== NULL
) {
1284 return NT_STATUS_OK
;
1287 table
= session
->table
;
1288 session
->table
= NULL
;
1290 conn
= session
->connection
;
1291 session
->connection
= NULL
;
1292 session
->status
= NT_STATUS_USER_SESSION_DELETED
;
1294 global_rec
= session
->global
->db_rec
;
1295 session
->global
->db_rec
= NULL
;
1296 if (global_rec
== NULL
) {
1297 uint8_t key_buf
[SMBXSRV_SESSION_GLOBAL_TDB_KEY_SIZE
];
1300 key
= smbXsrv_session_global_id_to_key(
1301 session
->global
->session_global_id
,
1304 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
1305 session
->global
, key
);
1306 if (global_rec
== NULL
) {
1307 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1308 "Failed to lock global key '%s'\n",
1309 session
->global
->session_global_id
,
1310 hex_encode_talloc(global_rec
, key
.dptr
,
1312 error
= NT_STATUS_INTERNAL_ERROR
;
1316 if (global_rec
!= NULL
) {
1317 status
= dbwrap_record_delete(global_rec
);
1318 if (!NT_STATUS_IS_OK(status
)) {
1319 TDB_DATA key
= dbwrap_record_get_key(global_rec
);
1321 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1322 "failed to delete global key '%s': %s\n",
1323 session
->global
->session_global_id
,
1324 hex_encode_talloc(global_rec
, key
.dptr
,
1326 nt_errstr(status
)));
1330 TALLOC_FREE(global_rec
);
1332 local_rec
= session
->db_rec
;
1333 if (local_rec
== NULL
) {
1334 uint8_t key_buf
[SMBXSRV_SESSION_LOCAL_TDB_KEY_SIZE
];
1337 key
= smbXsrv_session_local_id_to_key(session
->local_id
,
1340 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
1342 if (local_rec
== NULL
) {
1343 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1344 "Failed to lock local key '%s'\n",
1345 session
->global
->session_global_id
,
1346 hex_encode_talloc(local_rec
, key
.dptr
,
1348 error
= NT_STATUS_INTERNAL_ERROR
;
1352 if (local_rec
!= NULL
) {
1353 status
= dbwrap_record_delete(local_rec
);
1354 if (!NT_STATUS_IS_OK(status
)) {
1355 TDB_DATA key
= dbwrap_record_get_key(local_rec
);
1357 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1358 "failed to delete local key '%s': %s\n",
1359 session
->global
->session_global_id
,
1360 hex_encode_talloc(local_rec
, key
.dptr
,
1362 nt_errstr(status
)));
1365 table
->local
.num_sessions
-= 1;
1367 if (session
->db_rec
== NULL
) {
1368 TALLOC_FREE(local_rec
);
1370 session
->db_rec
= NULL
;
1372 if (session
->compat
) {
1373 file_close_user(conn
->sconn
, session
->compat
->vuid
);
1376 if (conn
->protocol
>= PROTOCOL_SMB2_02
) {
1377 status
= smb2srv_tcon_disconnect_all(session
);
1378 if (!NT_STATUS_IS_OK(status
)) {
1379 DEBUG(0, ("smbXsrv_session_logoff(0x%08x): "
1380 "smb2srv_tcon_disconnect_all() failed: %s\n",
1381 session
->global
->session_global_id
,
1382 nt_errstr(status
)));
1387 if (session
->compat
) {
1388 invalidate_vuid(conn
->sconn
, session
->compat
->vuid
);
1389 session
->compat
= NULL
;
1395 struct smbXsrv_session_logoff_all_state
{
1396 NTSTATUS first_status
;
1400 static int smbXsrv_session_logoff_all_callback(struct db_record
*local_rec
,
1401 void *private_data
);
1403 NTSTATUS
smbXsrv_session_logoff_all(struct smbXsrv_connection
*conn
)
1405 struct smbXsrv_session_table
*table
= conn
->session_table
;
1406 struct smbXsrv_session_logoff_all_state state
;
1410 if (table
== NULL
) {
1411 DEBUG(10, ("smbXsrv_session_logoff_all: "
1412 "empty session_table, nothing to do.\n"));
1413 return NT_STATUS_OK
;
1418 status
= dbwrap_traverse(table
->local
.db_ctx
,
1419 smbXsrv_session_logoff_all_callback
,
1421 if (!NT_STATUS_IS_OK(status
)) {
1422 DEBUG(0, ("smbXsrv_session_logoff_all: "
1423 "dbwrap_traverse() failed: %s\n",
1424 nt_errstr(status
)));
1428 if (!NT_STATUS_IS_OK(state
.first_status
)) {
1429 DEBUG(0, ("smbXsrv_session_logoff_all: "
1430 "count[%d] errors[%d] first[%s]\n",
1431 count
, state
.errors
,
1432 nt_errstr(state
.first_status
)));
1433 return state
.first_status
;
1436 return NT_STATUS_OK
;
1439 static int smbXsrv_session_logoff_all_callback(struct db_record
*local_rec
,
1442 struct smbXsrv_session_logoff_all_state
*state
=
1443 (struct smbXsrv_session_logoff_all_state
*)private_data
;
1446 struct smbXsrv_session
*session
= NULL
;
1449 val
= dbwrap_record_get_value(local_rec
);
1450 if (val
.dsize
!= sizeof(ptr
)) {
1451 status
= NT_STATUS_INTERNAL_ERROR
;
1452 if (NT_STATUS_IS_OK(state
->first_status
)) {
1453 state
->first_status
= status
;
1459 memcpy(&ptr
, val
.dptr
, val
.dsize
);
1460 session
= talloc_get_type_abort(ptr
, struct smbXsrv_session
);
1462 session
->db_rec
= local_rec
;
1463 status
= smbXsrv_session_logoff(session
);
1464 if (!NT_STATUS_IS_OK(status
)) {
1465 if (NT_STATUS_IS_OK(state
->first_status
)) {
1466 state
->first_status
= status
;
1475 NTSTATUS
smb1srv_session_table_init(struct smbXsrv_connection
*conn
)
1478 * Allow a range from 1..65534 with 65534 values.
1480 return smbXsrv_session_table_init(conn
, 1, UINT16_MAX
- 1,
1484 NTSTATUS
smb1srv_session_lookup(struct smbXsrv_connection
*conn
,
1485 uint16_t vuid
, NTTIME now
,
1486 struct smbXsrv_session
**session
)
1488 struct smbXsrv_session_table
*table
= conn
->session_table
;
1489 uint32_t local_id
= vuid
;
1491 return smbXsrv_session_local_lookup(table
, local_id
, now
, session
);
1494 NTSTATUS
smb2srv_session_table_init(struct smbXsrv_connection
*conn
)
1497 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1499 return smbXsrv_session_table_init(conn
, 1, UINT32_MAX
- 1,
1503 NTSTATUS
smb2srv_session_lookup(struct smbXsrv_connection
*conn
,
1504 uint64_t session_id
, NTTIME now
,
1505 struct smbXsrv_session
**session
)
1507 struct smbXsrv_session_table
*table
= conn
->session_table
;
1508 uint32_t local_id
= session_id
& UINT32_MAX
;
1509 uint64_t local_zeros
= session_id
& 0xFFFFFFFF00000000LLU
;
1511 if (local_zeros
!= 0) {
1512 return NT_STATUS_USER_SESSION_DELETED
;
1515 return smbXsrv_session_local_lookup(table
, local_id
, now
, session
);
1518 struct smbXsrv_session_global_traverse_state
{
1519 int (*fn
)(struct smbXsrv_session_global0
*, void *);
1523 static int smbXsrv_session_global_traverse_fn(struct db_record
*rec
, void *data
)
1526 struct smbXsrv_session_global_traverse_state
*state
=
1527 (struct smbXsrv_session_global_traverse_state
*)data
;
1528 TDB_DATA key
= dbwrap_record_get_key(rec
);
1529 TDB_DATA val
= dbwrap_record_get_value(rec
);
1530 DATA_BLOB blob
= data_blob_const(val
.dptr
, val
.dsize
);
1531 struct smbXsrv_session_globalB global_blob
;
1532 enum ndr_err_code ndr_err
;
1533 TALLOC_CTX
*frame
= talloc_stackframe();
1535 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
1536 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_session_globalB
);
1537 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1538 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1539 "key '%s' ndr_pull_struct_blob - %s\n",
1540 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1541 ndr_errstr(ndr_err
)));
1545 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
1546 DEBUG(1,("Invalid record in smbXsrv_session_global.tdb:"
1547 "key '%s' unsuported version - %d\n",
1548 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1549 (int)global_blob
.version
));
1553 global_blob
.info
.info0
->db_rec
= rec
;
1554 ret
= state
->fn(global_blob
.info
.info0
, state
->private_data
);
1560 NTSTATUS
smbXsrv_session_global_traverse(
1561 int (*fn
)(struct smbXsrv_session_global0
*, void *),
1567 struct smbXsrv_session_global_traverse_state state
= {
1569 .private_data
= private_data
,
1573 status
= smbXsrv_session_global_init();
1574 if (!NT_STATUS_IS_OK(status
)) {
1576 DEBUG(0, ("Failed to initialize session_global: %s\n",
1577 nt_errstr(status
)));
1581 status
= dbwrap_traverse_read(smbXsrv_session_global_db_ctx
,
1582 smbXsrv_session_global_traverse_fn
,