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,
70 status
= map_nt_error_from_unix_common(errno
);
75 smbXsrv_tcon_global_db_ctx
= db_ctx
;
82 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
83 * has the same result as integer comparison between the uint32_t
86 * TODO: implement string based key
89 #define SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
91 static TDB_DATA
smbXsrv_tcon_global_id_to_key(uint32_t id
,
96 RSIVAL(key_buf
, 0, id
);
98 key
= make_tdb_data(key_buf
, SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
);
104 static NTSTATUS
smbXsrv_tcon_global_key_to_id(TDB_DATA key
, uint32_t *id
)
107 return NT_STATUS_INVALID_PARAMETER
;
110 if (key
.dsize
!= SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
) {
111 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
114 *id
= RIVAL(key
.dptr
, 0);
120 #define SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
122 static TDB_DATA
smbXsrv_tcon_local_id_to_key(uint32_t id
,
127 RSIVAL(key_buf
, 0, id
);
129 key
= make_tdb_data(key_buf
, SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
);
134 static NTSTATUS
smbXsrv_tcon_local_key_to_id(TDB_DATA key
, uint32_t *id
)
137 return NT_STATUS_INVALID_PARAMETER
;
140 if (key
.dsize
!= SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
) {
141 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
144 *id
= RIVAL(key
.dptr
, 0);
149 static NTSTATUS
smbXsrv_tcon_table_init(TALLOC_CTX
*mem_ctx
,
150 struct smbXsrv_tcon_table
*table
,
158 if (lowest_id
> highest_id
) {
159 return NT_STATUS_INTERNAL_ERROR
;
162 max_range
= highest_id
;
163 max_range
-= lowest_id
;
166 if (max_tcons
> max_range
) {
167 return NT_STATUS_INTERNAL_ERROR
;
171 table
->local
.db_ctx
= db_open_rbt(table
);
172 if (table
->local
.db_ctx
== NULL
) {
173 return NT_STATUS_NO_MEMORY
;
175 table
->local
.lowest_id
= lowest_id
;
176 table
->local
.highest_id
= highest_id
;
177 table
->local
.max_tcons
= max_tcons
;
179 status
= smbXsrv_tcon_global_init();
180 if (!NT_STATUS_IS_OK(status
)) {
184 table
->global
.db_ctx
= smbXsrv_tcon_global_db_ctx
;
189 struct smb1srv_tcon_local_allocate_state
{
190 const uint32_t lowest_id
;
191 const uint32_t highest_id
;
197 static int smb1srv_tcon_local_allocate_traverse(struct db_record
*rec
,
200 struct smb1srv_tcon_local_allocate_state
*state
=
201 (struct smb1srv_tcon_local_allocate_state
*)private_data
;
202 TDB_DATA key
= dbwrap_record_get_key(rec
);
206 status
= smbXsrv_tcon_local_key_to_id(key
, &id
);
207 if (!NT_STATUS_IS_OK(status
)) {
208 state
->status
= status
;
212 if (id
<= state
->last_id
) {
213 state
->status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
218 if (id
> state
->useable_id
) {
219 state
->status
= NT_STATUS_OK
;
223 if (state
->useable_id
== state
->highest_id
) {
224 state
->status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
228 state
->useable_id
+=1;
232 static NTSTATUS
smb1srv_tcon_local_allocate_id(struct db_context
*db
,
236 struct db_record
**_rec
,
239 struct smb1srv_tcon_local_allocate_state state
= {
240 .lowest_id
= lowest_id
,
241 .highest_id
= highest_id
,
243 .useable_id
= lowest_id
,
244 .status
= NT_STATUS_INTERNAL_ERROR
,
254 if (lowest_id
> highest_id
) {
255 return NT_STATUS_INSUFFICIENT_RESOURCES
;
259 * first we try randomly
261 range
= (highest_id
- lowest_id
) + 1;
263 for (i
= 0; i
< (range
/ 2); i
++) {
265 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
268 struct db_record
*rec
= NULL
;
270 id
= generate_random() % range
;
273 if (id
< lowest_id
) {
276 if (id
> highest_id
) {
280 key
= smbXsrv_tcon_local_id_to_key(id
, key_buf
);
282 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
284 return NT_STATUS_INSUFFICIENT_RESOURCES
;
287 val
= dbwrap_record_get_value(rec
);
288 if (val
.dsize
!= 0) {
299 * if the range is almost full,
300 * we traverse the whole table
301 * (this relies on sorted behavior of dbwrap_rbt)
303 status
= dbwrap_traverse_read(db
, smb1srv_tcon_local_allocate_traverse
,
305 if (NT_STATUS_IS_OK(status
)) {
306 if (NT_STATUS_IS_OK(state
.status
)) {
307 return NT_STATUS_INTERNAL_ERROR
;
310 if (!NT_STATUS_EQUAL(state
.status
, NT_STATUS_INTERNAL_ERROR
)) {
314 if (state
.useable_id
<= state
.highest_id
) {
315 state
.status
= NT_STATUS_OK
;
317 return NT_STATUS_INSUFFICIENT_RESOURCES
;
319 } else if (!NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_DB_CORRUPTION
)) {
321 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
323 * If we get anything else it is an error, because it
324 * means we did not manage to find a free slot in
327 return NT_STATUS_INSUFFICIENT_RESOURCES
;
330 if (NT_STATUS_IS_OK(state
.status
)) {
332 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
335 struct db_record
*rec
= NULL
;
337 id
= state
.useable_id
;
339 key
= smbXsrv_tcon_local_id_to_key(id
, key_buf
);
341 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
343 return NT_STATUS_INSUFFICIENT_RESOURCES
;
346 val
= dbwrap_record_get_value(rec
);
347 if (val
.dsize
!= 0) {
349 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
360 struct smbXsrv_tcon_local_fetch_state
{
361 struct smbXsrv_tcon
*tcon
;
365 static void smbXsrv_tcon_local_fetch_parser(TDB_DATA key
, TDB_DATA data
,
368 struct smbXsrv_tcon_local_fetch_state
*state
=
369 (struct smbXsrv_tcon_local_fetch_state
*)private_data
;
372 if (data
.dsize
!= sizeof(ptr
)) {
373 state
->status
= NT_STATUS_INTERNAL_DB_ERROR
;
377 memcpy(&ptr
, data
.dptr
, data
.dsize
);
378 state
->tcon
= talloc_get_type_abort(ptr
, struct smbXsrv_tcon
);
379 state
->status
= NT_STATUS_OK
;
382 static NTSTATUS
smbXsrv_tcon_local_lookup(struct smbXsrv_tcon_table
*table
,
383 uint32_t tcon_local_id
,
385 struct smbXsrv_tcon
**_tcon
)
387 struct smbXsrv_tcon_local_fetch_state state
= {
389 .status
= NT_STATUS_INTERNAL_ERROR
,
391 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
397 if (tcon_local_id
== 0) {
398 return NT_STATUS_NETWORK_NAME_DELETED
;
402 /* this might happen before the end of negprot */
403 return NT_STATUS_NETWORK_NAME_DELETED
;
406 if (table
->local
.db_ctx
== NULL
) {
407 return NT_STATUS_INTERNAL_ERROR
;
410 key
= smbXsrv_tcon_local_id_to_key(tcon_local_id
, key_buf
);
412 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
413 smbXsrv_tcon_local_fetch_parser
,
415 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
416 return NT_STATUS_NETWORK_NAME_DELETED
;
417 } else if (!NT_STATUS_IS_OK(status
)) {
420 if (!NT_STATUS_IS_OK(state
.status
)) {
424 if (NT_STATUS_EQUAL(state
.tcon
->status
, NT_STATUS_NETWORK_NAME_DELETED
)) {
425 return NT_STATUS_NETWORK_NAME_DELETED
;
428 state
.tcon
->idle_time
= now
;
431 return state
.tcon
->status
;
434 static int smbXsrv_tcon_global_destructor(struct smbXsrv_tcon_global0
*global
)
439 static void smbXsrv_tcon_global_verify_record(struct db_record
*db_rec
,
443 struct smbXsrv_tcon_global0
**_g
);
445 static NTSTATUS
smbXsrv_tcon_global_allocate(struct db_context
*db
,
447 struct smbXsrv_tcon_global0
**_global
)
450 struct smbXsrv_tcon_global0
*global
= NULL
;
451 uint32_t last_free
= 0;
452 const uint32_t min_tries
= 3;
456 global
= talloc_zero(mem_ctx
, struct smbXsrv_tcon_global0
);
457 if (global
== NULL
) {
458 return NT_STATUS_NO_MEMORY
;
460 talloc_set_destructor(global
, smbXsrv_tcon_global_destructor
);
463 * Here we just randomly try the whole 32-bit space
465 * We use just 32-bit, because we want to reuse the
468 for (i
= 0; i
< UINT32_MAX
; i
++) {
469 bool is_free
= false;
470 bool was_free
= false;
472 uint8_t key_buf
[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
];
475 if (i
>= min_tries
&& last_free
!= 0) {
478 id
= generate_random();
483 if (id
== UINT32_MAX
) {
487 key
= smbXsrv_tcon_global_id_to_key(id
, key_buf
);
489 global
->db_rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
490 if (global
->db_rec
== NULL
) {
492 return NT_STATUS_INSUFFICIENT_RESOURCES
;
495 smbXsrv_tcon_global_verify_record(global
->db_rec
,
501 TALLOC_FREE(global
->db_rec
);
505 if (!was_free
&& i
< min_tries
) {
507 * The session_id is free now,
508 * but was not free before.
510 * This happens if a smbd crashed
511 * and did not cleanup the record.
513 * If this is one of our first tries,
514 * then we try to find a real free one.
516 if (last_free
== 0) {
519 TALLOC_FREE(global
->db_rec
);
523 global
->tcon_global_id
= id
;
529 /* should not be reached */
531 return NT_STATUS_INTERNAL_ERROR
;
534 static void smbXsrv_tcon_global_verify_record(struct db_record
*db_rec
,
538 struct smbXsrv_tcon_global0
**_g
)
543 struct smbXsrv_tcon_globalB global_blob
;
544 enum ndr_err_code ndr_err
;
545 struct smbXsrv_tcon_global0
*global
= NULL
;
547 TALLOC_CTX
*frame
= talloc_stackframe();
558 key
= dbwrap_record_get_key(db_rec
);
560 val
= dbwrap_record_get_value(db_rec
);
561 if (val
.dsize
== 0) {
570 blob
= data_blob_const(val
.dptr
, val
.dsize
);
572 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
573 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_tcon_globalB
);
574 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
575 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
576 DEBUG(1,("smbXsrv_tcon_global_verify_record: "
577 "key '%s' ndr_pull_struct_blob - %s\n",
578 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
584 DEBUG(10,("smbXsrv_tcon_global_verify_record\n"));
586 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
589 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
590 DEBUG(0,("smbXsrv_tcon_global_verify_record: "
591 "key '%s' use unsupported version %u\n",
592 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
593 global_blob
.version
));
594 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
599 global
= global_blob
.info
.info0
;
601 exists
= serverid_exists(&global
->server_id
);
603 DEBUG(2,("smbXsrv_tcon_global_verify_record: "
604 "key '%s' server_id %s does not exist.\n",
605 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
606 server_id_str(frame
, &global
->server_id
)));
608 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
611 dbwrap_record_delete(db_rec
);
617 *_g
= talloc_move(mem_ctx
, &global
);
622 static NTSTATUS
smbXsrv_tcon_global_store(struct smbXsrv_tcon_global0
*global
)
624 struct smbXsrv_tcon_globalB global_blob
;
625 DATA_BLOB blob
= data_blob_null
;
629 enum ndr_err_code ndr_err
;
632 * TODO: if we use other versions than '0'
633 * we would add glue code here, that would be able to
634 * store the information in the old format.
637 if (global
->db_rec
== NULL
) {
638 return NT_STATUS_INTERNAL_ERROR
;
641 key
= dbwrap_record_get_key(global
->db_rec
);
642 val
= dbwrap_record_get_value(global
->db_rec
);
644 ZERO_STRUCT(global_blob
);
645 global_blob
.version
= smbXsrv_version_global_current();
646 if (val
.dsize
>= 8) {
647 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
649 global_blob
.seqnum
+= 1;
650 global_blob
.info
.info0
= global
;
652 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
653 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_tcon_globalB
);
654 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
655 status
= ndr_map_error2ntstatus(ndr_err
);
656 DEBUG(1,("smbXsrv_tcon_global_store: key '%s' ndr_push - %s\n",
657 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
659 TALLOC_FREE(global
->db_rec
);
663 val
= make_tdb_data(blob
.data
, blob
.length
);
664 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
665 if (!NT_STATUS_IS_OK(status
)) {
666 DEBUG(1,("smbXsrv_tcon_global_store: key '%s' store - %s\n",
667 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
669 TALLOC_FREE(global
->db_rec
);
674 DEBUG(10,("smbXsrv_tcon_global_store: key '%s' stored\n",
675 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
)));
676 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
679 TALLOC_FREE(global
->db_rec
);
684 static int smbXsrv_tcon_destructor(struct smbXsrv_tcon
*tcon
)
688 status
= smbXsrv_tcon_disconnect(tcon
, 0);
689 if (!NT_STATUS_IS_OK(status
)) {
690 DEBUG(0, ("smbXsrv_tcon_destructor: "
691 "smbXsrv_tcon_disconnect() failed - %s\n",
695 TALLOC_FREE(tcon
->global
);
700 static NTSTATUS
smbXsrv_tcon_create(struct smbXsrv_tcon_table
*table
,
701 enum protocol_types protocol
,
702 struct server_id server_id
,
704 struct smbXsrv_tcon
**_tcon
)
706 struct db_record
*local_rec
= NULL
;
707 struct smbXsrv_tcon
*tcon
= NULL
;
710 struct smbXsrv_tcon_global0
*global
= NULL
;
713 if (table
->local
.num_tcons
>= table
->local
.max_tcons
) {
714 return NT_STATUS_INSUFFICIENT_RESOURCES
;
717 tcon
= talloc_zero(table
, struct smbXsrv_tcon
);
719 return NT_STATUS_NO_MEMORY
;
722 tcon
->status
= NT_STATUS_INTERNAL_ERROR
;
723 tcon
->idle_time
= now
;
725 status
= smbXsrv_tcon_global_allocate(table
->global
.db_ctx
,
727 if (!NT_STATUS_IS_OK(status
)) {
731 tcon
->global
= global
;
733 if (protocol
>= PROTOCOL_SMB2_02
) {
734 uint64_t id
= global
->tcon_global_id
;
735 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
738 global
->tcon_wire_id
= id
;
740 tcon
->local_id
= global
->tcon_global_id
;
742 key
= smbXsrv_tcon_local_id_to_key(tcon
->local_id
, key_buf
);
744 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
746 if (local_rec
== NULL
) {
748 return NT_STATUS_NO_MEMORY
;
751 val
= dbwrap_record_get_value(local_rec
);
752 if (val
.dsize
!= 0) {
754 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
758 status
= smb1srv_tcon_local_allocate_id(table
->local
.db_ctx
,
759 table
->local
.lowest_id
,
760 table
->local
.highest_id
,
764 if (!NT_STATUS_IS_OK(status
)) {
769 global
->tcon_wire_id
= tcon
->local_id
;
772 global
->creation_time
= now
;
774 global
->server_id
= server_id
;
777 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
778 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
779 TALLOC_FREE(local_rec
);
780 if (!NT_STATUS_IS_OK(status
)) {
784 table
->local
.num_tcons
+= 1;
786 talloc_set_destructor(tcon
, smbXsrv_tcon_destructor
);
788 status
= smbXsrv_tcon_global_store(global
);
789 if (!NT_STATUS_IS_OK(status
)) {
790 DEBUG(0,("smbXsrv_tcon_create: "
791 "global_id (0x%08x) store failed - %s\n",
792 tcon
->global
->tcon_global_id
,
799 struct smbXsrv_tconB tcon_blob
;
801 ZERO_STRUCT(tcon_blob
);
802 tcon_blob
.version
= SMBXSRV_VERSION_0
;
803 tcon_blob
.info
.info0
= tcon
;
805 DEBUG(10,("smbXsrv_tcon_create: global_id (0x%08x) stored\n",
806 tcon
->global
->tcon_global_id
));
807 NDR_PRINT_DEBUG(smbXsrv_tconB
, &tcon_blob
);
814 NTSTATUS
smbXsrv_tcon_update(struct smbXsrv_tcon
*tcon
)
816 struct smbXsrv_tcon_table
*table
= tcon
->table
;
818 uint8_t key_buf
[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
];
821 if (tcon
->global
->db_rec
!= NULL
) {
822 DEBUG(0, ("smbXsrv_tcon_update(0x%08x): "
823 "Called with db_rec != NULL'\n",
824 tcon
->global
->tcon_global_id
));
825 return NT_STATUS_INTERNAL_ERROR
;
828 key
= smbXsrv_tcon_global_id_to_key(tcon
->global
->tcon_global_id
,
831 tcon
->global
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
833 if (tcon
->global
->db_rec
== NULL
) {
834 DEBUG(0, ("smbXsrv_tcon_update(0x%08x): "
835 "Failed to lock global key '%s'\n",
836 tcon
->global
->tcon_global_id
,
837 hex_encode_talloc(talloc_tos(), key
.dptr
,
839 return NT_STATUS_INTERNAL_DB_ERROR
;
842 status
= smbXsrv_tcon_global_store(tcon
->global
);
843 if (!NT_STATUS_IS_OK(status
)) {
844 DEBUG(0,("smbXsrv_tcon_update: "
845 "global_id (0x%08x) store failed - %s\n",
846 tcon
->global
->tcon_global_id
,
852 struct smbXsrv_tconB tcon_blob
;
854 ZERO_STRUCT(tcon_blob
);
855 tcon_blob
.version
= SMBXSRV_VERSION_0
;
856 tcon_blob
.info
.info0
= tcon
;
858 DEBUG(10,("smbXsrv_tcon_update: global_id (0x%08x) stored\n",
859 tcon
->global
->tcon_global_id
));
860 NDR_PRINT_DEBUG(smbXsrv_tconB
, &tcon_blob
);
866 NTSTATUS
smbXsrv_tcon_disconnect(struct smbXsrv_tcon
*tcon
, uint64_t vuid
)
868 struct smbXsrv_tcon_table
*table
;
869 struct db_record
*local_rec
= NULL
;
870 struct db_record
*global_rec
= NULL
;
872 NTSTATUS error
= NT_STATUS_OK
;
874 if (tcon
->table
== NULL
) {
881 tcon
->status
= NT_STATUS_NETWORK_NAME_DELETED
;
883 global_rec
= tcon
->global
->db_rec
;
884 tcon
->global
->db_rec
= NULL
;
885 if (global_rec
== NULL
) {
886 uint8_t key_buf
[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
];
889 key
= smbXsrv_tcon_global_id_to_key(
890 tcon
->global
->tcon_global_id
,
893 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
895 if (global_rec
== NULL
) {
896 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
897 "Failed to lock global key '%s'\n",
898 tcon
->global
->tcon_global_id
,
899 tcon
->global
->share_name
,
900 hex_encode_talloc(global_rec
, key
.dptr
,
902 error
= NT_STATUS_INTERNAL_ERROR
;
906 if (global_rec
!= NULL
) {
907 status
= dbwrap_record_delete(global_rec
);
908 if (!NT_STATUS_IS_OK(status
)) {
909 TDB_DATA key
= dbwrap_record_get_key(global_rec
);
911 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
912 "failed to delete global key '%s': %s\n",
913 tcon
->global
->tcon_global_id
,
914 tcon
->global
->share_name
,
915 hex_encode_talloc(global_rec
, key
.dptr
,
921 TALLOC_FREE(global_rec
);
923 local_rec
= tcon
->db_rec
;
924 if (local_rec
== NULL
) {
925 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
928 key
= smbXsrv_tcon_local_id_to_key(tcon
->local_id
, key_buf
);
930 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
932 if (local_rec
== NULL
) {
933 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
934 "Failed to lock local key '%s'\n",
935 tcon
->global
->tcon_global_id
,
936 tcon
->global
->share_name
,
937 hex_encode_talloc(local_rec
, key
.dptr
,
939 error
= NT_STATUS_INTERNAL_ERROR
;
943 if (local_rec
!= NULL
) {
944 status
= dbwrap_record_delete(local_rec
);
945 if (!NT_STATUS_IS_OK(status
)) {
946 TDB_DATA key
= dbwrap_record_get_key(local_rec
);
948 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
949 "failed to delete local key '%s': %s\n",
950 tcon
->global
->tcon_global_id
,
951 tcon
->global
->share_name
,
952 hex_encode_talloc(local_rec
, key
.dptr
,
957 table
->local
.num_tcons
-= 1;
959 if (tcon
->db_rec
== NULL
) {
960 TALLOC_FREE(local_rec
);
967 ok
= set_current_service(tcon
->compat
, 0, true);
969 status
= NT_STATUS_INTERNAL_ERROR
;
970 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
971 "set_current_service() failed: %s\n",
972 tcon
->global
->tcon_global_id
,
973 tcon
->global
->share_name
,
979 close_cnum(tcon
->compat
, vuid
);
986 struct smbXsrv_tcon_disconnect_all_state
{
988 NTSTATUS first_status
;
992 static int smbXsrv_tcon_disconnect_all_callback(struct db_record
*local_rec
,
995 static NTSTATUS
smbXsrv_tcon_disconnect_all(struct smbXsrv_tcon_table
*table
,
998 struct smbXsrv_tcon_disconnect_all_state state
;
1002 if (table
== NULL
) {
1003 return NT_STATUS_OK
;
1009 status
= dbwrap_traverse(table
->local
.db_ctx
,
1010 smbXsrv_tcon_disconnect_all_callback
,
1012 if (!NT_STATUS_IS_OK(status
)) {
1013 DEBUG(0, ("smbXsrv_tcon_disconnect_all: "
1014 "dbwrap_traverse() failed: %s\n",
1015 nt_errstr(status
)));
1019 if (!NT_STATUS_IS_OK(state
.first_status
)) {
1020 DEBUG(0, ("smbXsrv_tcon_disconnect_all: "
1021 "count[%d] errors[%d] first[%s]\n",
1022 count
, state
.errors
,
1023 nt_errstr(state
.first_status
)));
1024 return state
.first_status
;
1027 return NT_STATUS_OK
;
1030 static int smbXsrv_tcon_disconnect_all_callback(struct db_record
*local_rec
,
1033 struct smbXsrv_tcon_disconnect_all_state
*state
=
1034 (struct smbXsrv_tcon_disconnect_all_state
*)private_data
;
1037 struct smbXsrv_tcon
*tcon
= NULL
;
1041 val
= dbwrap_record_get_value(local_rec
);
1042 if (val
.dsize
!= sizeof(ptr
)) {
1043 status
= NT_STATUS_INTERNAL_ERROR
;
1044 if (NT_STATUS_IS_OK(state
->first_status
)) {
1045 state
->first_status
= status
;
1051 memcpy(&ptr
, val
.dptr
, val
.dsize
);
1052 tcon
= talloc_get_type_abort(ptr
, struct smbXsrv_tcon
);
1055 if (vuid
== 0 && tcon
->compat
) {
1056 vuid
= tcon
->compat
->vuid
;
1059 tcon
->db_rec
= local_rec
;
1060 status
= smbXsrv_tcon_disconnect(tcon
, vuid
);
1061 if (!NT_STATUS_IS_OK(status
)) {
1062 if (NT_STATUS_IS_OK(state
->first_status
)) {
1063 state
->first_status
= status
;
1072 NTSTATUS
smb1srv_tcon_table_init(struct smbXsrv_connection
*conn
)
1074 struct smbXsrv_client
*client
= conn
->client
;
1077 * Allow a range from 1..65534 with 65534 values.
1079 client
->tcon_table
= talloc_zero(client
, struct smbXsrv_tcon_table
);
1080 if (client
->tcon_table
== NULL
) {
1081 return NT_STATUS_NO_MEMORY
;
1084 return smbXsrv_tcon_table_init(client
, client
->tcon_table
,
1089 NTSTATUS
smb1srv_tcon_create(struct smbXsrv_connection
*conn
,
1091 struct smbXsrv_tcon
**_tcon
)
1093 struct server_id id
= messaging_server_id(conn
->msg_ctx
);
1095 return smbXsrv_tcon_create(conn
->client
->tcon_table
,
1100 NTSTATUS
smb1srv_tcon_lookup(struct smbXsrv_connection
*conn
,
1101 uint16_t tree_id
, NTTIME now
,
1102 struct smbXsrv_tcon
**tcon
)
1104 uint32_t local_id
= tree_id
;
1106 return smbXsrv_tcon_local_lookup(conn
->client
->tcon_table
,
1107 local_id
, now
, tcon
);
1110 NTSTATUS
smb1srv_tcon_disconnect_all(struct smbXsrv_connection
*conn
)
1112 struct smbXsrv_client
*client
= conn
->client
;
1115 * We do not pass a vuid here,
1116 * which means the vuid is taken from
1117 * the tcon->compat->vuid.
1119 * NOTE: that tcon->compat->vuid may point to
1120 * a none existing vuid (or the wrong one)
1121 * as the tcon can exist without a session
1124 * This matches the old behavior of
1125 * conn_close_all(), but we should think
1126 * about how to fix this in future.
1128 return smbXsrv_tcon_disconnect_all(client
->tcon_table
, 0);
1131 NTSTATUS
smb2srv_tcon_table_init(struct smbXsrv_session
*session
)
1134 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1136 session
->tcon_table
= talloc_zero(session
, struct smbXsrv_tcon_table
);
1137 if (session
->tcon_table
== NULL
) {
1138 return NT_STATUS_NO_MEMORY
;
1141 return smbXsrv_tcon_table_init(session
, session
->tcon_table
,
1146 NTSTATUS
smb2srv_tcon_create(struct smbXsrv_session
*session
,
1148 struct smbXsrv_tcon
**_tcon
)
1150 struct server_id id
= messaging_server_id(session
->client
->msg_ctx
);
1152 return smbXsrv_tcon_create(session
->tcon_table
,
1157 NTSTATUS
smb2srv_tcon_lookup(struct smbXsrv_session
*session
,
1158 uint32_t tree_id
, NTTIME now
,
1159 struct smbXsrv_tcon
**tcon
)
1161 uint32_t local_id
= tree_id
;
1163 return smbXsrv_tcon_local_lookup(session
->tcon_table
,
1164 local_id
, now
, tcon
);
1167 NTSTATUS
smb2srv_tcon_disconnect_all(struct smbXsrv_session
*session
)
1171 if (session
->compat
) {
1172 vuid
= session
->compat
->vuid
;
1177 return smbXsrv_tcon_disconnect_all(session
->tcon_table
, vuid
);
1180 struct smbXsrv_tcon_global_traverse_state
{
1181 int (*fn
)(struct smbXsrv_tcon_global0
*, void *);
1185 static int smbXsrv_tcon_global_traverse_fn(struct db_record
*rec
, void *data
)
1188 struct smbXsrv_tcon_global_traverse_state
*state
=
1189 (struct smbXsrv_tcon_global_traverse_state
*)data
;
1190 TDB_DATA key
= dbwrap_record_get_key(rec
);
1191 TDB_DATA val
= dbwrap_record_get_value(rec
);
1192 DATA_BLOB blob
= data_blob_const(val
.dptr
, val
.dsize
);
1193 struct smbXsrv_tcon_globalB global_blob
;
1194 enum ndr_err_code ndr_err
;
1195 TALLOC_CTX
*frame
= talloc_stackframe();
1197 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
1198 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_tcon_globalB
);
1199 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1200 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
1201 "key '%s' ndr_pull_struct_blob - %s\n",
1202 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1203 ndr_errstr(ndr_err
)));
1207 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
1208 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
1209 "key '%s' unsuported version - %d\n",
1210 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1211 (int)global_blob
.version
));
1215 global_blob
.info
.info0
->db_rec
= rec
;
1216 ret
= state
->fn(global_blob
.info
.info0
, state
->private_data
);
1222 NTSTATUS
smbXsrv_tcon_global_traverse(
1223 int (*fn
)(struct smbXsrv_tcon_global0
*, void *),
1228 struct smbXsrv_tcon_global_traverse_state state
= {
1230 .private_data
= private_data
,
1234 status
= smbXsrv_tcon_global_init();
1235 if (!NT_STATUS_IS_OK(status
)) {
1237 DEBUG(0, ("Failed to initialize tcon_global: %s\n",
1238 nt_errstr(status
)));
1242 status
= dbwrap_traverse_read(smbXsrv_tcon_global_db_ctx
,
1243 smbXsrv_tcon_global_traverse_fn
,