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 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");
58 if (global_path
== NULL
) {
59 return NT_STATUS_NO_MEMORY
;
62 db_ctx
= db_open(NULL
, global_path
,
66 TDB_INCOMPATIBLE_HASH
,
67 O_RDWR
| O_CREAT
, 0600,
70 TALLOC_FREE(global_path
);
74 status
= map_nt_error_from_unix_common(errno
);
79 smbXsrv_tcon_global_db_ctx
= db_ctx
;
86 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
87 * has the same result as integer comparison between the uint32_t
90 * TODO: implement string based key
93 #define SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
95 static TDB_DATA
smbXsrv_tcon_global_id_to_key(uint32_t id
,
100 RSIVAL(key_buf
, 0, id
);
102 key
= make_tdb_data(key_buf
, SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
);
108 static NTSTATUS
smbXsrv_tcon_global_key_to_id(TDB_DATA key
, uint32_t *id
)
111 return NT_STATUS_INVALID_PARAMETER
;
114 if (key
.dsize
!= SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
) {
115 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
118 *id
= RIVAL(key
.dptr
, 0);
124 #define SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
126 static TDB_DATA
smbXsrv_tcon_local_id_to_key(uint32_t id
,
131 RSIVAL(key_buf
, 0, id
);
133 key
= make_tdb_data(key_buf
, SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
);
138 static NTSTATUS
smbXsrv_tcon_local_key_to_id(TDB_DATA key
, uint32_t *id
)
141 return NT_STATUS_INVALID_PARAMETER
;
144 if (key
.dsize
!= SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
) {
145 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
148 *id
= RIVAL(key
.dptr
, 0);
153 static NTSTATUS
smbXsrv_tcon_table_init(TALLOC_CTX
*mem_ctx
,
154 struct smbXsrv_tcon_table
*table
,
162 if (lowest_id
> highest_id
) {
163 return NT_STATUS_INTERNAL_ERROR
;
166 max_range
= highest_id
;
167 max_range
-= lowest_id
;
170 if (max_tcons
> max_range
) {
171 return NT_STATUS_INTERNAL_ERROR
;
175 table
->local
.db_ctx
= db_open_rbt(table
);
176 if (table
->local
.db_ctx
== NULL
) {
177 return NT_STATUS_NO_MEMORY
;
179 table
->local
.lowest_id
= lowest_id
;
180 table
->local
.highest_id
= highest_id
;
181 table
->local
.max_tcons
= max_tcons
;
183 status
= smbXsrv_tcon_global_init();
184 if (!NT_STATUS_IS_OK(status
)) {
188 table
->global
.db_ctx
= smbXsrv_tcon_global_db_ctx
;
193 struct smb1srv_tcon_local_allocate_state
{
194 const uint32_t lowest_id
;
195 const uint32_t highest_id
;
201 static int smb1srv_tcon_local_allocate_traverse(struct db_record
*rec
,
204 struct smb1srv_tcon_local_allocate_state
*state
=
205 (struct smb1srv_tcon_local_allocate_state
*)private_data
;
206 TDB_DATA key
= dbwrap_record_get_key(rec
);
210 status
= smbXsrv_tcon_local_key_to_id(key
, &id
);
211 if (!NT_STATUS_IS_OK(status
)) {
212 state
->status
= status
;
216 if (id
<= state
->last_id
) {
217 state
->status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
222 if (id
> state
->useable_id
) {
223 state
->status
= NT_STATUS_OK
;
227 if (state
->useable_id
== state
->highest_id
) {
228 state
->status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
232 state
->useable_id
+=1;
236 static NTSTATUS
smb1srv_tcon_local_allocate_id(struct db_context
*db
,
240 struct db_record
**_rec
,
243 struct smb1srv_tcon_local_allocate_state state
= {
244 .lowest_id
= lowest_id
,
245 .highest_id
= highest_id
,
247 .useable_id
= lowest_id
,
248 .status
= NT_STATUS_INTERNAL_ERROR
,
258 if (lowest_id
> highest_id
) {
259 return NT_STATUS_INSUFFICIENT_RESOURCES
;
263 * first we try randomly
265 range
= (highest_id
- lowest_id
) + 1;
267 for (i
= 0; i
< (range
/ 2); i
++) {
269 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
272 struct db_record
*rec
= NULL
;
274 id
= generate_random() % range
;
277 if (id
< lowest_id
) {
280 if (id
> highest_id
) {
284 key
= smbXsrv_tcon_local_id_to_key(id
, key_buf
);
286 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
288 return NT_STATUS_INSUFFICIENT_RESOURCES
;
291 val
= dbwrap_record_get_value(rec
);
292 if (val
.dsize
!= 0) {
303 * if the range is almost full,
304 * we traverse the whole table
305 * (this relies on sorted behavior of dbwrap_rbt)
307 status
= dbwrap_traverse_read(db
, smb1srv_tcon_local_allocate_traverse
,
309 if (NT_STATUS_IS_OK(status
)) {
310 if (NT_STATUS_IS_OK(state
.status
)) {
311 return NT_STATUS_INTERNAL_ERROR
;
314 if (!NT_STATUS_EQUAL(state
.status
, NT_STATUS_INTERNAL_ERROR
)) {
318 if (state
.useable_id
<= state
.highest_id
) {
319 state
.status
= NT_STATUS_OK
;
321 return NT_STATUS_INSUFFICIENT_RESOURCES
;
323 } else if (!NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_DB_CORRUPTION
)) {
325 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
327 * If we get anything else it is an error, because it
328 * means we did not manage to find a free slot in
331 return NT_STATUS_INSUFFICIENT_RESOURCES
;
334 if (NT_STATUS_IS_OK(state
.status
)) {
336 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
339 struct db_record
*rec
= NULL
;
341 id
= state
.useable_id
;
343 key
= smbXsrv_tcon_local_id_to_key(id
, key_buf
);
345 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
347 return NT_STATUS_INSUFFICIENT_RESOURCES
;
350 val
= dbwrap_record_get_value(rec
);
351 if (val
.dsize
!= 0) {
353 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
364 struct smbXsrv_tcon_local_fetch_state
{
365 struct smbXsrv_tcon
*tcon
;
369 static void smbXsrv_tcon_local_fetch_parser(TDB_DATA key
, TDB_DATA data
,
372 struct smbXsrv_tcon_local_fetch_state
*state
=
373 (struct smbXsrv_tcon_local_fetch_state
*)private_data
;
376 if (data
.dsize
!= sizeof(ptr
)) {
377 state
->status
= NT_STATUS_INTERNAL_DB_ERROR
;
381 memcpy(&ptr
, data
.dptr
, data
.dsize
);
382 state
->tcon
= talloc_get_type_abort(ptr
, struct smbXsrv_tcon
);
383 state
->status
= NT_STATUS_OK
;
386 static NTSTATUS
smbXsrv_tcon_local_lookup(struct smbXsrv_tcon_table
*table
,
387 uint32_t tcon_local_id
,
389 struct smbXsrv_tcon
**_tcon
)
391 struct smbXsrv_tcon_local_fetch_state state
= {
393 .status
= NT_STATUS_INTERNAL_ERROR
,
395 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
401 if (tcon_local_id
== 0) {
402 return NT_STATUS_NETWORK_NAME_DELETED
;
406 /* this might happen before the end of negprot */
407 return NT_STATUS_NETWORK_NAME_DELETED
;
410 if (table
->local
.db_ctx
== NULL
) {
411 return NT_STATUS_INTERNAL_ERROR
;
414 key
= smbXsrv_tcon_local_id_to_key(tcon_local_id
, key_buf
);
416 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
417 smbXsrv_tcon_local_fetch_parser
,
419 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
420 return NT_STATUS_NETWORK_NAME_DELETED
;
421 } else if (!NT_STATUS_IS_OK(status
)) {
424 if (!NT_STATUS_IS_OK(state
.status
)) {
428 if (NT_STATUS_EQUAL(state
.tcon
->status
, NT_STATUS_NETWORK_NAME_DELETED
)) {
429 return NT_STATUS_NETWORK_NAME_DELETED
;
432 state
.tcon
->idle_time
= now
;
435 return state
.tcon
->status
;
438 static int smbXsrv_tcon_global_destructor(struct smbXsrv_tcon_global0
*global
)
443 static void smbXsrv_tcon_global_verify_record(struct db_record
*db_rec
,
447 struct smbXsrv_tcon_global0
**_g
);
449 static NTSTATUS
smbXsrv_tcon_global_allocate(struct db_context
*db
,
451 struct smbXsrv_tcon_global0
**_global
)
454 struct smbXsrv_tcon_global0
*global
= NULL
;
455 uint32_t last_free
= 0;
456 const uint32_t min_tries
= 3;
460 global
= talloc_zero(mem_ctx
, struct smbXsrv_tcon_global0
);
461 if (global
== NULL
) {
462 return NT_STATUS_NO_MEMORY
;
464 talloc_set_destructor(global
, smbXsrv_tcon_global_destructor
);
467 * Here we just randomly try the whole 32-bit space
469 * We use just 32-bit, because we want to reuse the
472 for (i
= 0; i
< UINT32_MAX
; i
++) {
473 bool is_free
= false;
474 bool was_free
= false;
476 uint8_t key_buf
[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
];
479 if (i
>= min_tries
&& last_free
!= 0) {
482 id
= generate_random();
487 if (id
== UINT32_MAX
) {
491 key
= smbXsrv_tcon_global_id_to_key(id
, key_buf
);
493 global
->db_rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
494 if (global
->db_rec
== NULL
) {
496 return NT_STATUS_INSUFFICIENT_RESOURCES
;
499 smbXsrv_tcon_global_verify_record(global
->db_rec
,
505 TALLOC_FREE(global
->db_rec
);
509 if (!was_free
&& i
< min_tries
) {
511 * The session_id is free now,
512 * but was not free before.
514 * This happens if a smbd crashed
515 * and did not cleanup the record.
517 * If this is one of our first tries,
518 * then we try to find a real free one.
520 if (last_free
== 0) {
523 TALLOC_FREE(global
->db_rec
);
527 global
->tcon_global_id
= id
;
533 /* should not be reached */
535 return NT_STATUS_INTERNAL_ERROR
;
538 static void smbXsrv_tcon_global_verify_record(struct db_record
*db_rec
,
542 struct smbXsrv_tcon_global0
**_g
)
547 struct smbXsrv_tcon_globalB global_blob
;
548 enum ndr_err_code ndr_err
;
549 struct smbXsrv_tcon_global0
*global
= NULL
;
551 TALLOC_CTX
*frame
= talloc_stackframe();
562 key
= dbwrap_record_get_key(db_rec
);
564 val
= dbwrap_record_get_value(db_rec
);
565 if (val
.dsize
== 0) {
574 blob
= data_blob_const(val
.dptr
, val
.dsize
);
576 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
577 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_tcon_globalB
);
578 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
579 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
580 DEBUG(1,("smbXsrv_tcon_global_verify_record: "
581 "key '%s' ndr_pull_struct_blob - %s\n",
582 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
588 DEBUG(10,("smbXsrv_tcon_global_verify_record\n"));
590 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
593 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
594 DEBUG(0,("smbXsrv_tcon_global_verify_record: "
595 "key '%s' use unsupported version %u\n",
596 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
597 global_blob
.version
));
598 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
603 global
= global_blob
.info
.info0
;
605 exists
= serverid_exists(&global
->server_id
);
607 struct server_id_buf idbuf
;
608 DEBUG(2,("smbXsrv_tcon_global_verify_record: "
609 "key '%s' server_id %s does not exist.\n",
610 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
611 server_id_str_buf(global
->server_id
, &idbuf
)));
613 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
616 dbwrap_record_delete(db_rec
);
622 *_g
= talloc_move(mem_ctx
, &global
);
627 static NTSTATUS
smbXsrv_tcon_global_store(struct smbXsrv_tcon_global0
*global
)
629 struct smbXsrv_tcon_globalB global_blob
;
630 DATA_BLOB blob
= data_blob_null
;
634 enum ndr_err_code ndr_err
;
637 * TODO: if we use other versions than '0'
638 * we would add glue code here, that would be able to
639 * store the information in the old format.
642 if (global
->db_rec
== NULL
) {
643 return NT_STATUS_INTERNAL_ERROR
;
646 key
= dbwrap_record_get_key(global
->db_rec
);
647 val
= dbwrap_record_get_value(global
->db_rec
);
649 ZERO_STRUCT(global_blob
);
650 global_blob
.version
= smbXsrv_version_global_current();
651 if (val
.dsize
>= 8) {
652 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
654 global_blob
.seqnum
+= 1;
655 global_blob
.info
.info0
= global
;
657 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
658 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_tcon_globalB
);
659 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
660 status
= ndr_map_error2ntstatus(ndr_err
);
661 DEBUG(1,("smbXsrv_tcon_global_store: key '%s' ndr_push - %s\n",
662 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
664 TALLOC_FREE(global
->db_rec
);
668 val
= make_tdb_data(blob
.data
, blob
.length
);
669 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
670 if (!NT_STATUS_IS_OK(status
)) {
671 DEBUG(1,("smbXsrv_tcon_global_store: key '%s' store - %s\n",
672 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
674 TALLOC_FREE(global
->db_rec
);
679 DEBUG(10,("smbXsrv_tcon_global_store: key '%s' stored\n",
680 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
)));
681 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB
, &global_blob
);
684 TALLOC_FREE(global
->db_rec
);
689 static int smbXsrv_tcon_destructor(struct smbXsrv_tcon
*tcon
)
693 status
= smbXsrv_tcon_disconnect(tcon
, 0);
694 if (!NT_STATUS_IS_OK(status
)) {
695 DEBUG(0, ("smbXsrv_tcon_destructor: "
696 "smbXsrv_tcon_disconnect() failed - %s\n",
700 TALLOC_FREE(tcon
->global
);
705 static NTSTATUS
smbXsrv_tcon_create(struct smbXsrv_tcon_table
*table
,
706 enum protocol_types protocol
,
707 struct server_id server_id
,
709 struct smbXsrv_tcon
**_tcon
)
711 struct db_record
*local_rec
= NULL
;
712 struct smbXsrv_tcon
*tcon
= NULL
;
715 struct smbXsrv_tcon_global0
*global
= NULL
;
718 if (table
->local
.num_tcons
>= table
->local
.max_tcons
) {
719 return NT_STATUS_INSUFFICIENT_RESOURCES
;
722 tcon
= talloc_zero(table
, struct smbXsrv_tcon
);
724 return NT_STATUS_NO_MEMORY
;
727 tcon
->status
= NT_STATUS_INTERNAL_ERROR
;
728 tcon
->idle_time
= now
;
730 status
= smbXsrv_tcon_global_allocate(table
->global
.db_ctx
,
732 if (!NT_STATUS_IS_OK(status
)) {
736 tcon
->global
= global
;
738 if (protocol
>= PROTOCOL_SMB2_02
) {
739 uint64_t id
= global
->tcon_global_id
;
740 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
743 global
->tcon_wire_id
= id
;
745 tcon
->local_id
= global
->tcon_global_id
;
747 key
= smbXsrv_tcon_local_id_to_key(tcon
->local_id
, key_buf
);
749 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
751 if (local_rec
== NULL
) {
753 return NT_STATUS_NO_MEMORY
;
756 val
= dbwrap_record_get_value(local_rec
);
757 if (val
.dsize
!= 0) {
759 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
763 status
= smb1srv_tcon_local_allocate_id(table
->local
.db_ctx
,
764 table
->local
.lowest_id
,
765 table
->local
.highest_id
,
769 if (!NT_STATUS_IS_OK(status
)) {
774 global
->tcon_wire_id
= tcon
->local_id
;
777 global
->creation_time
= now
;
779 global
->server_id
= server_id
;
782 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
783 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
784 TALLOC_FREE(local_rec
);
785 if (!NT_STATUS_IS_OK(status
)) {
789 table
->local
.num_tcons
+= 1;
791 talloc_set_destructor(tcon
, smbXsrv_tcon_destructor
);
793 status
= smbXsrv_tcon_global_store(global
);
794 if (!NT_STATUS_IS_OK(status
)) {
795 DEBUG(0,("smbXsrv_tcon_create: "
796 "global_id (0x%08x) store failed - %s\n",
797 tcon
->global
->tcon_global_id
,
804 struct smbXsrv_tconB tcon_blob
;
806 ZERO_STRUCT(tcon_blob
);
807 tcon_blob
.version
= SMBXSRV_VERSION_0
;
808 tcon_blob
.info
.info0
= tcon
;
810 DEBUG(10,("smbXsrv_tcon_create: global_id (0x%08x) stored\n",
811 tcon
->global
->tcon_global_id
));
812 NDR_PRINT_DEBUG(smbXsrv_tconB
, &tcon_blob
);
819 NTSTATUS
smbXsrv_tcon_update(struct smbXsrv_tcon
*tcon
)
821 struct smbXsrv_tcon_table
*table
= tcon
->table
;
823 uint8_t key_buf
[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
];
826 if (tcon
->global
->db_rec
!= NULL
) {
827 DEBUG(0, ("smbXsrv_tcon_update(0x%08x): "
828 "Called with db_rec != NULL'\n",
829 tcon
->global
->tcon_global_id
));
830 return NT_STATUS_INTERNAL_ERROR
;
833 key
= smbXsrv_tcon_global_id_to_key(tcon
->global
->tcon_global_id
,
836 tcon
->global
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
838 if (tcon
->global
->db_rec
== NULL
) {
839 DEBUG(0, ("smbXsrv_tcon_update(0x%08x): "
840 "Failed to lock global key '%s'\n",
841 tcon
->global
->tcon_global_id
,
842 hex_encode_talloc(talloc_tos(), key
.dptr
,
844 return NT_STATUS_INTERNAL_DB_ERROR
;
847 status
= smbXsrv_tcon_global_store(tcon
->global
);
848 if (!NT_STATUS_IS_OK(status
)) {
849 DEBUG(0,("smbXsrv_tcon_update: "
850 "global_id (0x%08x) store failed - %s\n",
851 tcon
->global
->tcon_global_id
,
857 struct smbXsrv_tconB tcon_blob
;
859 ZERO_STRUCT(tcon_blob
);
860 tcon_blob
.version
= SMBXSRV_VERSION_0
;
861 tcon_blob
.info
.info0
= tcon
;
863 DEBUG(10,("smbXsrv_tcon_update: global_id (0x%08x) stored\n",
864 tcon
->global
->tcon_global_id
));
865 NDR_PRINT_DEBUG(smbXsrv_tconB
, &tcon_blob
);
871 NTSTATUS
smbXsrv_tcon_disconnect(struct smbXsrv_tcon
*tcon
, uint64_t vuid
)
873 struct smbXsrv_tcon_table
*table
;
874 struct db_record
*local_rec
= NULL
;
875 struct db_record
*global_rec
= NULL
;
877 NTSTATUS error
= NT_STATUS_OK
;
879 if (tcon
->table
== NULL
) {
886 tcon
->status
= NT_STATUS_NETWORK_NAME_DELETED
;
888 global_rec
= tcon
->global
->db_rec
;
889 tcon
->global
->db_rec
= NULL
;
890 if (global_rec
== NULL
) {
891 uint8_t key_buf
[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE
];
894 key
= smbXsrv_tcon_global_id_to_key(
895 tcon
->global
->tcon_global_id
,
898 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
900 if (global_rec
== NULL
) {
901 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
902 "Failed to lock global key '%s'\n",
903 tcon
->global
->tcon_global_id
,
904 tcon
->global
->share_name
,
905 hex_encode_talloc(global_rec
, key
.dptr
,
907 error
= NT_STATUS_INTERNAL_ERROR
;
911 if (global_rec
!= NULL
) {
912 status
= dbwrap_record_delete(global_rec
);
913 if (!NT_STATUS_IS_OK(status
)) {
914 TDB_DATA key
= dbwrap_record_get_key(global_rec
);
916 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
917 "failed to delete global key '%s': %s\n",
918 tcon
->global
->tcon_global_id
,
919 tcon
->global
->share_name
,
920 hex_encode_talloc(global_rec
, key
.dptr
,
926 TALLOC_FREE(global_rec
);
928 local_rec
= tcon
->db_rec
;
929 if (local_rec
== NULL
) {
930 uint8_t key_buf
[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE
];
933 key
= smbXsrv_tcon_local_id_to_key(tcon
->local_id
, key_buf
);
935 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
937 if (local_rec
== NULL
) {
938 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
939 "Failed to lock local key '%s'\n",
940 tcon
->global
->tcon_global_id
,
941 tcon
->global
->share_name
,
942 hex_encode_talloc(local_rec
, key
.dptr
,
944 error
= NT_STATUS_INTERNAL_ERROR
;
948 if (local_rec
!= NULL
) {
949 status
= dbwrap_record_delete(local_rec
);
950 if (!NT_STATUS_IS_OK(status
)) {
951 TDB_DATA key
= dbwrap_record_get_key(local_rec
);
953 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
954 "failed to delete local key '%s': %s\n",
955 tcon
->global
->tcon_global_id
,
956 tcon
->global
->share_name
,
957 hex_encode_talloc(local_rec
, key
.dptr
,
962 table
->local
.num_tcons
-= 1;
964 if (tcon
->db_rec
== NULL
) {
965 TALLOC_FREE(local_rec
);
972 ok
= set_current_service(tcon
->compat
, 0, true);
974 status
= NT_STATUS_INTERNAL_ERROR
;
975 DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
976 "set_current_service() failed: %s\n",
977 tcon
->global
->tcon_global_id
,
978 tcon
->global
->share_name
,
984 close_cnum(tcon
->compat
, vuid
);
991 struct smbXsrv_tcon_disconnect_all_state
{
993 NTSTATUS first_status
;
997 static int smbXsrv_tcon_disconnect_all_callback(struct db_record
*local_rec
,
1000 static NTSTATUS
smbXsrv_tcon_disconnect_all(struct smbXsrv_tcon_table
*table
,
1003 struct smbXsrv_tcon_disconnect_all_state state
;
1007 if (table
== NULL
) {
1008 return NT_STATUS_OK
;
1014 status
= dbwrap_traverse(table
->local
.db_ctx
,
1015 smbXsrv_tcon_disconnect_all_callback
,
1017 if (!NT_STATUS_IS_OK(status
)) {
1018 DEBUG(0, ("smbXsrv_tcon_disconnect_all: "
1019 "dbwrap_traverse() failed: %s\n",
1020 nt_errstr(status
)));
1024 if (!NT_STATUS_IS_OK(state
.first_status
)) {
1025 DEBUG(0, ("smbXsrv_tcon_disconnect_all: "
1026 "count[%d] errors[%d] first[%s]\n",
1027 count
, state
.errors
,
1028 nt_errstr(state
.first_status
)));
1029 return state
.first_status
;
1032 return NT_STATUS_OK
;
1035 static int smbXsrv_tcon_disconnect_all_callback(struct db_record
*local_rec
,
1038 struct smbXsrv_tcon_disconnect_all_state
*state
=
1039 (struct smbXsrv_tcon_disconnect_all_state
*)private_data
;
1042 struct smbXsrv_tcon
*tcon
= NULL
;
1046 val
= dbwrap_record_get_value(local_rec
);
1047 if (val
.dsize
!= sizeof(ptr
)) {
1048 status
= NT_STATUS_INTERNAL_ERROR
;
1049 if (NT_STATUS_IS_OK(state
->first_status
)) {
1050 state
->first_status
= status
;
1056 memcpy(&ptr
, val
.dptr
, val
.dsize
);
1057 tcon
= talloc_get_type_abort(ptr
, struct smbXsrv_tcon
);
1060 if (vuid
== 0 && tcon
->compat
) {
1061 vuid
= tcon
->compat
->vuid
;
1064 tcon
->db_rec
= local_rec
;
1065 status
= smbXsrv_tcon_disconnect(tcon
, vuid
);
1066 if (!NT_STATUS_IS_OK(status
)) {
1067 if (NT_STATUS_IS_OK(state
->first_status
)) {
1068 state
->first_status
= status
;
1077 NTSTATUS
smb1srv_tcon_table_init(struct smbXsrv_connection
*conn
)
1079 struct smbXsrv_client
*client
= conn
->client
;
1082 * Allow a range from 1..65534 with 65534 values.
1084 client
->tcon_table
= talloc_zero(client
, struct smbXsrv_tcon_table
);
1085 if (client
->tcon_table
== NULL
) {
1086 return NT_STATUS_NO_MEMORY
;
1089 return smbXsrv_tcon_table_init(client
, client
->tcon_table
,
1094 NTSTATUS
smb1srv_tcon_create(struct smbXsrv_connection
*conn
,
1096 struct smbXsrv_tcon
**_tcon
)
1098 struct server_id id
= messaging_server_id(conn
->msg_ctx
);
1100 return smbXsrv_tcon_create(conn
->client
->tcon_table
,
1105 NTSTATUS
smb1srv_tcon_lookup(struct smbXsrv_connection
*conn
,
1106 uint16_t tree_id
, NTTIME now
,
1107 struct smbXsrv_tcon
**tcon
)
1109 uint32_t local_id
= tree_id
;
1111 return smbXsrv_tcon_local_lookup(conn
->client
->tcon_table
,
1112 local_id
, now
, tcon
);
1115 NTSTATUS
smb1srv_tcon_disconnect_all(struct smbXsrv_connection
*conn
)
1117 struct smbXsrv_client
*client
= conn
->client
;
1120 * We do not pass a vuid here,
1121 * which means the vuid is taken from
1122 * the tcon->compat->vuid.
1124 * NOTE: that tcon->compat->vuid may point to
1125 * a none existing vuid (or the wrong one)
1126 * as the tcon can exist without a session
1129 * This matches the old behavior of
1130 * conn_close_all(), but we should think
1131 * about how to fix this in future.
1133 return smbXsrv_tcon_disconnect_all(client
->tcon_table
, 0);
1136 NTSTATUS
smb2srv_tcon_table_init(struct smbXsrv_session
*session
)
1139 * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
1141 session
->tcon_table
= talloc_zero(session
, struct smbXsrv_tcon_table
);
1142 if (session
->tcon_table
== NULL
) {
1143 return NT_STATUS_NO_MEMORY
;
1146 return smbXsrv_tcon_table_init(session
, session
->tcon_table
,
1151 NTSTATUS
smb2srv_tcon_create(struct smbXsrv_session
*session
,
1153 struct smbXsrv_tcon
**_tcon
)
1155 struct server_id id
= messaging_server_id(session
->client
->msg_ctx
);
1157 return smbXsrv_tcon_create(session
->tcon_table
,
1162 NTSTATUS
smb2srv_tcon_lookup(struct smbXsrv_session
*session
,
1163 uint32_t tree_id
, NTTIME now
,
1164 struct smbXsrv_tcon
**tcon
)
1166 uint32_t local_id
= tree_id
;
1168 return smbXsrv_tcon_local_lookup(session
->tcon_table
,
1169 local_id
, now
, tcon
);
1172 NTSTATUS
smb2srv_tcon_disconnect_all(struct smbXsrv_session
*session
)
1176 if (session
->compat
) {
1177 vuid
= session
->compat
->vuid
;
1182 return smbXsrv_tcon_disconnect_all(session
->tcon_table
, vuid
);
1185 struct smbXsrv_tcon_global_traverse_state
{
1186 int (*fn
)(struct smbXsrv_tcon_global0
*, void *);
1190 static int smbXsrv_tcon_global_traverse_fn(struct db_record
*rec
, void *data
)
1193 struct smbXsrv_tcon_global_traverse_state
*state
=
1194 (struct smbXsrv_tcon_global_traverse_state
*)data
;
1195 TDB_DATA key
= dbwrap_record_get_key(rec
);
1196 TDB_DATA val
= dbwrap_record_get_value(rec
);
1197 DATA_BLOB blob
= data_blob_const(val
.dptr
, val
.dsize
);
1198 struct smbXsrv_tcon_globalB global_blob
;
1199 enum ndr_err_code ndr_err
;
1200 TALLOC_CTX
*frame
= talloc_stackframe();
1202 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
1203 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_tcon_globalB
);
1204 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1205 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
1206 "key '%s' ndr_pull_struct_blob - %s\n",
1207 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1208 ndr_errstr(ndr_err
)));
1212 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
1213 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
1214 "key '%s' unsuported version - %d\n",
1215 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1216 (int)global_blob
.version
));
1220 global_blob
.info
.info0
->db_rec
= rec
;
1221 ret
= state
->fn(global_blob
.info
.info0
, state
->private_data
);
1227 NTSTATUS
smbXsrv_tcon_global_traverse(
1228 int (*fn
)(struct smbXsrv_tcon_global0
*, void *),
1233 struct smbXsrv_tcon_global_traverse_state state
= {
1235 .private_data
= private_data
,
1239 status
= smbXsrv_tcon_global_init();
1240 if (!NT_STATUS_IS_OK(status
)) {
1242 DEBUG(0, ("Failed to initialize tcon_global: %s\n",
1243 nt_errstr(status
)));
1247 status
= dbwrap_traverse_read(smbXsrv_tcon_global_db_ctx
,
1248 smbXsrv_tcon_global_traverse_fn
,