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"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25 #include "dbwrap/dbwrap.h"
26 #include "dbwrap/dbwrap_rbt.h"
27 #include "dbwrap/dbwrap_open.h"
29 #include "lib/util/util_tdb.h"
30 #include "librpc/gen_ndr/ndr_smbXsrv.h"
33 struct smbXsrv_tcon_table
{
35 struct db_context
*db_ctx
;
42 struct db_context
*db_ctx
;
46 static struct db_context
*smbXsrv_tcon_global_db_ctx
= NULL
;
48 NTSTATUS
smbXsrv_tcon_global_init(void)
50 const char *global_path
= NULL
;
51 struct db_context
*db_ctx
= NULL
;
53 if (smbXsrv_tcon_global_db_ctx
!= NULL
) {
57 global_path
= lock_path("smbXsrv_tcon_global.tdb");
59 db_ctx
= db_open(NULL
, global_path
,
63 TDB_INCOMPATIBLE_HASH
,
64 O_RDWR
| O_CREAT
, 0600,
69 status
= map_nt_error_from_unix_common(errno
);
74 smbXsrv_tcon_global_db_ctx
= db_ctx
;
81 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
82 * has the same result as integer comparison between the uint32_t
85 * TODO: implement string based key
88 #define SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
90 static TDB_DATA
smbXsrv_tcon_global_id_to_key(uint32_t id
,
95 RSIVAL(key_buf
, 0, id
);
97 key
= make_tdb_data(key_buf
, SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
);
103 static NTSTATUS
smbXsrv_tcon_global_key_to_id(TDB_DATA key
, uint32_t *id
)
106 return NT_STATUS_INVALID_PARAMETER
;
109 if (key
.dsize
!= SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
) {
110 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
113 *id
= RIVAL(key
.dptr
, 0);
119 #define SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
121 static TDB_DATA
smbXsrv_tcon_local_id_to_key(uint32_t id
,
126 RSIVAL(key_buf
, 0, id
);
128 key
= make_tdb_data(key_buf
, SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
);
133 static NTSTATUS
smbXsrv_tcon_local_key_to_id(TDB_DATA key
, uint32_t *id
)
136 return NT_STATUS_INVALID_PARAMETER
;
139 if (key
.dsize
!= SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
) {
140 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
143 *id
= RIVAL(key
.dptr
, 0);
148 static NTSTATUS
smbXsrv_tcon_table_init(TALLOC_CTX
*mem_ctx
,
149 struct smbXsrv_tcon_table
*table
,
157 if (lowest_id
> highest_id
) {
158 return NT_STATUS_INTERNAL_ERROR
;
161 max_range
= highest_id
;
162 max_range
-= lowest_id
;
165 if (max_tcons
> max_range
) {
166 return NT_STATUS_INTERNAL_ERROR
;
170 table
->local
.db_ctx
= db_open_rbt(table
);
171 if (table
->local
.db_ctx
== NULL
) {
172 return NT_STATUS_NO_MEMORY
;
174 table
->local
.lowest_id
= lowest_id
;
175 table
->local
.highest_id
= highest_id
;
176 table
->local
.max_tcons
= max_tcons
;
178 status
= smbXsrv_tcon_global_init();
179 if (!NT_STATUS_IS_OK(status
)) {
183 table
->global
.db_ctx
= smbXsrv_tcon_global_db_ctx
;
188 struct smb1srv_tcon_local_allocate_state
{
189 const uint32_t lowest_id
;
190 const uint32_t highest_id
;
196 static int smb1srv_tcon_local_allocate_traverse(struct db_record
*rec
,
199 struct smb1srv_tcon_local_allocate_state
*state
=
200 (struct smb1srv_tcon_local_allocate_state
*)private_data
;
201 TDB_DATA key
= dbwrap_record_get_key(rec
);
205 status
= smbXsrv_tcon_local_key_to_id(key
, &id
);
206 if (!NT_STATUS_IS_OK(status
)) {
207 state
->status
= status
;
211 if (id
<= state
->last_id
) {
212 state
->status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
217 if (id
> state
->useable_id
) {
218 state
->status
= NT_STATUS_OK
;
222 if (state
->useable_id
== state
->highest_id
) {
223 state
->status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
227 state
->useable_id
+=1;
231 static NTSTATUS
smb1srv_tcon_local_allocate_id(struct db_context
*db
,
235 struct db_record
**_rec
,
238 struct smb1srv_tcon_local_allocate_state state
= {
239 .lowest_id
= lowest_id
,
240 .highest_id
= highest_id
,
242 .useable_id
= lowest_id
,
243 .status
= NT_STATUS_INTERNAL_ERROR
,
253 if (lowest_id
> highest_id
) {
254 return NT_STATUS_INSUFFICIENT_RESOURCES
;
258 * first we try randomly
260 range
= (highest_id
- lowest_id
) + 1;
262 for (i
= 0; i
< (range
/ 2); i
++) {
264 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
267 struct db_record
*rec
= NULL
;
269 id
= generate_random() % range
;
272 if (id
< lowest_id
) {
275 if (id
> highest_id
) {
279 key
= smbXsrv_tcon_local_id_to_key(id
, key_buf
);
281 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
283 return NT_STATUS_INSUFFICIENT_RESOURCES
;
286 val
= dbwrap_record_get_value(rec
);
287 if (val
.dsize
!= 0) {
298 * if the range is almost full,
299 * we traverse the whole table
300 * (this relies on sorted behavior of dbwrap_rbt)
302 status
= dbwrap_traverse_read(db
, smb1srv_tcon_local_allocate_traverse
,
304 if (NT_STATUS_IS_OK(status
)) {
305 if (NT_STATUS_IS_OK(state
.status
)) {
306 return NT_STATUS_INTERNAL_ERROR
;
309 if (!NT_STATUS_EQUAL(state
.status
, NT_STATUS_INTERNAL_ERROR
)) {
313 if (state
.useable_id
<= state
.highest_id
) {
314 state
.status
= NT_STATUS_OK
;
316 return NT_STATUS_INSUFFICIENT_RESOURCES
;
318 } else if (!NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_DB_CORRUPTION
)) {
320 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
322 * If we get anything else it is an error, because it
323 * means we did not manage to find a free slot in
326 return NT_STATUS_INSUFFICIENT_RESOURCES
;
329 if (NT_STATUS_IS_OK(state
.status
)) {
331 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
334 struct db_record
*rec
= NULL
;
336 id
= state
.useable_id
;
338 key
= smbXsrv_tcon_local_id_to_key(id
, key_buf
);
340 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
342 return NT_STATUS_INSUFFICIENT_RESOURCES
;
345 val
= dbwrap_record_get_value(rec
);
346 if (val
.dsize
!= 0) {
348 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
359 struct smbXsrv_tcon_local_fetch_state
{
360 struct smbXsrv_tcon
*tcon
;
364 static void smbXsrv_tcon_local_fetch_parser(TDB_DATA key
, TDB_DATA data
,
367 struct smbXsrv_tcon_local_fetch_state
*state
=
368 (struct smbXsrv_tcon_local_fetch_state
*)private_data
;
371 if (data
.dsize
!= sizeof(ptr
)) {
372 state
->status
= NT_STATUS_INTERNAL_DB_ERROR
;
376 memcpy(&ptr
, data
.dptr
, data
.dsize
);
377 state
->tcon
= talloc_get_type_abort(ptr
, struct smbXsrv_tcon
);
378 state
->status
= NT_STATUS_OK
;
381 static NTSTATUS
smbXsrv_tcon_local_lookup(struct smbXsrv_tcon_table
*table
,
382 uint32_t tcon_local_id
,
384 struct smbXsrv_tcon
**_tcon
)
386 struct smbXsrv_tcon_local_fetch_state state
= {
388 .status
= NT_STATUS_INTERNAL_ERROR
,
390 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
396 if (tcon_local_id
== 0) {
397 return NT_STATUS_NETWORK_NAME_DELETED
;
401 /* this might happen before the end of negprot */
402 return NT_STATUS_NETWORK_NAME_DELETED
;
405 if (table
->local
.db_ctx
== NULL
) {
406 return NT_STATUS_INTERNAL_ERROR
;
409 key
= smbXsrv_tcon_local_id_to_key(tcon_local_id
, key_buf
);
411 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
412 smbXsrv_tcon_local_fetch_parser
,
414 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
415 return NT_STATUS_NETWORK_NAME_DELETED
;
416 } else if (!NT_STATUS_IS_OK(status
)) {
419 if (!NT_STATUS_IS_OK(state
.status
)) {
423 if (NT_STATUS_EQUAL(state
.tcon
->status
, NT_STATUS_NETWORK_NAME_DELETED
)) {
424 return NT_STATUS_NETWORK_NAME_DELETED
;
427 state
.tcon
->idle_time
= now
;
430 return state
.tcon
->status
;
433 static int smbXsrv_tcon_global_destructor(struct smbXsrv_tcon_global0
*global
)
438 static void smbXsrv_tcon_global_verify_record(struct db_record
*db_rec
,
442 struct smbXsrv_tcon_global0
**_g
);
444 static NTSTATUS
smbXsrv_tcon_global_allocate(struct db_context
*db
,
446 struct smbXsrv_tcon_global0
**_global
)
449 struct smbXsrv_tcon_global0
*global
= NULL
;
450 uint32_t last_free
= 0;
451 const uint32_t min_tries
= 3;
455 global
= talloc_zero(mem_ctx
, struct smbXsrv_tcon_global0
);
456 if (global
== NULL
) {
457 return NT_STATUS_NO_MEMORY
;
459 talloc_set_destructor(global
, smbXsrv_tcon_global_destructor
);
462 * Here we just randomly try the whole 32-bit space
464 * We use just 32-bit, because we want to reuse the
467 for (i
= 0; i
< UINT32_MAX
; i
++) {
468 bool is_free
= false;
469 bool was_free
= false;
471 uint8_t key_buf
[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
];
474 if (i
>= min_tries
&& last_free
!= 0) {
477 id
= generate_random();
482 if (id
== UINT32_MAX
) {
486 key
= smbXsrv_tcon_global_id_to_key(id
, key_buf
);
488 global
->db_rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
489 if (global
->db_rec
== NULL
) {
491 return NT_STATUS_INSUFFICIENT_RESOURCES
;
494 smbXsrv_tcon_global_verify_record(global
->db_rec
,
500 TALLOC_FREE(global
->db_rec
);
504 if (!was_free
&& i
< min_tries
) {
506 * The session_id is free now,
507 * but was not free before.
509 * This happens if a smbd crashed
510 * and did not cleanup the record.
512 * If this is one of our first tries,
513 * then we try to find a real free one.
515 if (last_free
== 0) {
518 TALLOC_FREE(global
->db_rec
);
522 global
->tcon_global_id
= id
;
528 /* should not be reached */
530 return NT_STATUS_INTERNAL_ERROR
;
533 static void smbXsrv_tcon_global_verify_record(struct db_record
*db_rec
,
537 struct smbXsrv_tcon_global0
**_g
)
542 struct smbXsrv_tcon_globalB global_blob
;
543 enum ndr_err_code ndr_err
;
544 struct smbXsrv_tcon_global0
*global
= NULL
;
546 TALLOC_CTX
*frame
= talloc_stackframe();
557 key
= dbwrap_record_get_key(db_rec
);
559 val
= dbwrap_record_get_value(db_rec
);
560 if (val
.dsize
== 0) {
569 blob
= data_blob_const(val
.dptr
, val
.dsize
);
571 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
572 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_tcon_globalB
);
573 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
574 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
575 DEBUG(1,("smbXsrv_tcon_global_verify_record: "
576 "key '%s' ndr_pull_struct_blob - %s\n",
577 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
583 DEBUG(10,("smbXsrv_tcon_global_verify_record\n"));
585 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
588 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
589 DEBUG(0,("smbXsrv_tcon_global_verify_record: "
590 "key '%s' use unsupported version %u\n",
591 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
592 global_blob
.version
));
593 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
598 global
= global_blob
.info
.info0
;
600 exists
= serverid_exists(&global
->server_id
);
602 DEBUG(2,("smbXsrv_tcon_global_verify_record: "
603 "key '%s' server_id %s does not exist.\n",
604 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
605 server_id_str(frame
, &global
->server_id
)));
607 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
610 dbwrap_record_delete(db_rec
);
616 *_g
= talloc_move(mem_ctx
, &global
);
621 static NTSTATUS
smbXsrv_tcon_global_store(struct smbXsrv_tcon_global0
*global
)
623 struct smbXsrv_tcon_globalB global_blob
;
624 DATA_BLOB blob
= data_blob_null
;
628 enum ndr_err_code ndr_err
;
631 * TODO: if we use other versions than '0'
632 * we would add glue code here, that would be able to
633 * store the information in the old format.
636 if (global
->db_rec
== NULL
) {
637 return NT_STATUS_INTERNAL_ERROR
;
640 key
= dbwrap_record_get_key(global
->db_rec
);
641 val
= dbwrap_record_get_value(global
->db_rec
);
643 ZERO_STRUCT(global_blob
);
644 global_blob
.version
= smbXsrv_version_global_current();
645 if (val
.dsize
>= 8) {
646 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
648 global_blob
.seqnum
+= 1;
649 global_blob
.info
.info0
= global
;
651 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
652 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_tcon_globalB
);
653 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
654 status
= ndr_map_error2ntstatus(ndr_err
);
655 DEBUG(1,("smbXsrv_tcon_global_store: key '%s' ndr_push - %s\n",
656 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
658 TALLOC_FREE(global
->db_rec
);
662 val
= make_tdb_data(blob
.data
, blob
.length
);
663 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
664 if (!NT_STATUS_IS_OK(status
)) {
665 DEBUG(1,("smbXsrv_tcon_global_store: key '%s' store - %s\n",
666 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
668 TALLOC_FREE(global
->db_rec
);
673 DEBUG(10,("smbXsrv_tcon_global_store: key '%s' stored\n",
674 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
)));
675 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
678 TALLOC_FREE(global
->db_rec
);
683 static int smbXsrv_tcon_destructor(struct smbXsrv_tcon
*tcon
)
687 status
= smbXsrv_tcon_disconnect(tcon
, 0);
688 if (!NT_STATUS_IS_OK(status
)) {
689 DEBUG(0, ("smbXsrv_tcon_destructor: "
690 "smbXsrv_tcon_disconnect() failed - %s\n",
694 TALLOC_FREE(tcon
->global
);
699 static NTSTATUS
smbXsrv_tcon_create(struct smbXsrv_connection
*conn
,
700 struct smbXsrv_tcon_table
*table
,
702 struct smbXsrv_tcon
**_tcon
)
704 struct db_record
*local_rec
= NULL
;
705 struct smbXsrv_tcon
*tcon
= NULL
;
708 struct smbXsrv_tcon_global0
*global
= NULL
;
711 if (table
->local
.num_tcons
>= table
->local
.max_tcons
) {
712 return NT_STATUS_INSUFFICIENT_RESOURCES
;
715 tcon
= talloc_zero(table
, struct smbXsrv_tcon
);
717 return NT_STATUS_NO_MEMORY
;
720 tcon
->status
= NT_STATUS_INTERNAL_ERROR
;
721 tcon
->idle_time
= now
;
723 status
= smbXsrv_tcon_global_allocate(table
->global
.db_ctx
,
725 if (!NT_STATUS_IS_OK(status
)) {
729 tcon
->global
= global
;
731 if (conn
->protocol
>= PROTOCOL_SMB2_02
) {
732 uint64_t id
= global
->tcon_global_id
;
733 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
736 global
->tcon_wire_id
= id
;
738 tcon
->local_id
= global
->tcon_global_id
;
740 key
= smbXsrv_tcon_local_id_to_key(tcon
->local_id
, key_buf
);
742 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
744 if (local_rec
== NULL
) {
746 return NT_STATUS_NO_MEMORY
;
749 val
= dbwrap_record_get_value(local_rec
);
750 if (val
.dsize
!= 0) {
752 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
756 status
= smb1srv_tcon_local_allocate_id(table
->local
.db_ctx
,
757 table
->local
.lowest_id
,
758 table
->local
.highest_id
,
762 if (!NT_STATUS_IS_OK(status
)) {
767 global
->tcon_wire_id
= tcon
->local_id
;
770 global
->creation_time
= now
;
772 global
->server_id
= messaging_server_id(conn
->msg_ctx
);
775 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
776 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
777 TALLOC_FREE(local_rec
);
778 if (!NT_STATUS_IS_OK(status
)) {
782 table
->local
.num_tcons
+= 1;
784 talloc_set_destructor(tcon
, smbXsrv_tcon_destructor
);
786 status
= smbXsrv_tcon_global_store(global
);
787 if (!NT_STATUS_IS_OK(status
)) {
788 DEBUG(0,("smbXsrv_tcon_create: "
789 "global_id (0x%08x) store failed - %s\n",
790 tcon
->global
->tcon_global_id
,
797 struct smbXsrv_tconB tcon_blob
;
799 ZERO_STRUCT(tcon_blob
);
800 tcon_blob
.version
= SMBXSRV_VERSION_0
;
801 tcon_blob
.info
.info0
= tcon
;
803 DEBUG(10,("smbXsrv_tcon_create: global_id (0x%08x) stored\n",
804 tcon
->global
->tcon_global_id
));
805 NDR_PRINT_DEBUG(smbXsrv_tconB
, &tcon_blob
);
812 NTSTATUS
smbXsrv_tcon_update(struct smbXsrv_tcon
*tcon
)
814 struct smbXsrv_tcon_table
*table
= tcon
->table
;
816 uint8_t key_buf
[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
];
819 if (tcon
->global
->db_rec
!= NULL
) {
820 DEBUG(0, ("smbXsrv_tcon_update(0x%08x): "
821 "Called with db_rec != NULL'\n",
822 tcon
->global
->tcon_global_id
));
823 return NT_STATUS_INTERNAL_ERROR
;
826 key
= smbXsrv_tcon_global_id_to_key(tcon
->global
->tcon_global_id
,
829 tcon
->global
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
831 if (tcon
->global
->db_rec
== NULL
) {
832 DEBUG(0, ("smbXsrv_tcon_update(0x%08x): "
833 "Failed to lock global key '%s'\n",
834 tcon
->global
->tcon_global_id
,
835 hex_encode_talloc(talloc_tos(), key
.dptr
,
837 return NT_STATUS_INTERNAL_DB_ERROR
;
840 status
= smbXsrv_tcon_global_store(tcon
->global
);
841 if (!NT_STATUS_IS_OK(status
)) {
842 DEBUG(0,("smbXsrv_tcon_update: "
843 "global_id (0x%08x) store failed - %s\n",
844 tcon
->global
->tcon_global_id
,
850 struct smbXsrv_tconB tcon_blob
;
852 ZERO_STRUCT(tcon_blob
);
853 tcon_blob
.version
= SMBXSRV_VERSION_0
;
854 tcon_blob
.info
.info0
= tcon
;
856 DEBUG(10,("smbXsrv_tcon_update: global_id (0x%08x) stored\n",
857 tcon
->global
->tcon_global_id
));
858 NDR_PRINT_DEBUG(smbXsrv_tconB
, &tcon_blob
);
864 NTSTATUS
smbXsrv_tcon_disconnect(struct smbXsrv_tcon
*tcon
, uint64_t vuid
)
866 struct smbXsrv_tcon_table
*table
;
867 struct db_record
*local_rec
= NULL
;
868 struct db_record
*global_rec
= NULL
;
870 NTSTATUS error
= NT_STATUS_OK
;
872 if (tcon
->table
== NULL
) {
879 tcon
->status
= NT_STATUS_NETWORK_NAME_DELETED
;
881 global_rec
= tcon
->global
->db_rec
;
882 tcon
->global
->db_rec
= NULL
;
883 if (global_rec
== NULL
) {
884 uint8_t key_buf
[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
];
887 key
= smbXsrv_tcon_global_id_to_key(
888 tcon
->global
->tcon_global_id
,
891 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
893 if (global_rec
== NULL
) {
894 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
895 "Failed to lock global key '%s'\n",
896 tcon
->global
->tcon_global_id
,
897 tcon
->global
->share_name
,
898 hex_encode_talloc(global_rec
, key
.dptr
,
900 error
= NT_STATUS_INTERNAL_ERROR
;
904 if (global_rec
!= NULL
) {
905 status
= dbwrap_record_delete(global_rec
);
906 if (!NT_STATUS_IS_OK(status
)) {
907 TDB_DATA key
= dbwrap_record_get_key(global_rec
);
909 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
910 "failed to delete global key '%s': %s\n",
911 tcon
->global
->tcon_global_id
,
912 tcon
->global
->share_name
,
913 hex_encode_talloc(global_rec
, key
.dptr
,
919 TALLOC_FREE(global_rec
);
921 local_rec
= tcon
->db_rec
;
922 if (local_rec
== NULL
) {
923 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
926 key
= smbXsrv_tcon_local_id_to_key(tcon
->local_id
, key_buf
);
928 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
930 if (local_rec
== NULL
) {
931 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
932 "Failed to lock local key '%s'\n",
933 tcon
->global
->tcon_global_id
,
934 tcon
->global
->share_name
,
935 hex_encode_talloc(local_rec
, key
.dptr
,
937 error
= NT_STATUS_INTERNAL_ERROR
;
941 if (local_rec
!= NULL
) {
942 status
= dbwrap_record_delete(local_rec
);
943 if (!NT_STATUS_IS_OK(status
)) {
944 TDB_DATA key
= dbwrap_record_get_key(local_rec
);
946 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
947 "failed to delete local key '%s': %s\n",
948 tcon
->global
->tcon_global_id
,
949 tcon
->global
->share_name
,
950 hex_encode_talloc(local_rec
, key
.dptr
,
955 table
->local
.num_tcons
-= 1;
957 if (tcon
->db_rec
== NULL
) {
958 TALLOC_FREE(local_rec
);
965 ok
= set_current_service(tcon
->compat
, 0, true);
967 status
= NT_STATUS_INTERNAL_ERROR
;
968 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
969 "set_current_service() failed: %s\n",
970 tcon
->global
->tcon_global_id
,
971 tcon
->global
->share_name
,
977 close_cnum(tcon
->compat
, vuid
);
984 struct smbXsrv_tcon_disconnect_all_state
{
986 NTSTATUS first_status
;
990 static int smbXsrv_tcon_disconnect_all_callback(struct db_record
*local_rec
,
993 static NTSTATUS
smbXsrv_tcon_disconnect_all(struct smbXsrv_tcon_table
*table
,
996 struct smbXsrv_tcon_disconnect_all_state state
;
1000 if (table
== NULL
) {
1001 return NT_STATUS_OK
;
1007 status
= dbwrap_traverse(table
->local
.db_ctx
,
1008 smbXsrv_tcon_disconnect_all_callback
,
1010 if (!NT_STATUS_IS_OK(status
)) {
1011 DEBUG(0, ("smbXsrv_tcon_disconnect_all: "
1012 "dbwrap_traverse() failed: %s\n",
1013 nt_errstr(status
)));
1017 if (!NT_STATUS_IS_OK(state
.first_status
)) {
1018 DEBUG(0, ("smbXsrv_tcon_disconnect_all: "
1019 "count[%d] errors[%d] first[%s]\n",
1020 count
, state
.errors
,
1021 nt_errstr(state
.first_status
)));
1022 return state
.first_status
;
1025 return NT_STATUS_OK
;
1028 static int smbXsrv_tcon_disconnect_all_callback(struct db_record
*local_rec
,
1031 struct smbXsrv_tcon_disconnect_all_state
*state
=
1032 (struct smbXsrv_tcon_disconnect_all_state
*)private_data
;
1035 struct smbXsrv_tcon
*tcon
= NULL
;
1039 val
= dbwrap_record_get_value(local_rec
);
1040 if (val
.dsize
!= sizeof(ptr
)) {
1041 status
= NT_STATUS_INTERNAL_ERROR
;
1042 if (NT_STATUS_IS_OK(state
->first_status
)) {
1043 state
->first_status
= status
;
1049 memcpy(&ptr
, val
.dptr
, val
.dsize
);
1050 tcon
= talloc_get_type_abort(ptr
, struct smbXsrv_tcon
);
1053 if (vuid
== 0 && tcon
->compat
) {
1054 vuid
= tcon
->compat
->vuid
;
1057 tcon
->db_rec
= local_rec
;
1058 status
= smbXsrv_tcon_disconnect(tcon
, vuid
);
1059 if (!NT_STATUS_IS_OK(status
)) {
1060 if (NT_STATUS_IS_OK(state
->first_status
)) {
1061 state
->first_status
= status
;
1070 NTSTATUS
smb1srv_tcon_table_init(struct smbXsrv_connection
*conn
)
1073 * Allow a range from 1..65534 with 65534 values.
1075 conn
->tcon_table
= talloc_zero(conn
, struct smbXsrv_tcon_table
);
1076 if (conn
->tcon_table
== NULL
) {
1077 return NT_STATUS_NO_MEMORY
;
1080 return smbXsrv_tcon_table_init(conn
, conn
->tcon_table
,
1085 NTSTATUS
smb1srv_tcon_create(struct smbXsrv_connection
*conn
,
1087 struct smbXsrv_tcon
**_tcon
)
1089 return smbXsrv_tcon_create(conn
, conn
->tcon_table
, now
,
1093 NTSTATUS
smb1srv_tcon_lookup(struct smbXsrv_connection
*conn
,
1094 uint16_t tree_id
, NTTIME now
,
1095 struct smbXsrv_tcon
**tcon
)
1097 uint32_t local_id
= tree_id
;
1099 return smbXsrv_tcon_local_lookup(conn
->tcon_table
,
1100 local_id
, now
, tcon
);
1103 NTSTATUS
smb1srv_tcon_disconnect_all(struct smbXsrv_connection
*conn
)
1106 * We do not pass a vuid here,
1107 * which means the vuid is taken from
1108 * the tcon->compat->vuid.
1110 * NOTE: that tcon->compat->vuid may point to
1111 * a none existing vuid (or the wrong one)
1112 * as the tcon can exist without a session
1115 * This matches the old behavior of
1116 * conn_close_all(), but we should think
1117 * about how to fix this in future.
1119 return smbXsrv_tcon_disconnect_all(conn
->tcon_table
, 0);
1122 NTSTATUS
smb2srv_tcon_table_init(struct smbXsrv_session
*session
)
1125 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1127 session
->tcon_table
= talloc_zero(session
, struct smbXsrv_tcon_table
);
1128 if (session
->tcon_table
== NULL
) {
1129 return NT_STATUS_NO_MEMORY
;
1132 return smbXsrv_tcon_table_init(session
, session
->tcon_table
,
1137 NTSTATUS
smb2srv_tcon_create(struct smbXsrv_session
*session
,
1139 struct smbXsrv_tcon
**_tcon
)
1141 return smbXsrv_tcon_create(session
->connection
, session
->tcon_table
,
1145 NTSTATUS
smb2srv_tcon_lookup(struct smbXsrv_session
*session
,
1146 uint32_t tree_id
, NTTIME now
,
1147 struct smbXsrv_tcon
**tcon
)
1149 uint32_t local_id
= tree_id
;
1151 return smbXsrv_tcon_local_lookup(session
->tcon_table
,
1152 local_id
, now
, tcon
);
1155 NTSTATUS
smb2srv_tcon_disconnect_all(struct smbXsrv_session
*session
)
1159 if (session
->compat
) {
1160 vuid
= session
->compat
->vuid
;
1165 return smbXsrv_tcon_disconnect_all(session
->tcon_table
, vuid
);
1168 struct smbXsrv_tcon_global_traverse_state
{
1169 int (*fn
)(struct smbXsrv_tcon_global0
*, void *);
1173 static int smbXsrv_tcon_global_traverse_fn(struct db_record
*rec
, void *data
)
1176 struct smbXsrv_tcon_global_traverse_state
*state
=
1177 (struct smbXsrv_tcon_global_traverse_state
*)data
;
1178 TDB_DATA key
= dbwrap_record_get_key(rec
);
1179 TDB_DATA val
= dbwrap_record_get_value(rec
);
1180 DATA_BLOB blob
= data_blob_const(val
.dptr
, val
.dsize
);
1181 struct smbXsrv_tcon_globalB global_blob
;
1182 enum ndr_err_code ndr_err
;
1183 TALLOC_CTX
*frame
= talloc_stackframe();
1185 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
1186 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_tcon_globalB
);
1187 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1188 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
1189 "key '%s' ndr_pull_struct_blob - %s\n",
1190 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1191 ndr_errstr(ndr_err
)));
1195 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
1196 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
1197 "key '%s' unsuported version - %d\n",
1198 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1199 (int)global_blob
.version
));
1203 global_blob
.info
.info0
->db_rec
= rec
;
1204 ret
= state
->fn(global_blob
.info
.info0
, state
->private_data
);
1210 NTSTATUS
smbXsrv_tcon_global_traverse(
1211 int (*fn
)(struct smbXsrv_tcon_global0
*, void *),
1216 struct smbXsrv_tcon_global_traverse_state state
= {
1218 .private_data
= private_data
,
1222 status
= smbXsrv_tcon_global_init();
1223 if (!NT_STATUS_IS_OK(status
)) {
1225 DEBUG(0, ("Failed to initialize tcon_global: %s\n",
1226 nt_errstr(status
)));
1230 status
= dbwrap_traverse_read(smbXsrv_tcon_global_db_ctx
,
1231 smbXsrv_tcon_global_traverse_fn
,