2 Unix SMB/CIFS implementation.
4 Copyright (C) Stefan Metzmacher 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"
28 #include "../libcli/security/security.h"
30 #include "lib/util/util_tdb.h"
31 #include "librpc/gen_ndr/ndr_smbXsrv.h"
32 #include <ccan/hash/hash.h>
35 struct smbXsrv_open_table
{
37 struct db_context
*db_ctx
;
44 struct db_context
*db_ctx
;
48 static struct db_context
*smbXsrv_open_global_db_ctx
= NULL
;
50 NTSTATUS
smbXsrv_open_global_init(void)
52 const char *global_path
= NULL
;
53 struct db_context
*db_ctx
= NULL
;
55 if (smbXsrv_open_global_db_ctx
!= NULL
) {
59 global_path
= lock_path("smbXsrv_open_global.tdb");
61 db_ctx
= db_open(NULL
, global_path
,
65 TDB_INCOMPATIBLE_HASH
,
66 O_RDWR
| O_CREAT
, 0600,
72 status
= map_nt_error_from_unix_common(errno
);
77 smbXsrv_open_global_db_ctx
= db_ctx
;
84 * We need to store the keys in big endian so that dbwrap_rbt's memcmp
85 * has the same result as integer comparison between the uint32_t
88 * TODO: implement string based key
91 #define SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
93 static TDB_DATA
smbXsrv_open_global_id_to_key(uint32_t id
,
98 RSIVAL(key_buf
, 0, id
);
100 key
= make_tdb_data(key_buf
, SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
);
106 static NTSTATUS
smbXsrv_open_global_key_to_id(TDB_DATA key
, uint32_t *id
)
109 return NT_STATUS_INVALID_PARAMETER
;
112 if (key
.dsize
!= SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
) {
113 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
116 *id
= RIVAL(key
.dptr
, 0);
122 #define SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
124 static TDB_DATA
smbXsrv_open_local_id_to_key(uint32_t id
,
129 RSIVAL(key_buf
, 0, id
);
131 key
= make_tdb_data(key_buf
, SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE
);
136 static NTSTATUS
smbXsrv_open_local_key_to_id(TDB_DATA key
, uint32_t *id
)
139 return NT_STATUS_INVALID_PARAMETER
;
142 if (key
.dsize
!= SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE
) {
143 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
146 *id
= RIVAL(key
.dptr
, 0);
151 static NTSTATUS
smbXsrv_open_table_init(struct smbXsrv_connection
*conn
,
156 struct smbXsrv_client
*client
= conn
->client
;
157 struct smbXsrv_open_table
*table
;
161 if (lowest_id
> highest_id
) {
162 return NT_STATUS_INTERNAL_ERROR
;
165 max_range
= highest_id
;
166 max_range
-= lowest_id
;
169 if (max_opens
> max_range
) {
170 return NT_STATUS_INTERNAL_ERROR
;
173 table
= talloc_zero(client
, struct smbXsrv_open_table
);
175 return NT_STATUS_NO_MEMORY
;
178 table
->local
.db_ctx
= db_open_rbt(table
);
179 if (table
->local
.db_ctx
== NULL
) {
181 return NT_STATUS_NO_MEMORY
;
183 table
->local
.lowest_id
= lowest_id
;
184 table
->local
.highest_id
= highest_id
;
185 table
->local
.max_opens
= max_opens
;
187 status
= smbXsrv_open_global_init();
188 if (!NT_STATUS_IS_OK(status
)) {
193 table
->global
.db_ctx
= smbXsrv_open_global_db_ctx
;
195 client
->open_table
= table
;
199 struct smbXsrv_open_local_allocate_state
{
200 const uint32_t lowest_id
;
201 const uint32_t highest_id
;
207 static int smbXsrv_open_local_allocate_traverse(struct db_record
*rec
,
210 struct smbXsrv_open_local_allocate_state
*state
=
211 (struct smbXsrv_open_local_allocate_state
*)private_data
;
212 TDB_DATA key
= dbwrap_record_get_key(rec
);
216 status
= smbXsrv_open_local_key_to_id(key
, &id
);
217 if (!NT_STATUS_IS_OK(status
)) {
218 state
->status
= status
;
222 if (id
<= state
->last_id
) {
223 state
->status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
228 if (id
> state
->useable_id
) {
229 state
->status
= NT_STATUS_OK
;
233 if (state
->useable_id
== state
->highest_id
) {
234 state
->status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
238 state
->useable_id
+=1;
242 static NTSTATUS
smbXsrv_open_local_allocate_id(struct db_context
*db
,
246 struct db_record
**_rec
,
249 struct smbXsrv_open_local_allocate_state state
= {
250 .lowest_id
= lowest_id
,
251 .highest_id
= highest_id
,
253 .useable_id
= lowest_id
,
254 .status
= NT_STATUS_INTERNAL_ERROR
,
264 if (lowest_id
> highest_id
) {
265 return NT_STATUS_INSUFFICIENT_RESOURCES
;
269 * first we try randomly
271 range
= (highest_id
- lowest_id
) + 1;
273 for (i
= 0; i
< (range
/ 2); i
++) {
275 uint8_t key_buf
[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE
];
278 struct db_record
*rec
= NULL
;
280 id
= generate_random() % range
;
283 if (id
< lowest_id
) {
286 if (id
> highest_id
) {
290 key
= smbXsrv_open_local_id_to_key(id
, key_buf
);
292 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
294 return NT_STATUS_INSUFFICIENT_RESOURCES
;
297 val
= dbwrap_record_get_value(rec
);
298 if (val
.dsize
!= 0) {
309 * if the range is almost full,
310 * we traverse the whole table
311 * (this relies on sorted behavior of dbwrap_rbt)
313 status
= dbwrap_traverse_read(db
, smbXsrv_open_local_allocate_traverse
,
315 if (NT_STATUS_IS_OK(status
)) {
316 if (NT_STATUS_IS_OK(state
.status
)) {
317 return NT_STATUS_INTERNAL_ERROR
;
320 if (!NT_STATUS_EQUAL(state
.status
, NT_STATUS_INTERNAL_ERROR
)) {
324 if (state
.useable_id
<= state
.highest_id
) {
325 state
.status
= NT_STATUS_OK
;
327 return NT_STATUS_INSUFFICIENT_RESOURCES
;
329 } else if (!NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_DB_CORRUPTION
)) {
331 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
333 * If we get anything else it is an error, because it
334 * means we did not manage to find a free slot in
337 return NT_STATUS_INSUFFICIENT_RESOURCES
;
340 if (NT_STATUS_IS_OK(state
.status
)) {
342 uint8_t key_buf
[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE
];
345 struct db_record
*rec
= NULL
;
347 id
= state
.useable_id
;
349 key
= smbXsrv_open_local_id_to_key(id
, key_buf
);
351 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
353 return NT_STATUS_INSUFFICIENT_RESOURCES
;
356 val
= dbwrap_record_get_value(rec
);
357 if (val
.dsize
!= 0) {
359 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
370 struct smbXsrv_open_local_fetch_state
{
371 struct smbXsrv_open
*op
;
375 static void smbXsrv_open_local_fetch_parser(TDB_DATA key
, TDB_DATA data
,
378 struct smbXsrv_open_local_fetch_state
*state
=
379 (struct smbXsrv_open_local_fetch_state
*)private_data
;
382 if (data
.dsize
!= sizeof(ptr
)) {
383 state
->status
= NT_STATUS_INTERNAL_DB_ERROR
;
387 memcpy(&ptr
, data
.dptr
, data
.dsize
);
388 state
->op
= talloc_get_type_abort(ptr
, struct smbXsrv_open
);
389 state
->status
= NT_STATUS_OK
;
392 static NTSTATUS
smbXsrv_open_local_lookup(struct smbXsrv_open_table
*table
,
393 uint32_t open_local_id
,
394 uint32_t open_global_id
,
396 struct smbXsrv_open
**_open
)
398 struct smbXsrv_open_local_fetch_state state
= {
400 .status
= NT_STATUS_INTERNAL_ERROR
,
402 uint8_t key_buf
[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE
];
408 if (open_local_id
== 0) {
409 return NT_STATUS_FILE_CLOSED
;
413 /* this might happen before the end of negprot */
414 return NT_STATUS_FILE_CLOSED
;
417 if (table
->local
.db_ctx
== NULL
) {
418 return NT_STATUS_INTERNAL_ERROR
;
421 key
= smbXsrv_open_local_id_to_key(open_local_id
, key_buf
);
423 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
424 smbXsrv_open_local_fetch_parser
,
426 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
427 return NT_STATUS_FILE_CLOSED
;
428 } else if (!NT_STATUS_IS_OK(status
)) {
431 if (!NT_STATUS_IS_OK(state
.status
)) {
435 if (NT_STATUS_EQUAL(state
.op
->status
, NT_STATUS_FILE_CLOSED
)) {
436 return NT_STATUS_FILE_CLOSED
;
439 if (open_global_id
== 0) {
440 /* make the global check a no-op for SMB1 */
441 open_global_id
= state
.op
->global
->open_global_id
;
444 if (state
.op
->global
->open_global_id
!= open_global_id
) {
445 return NT_STATUS_FILE_CLOSED
;
449 state
.op
->idle_time
= now
;
453 return state
.op
->status
;
456 static int smbXsrv_open_global_destructor(struct smbXsrv_open_global0
*global
)
461 static void smbXsrv_open_global_verify_record(struct db_record
*db_rec
,
465 struct smbXsrv_open_global0
**_g
);
467 static NTSTATUS
smbXsrv_open_global_allocate(struct db_context
*db
,
469 struct smbXsrv_open_global0
**_global
)
472 struct smbXsrv_open_global0
*global
= NULL
;
473 uint32_t last_free
= 0;
474 const uint32_t min_tries
= 3;
478 global
= talloc_zero(mem_ctx
, struct smbXsrv_open_global0
);
479 if (global
== NULL
) {
480 return NT_STATUS_NO_MEMORY
;
482 talloc_set_destructor(global
, smbXsrv_open_global_destructor
);
485 * Here we just randomly try the whole 32-bit space
487 * We use just 32-bit, because we want to reuse the
490 for (i
= 0; i
< UINT32_MAX
; i
++) {
491 bool is_free
= false;
492 bool was_free
= false;
494 uint8_t key_buf
[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
];
497 if (i
>= min_tries
&& last_free
!= 0) {
500 id
= generate_random();
505 if (id
== UINT32_MAX
) {
509 key
= smbXsrv_open_global_id_to_key(id
, key_buf
);
511 global
->db_rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
512 if (global
->db_rec
== NULL
) {
514 return NT_STATUS_INSUFFICIENT_RESOURCES
;
517 smbXsrv_open_global_verify_record(global
->db_rec
,
523 TALLOC_FREE(global
->db_rec
);
527 if (!was_free
&& i
< min_tries
) {
529 * The session_id is free now,
530 * but was not free before.
532 * This happens if a smbd crashed
533 * and did not cleanup the record.
535 * If this is one of our first tries,
536 * then we try to find a real free one.
538 if (last_free
== 0) {
541 TALLOC_FREE(global
->db_rec
);
545 global
->open_global_id
= id
;
551 /* should not be reached */
553 return NT_STATUS_INTERNAL_ERROR
;
556 static void smbXsrv_open_global_verify_record(struct db_record
*db_rec
,
560 struct smbXsrv_open_global0
**_g
)
565 struct smbXsrv_open_globalB global_blob
;
566 enum ndr_err_code ndr_err
;
567 struct smbXsrv_open_global0
*global
= NULL
;
569 TALLOC_CTX
*frame
= talloc_stackframe();
580 key
= dbwrap_record_get_key(db_rec
);
582 val
= dbwrap_record_get_value(db_rec
);
583 if (val
.dsize
== 0) {
584 DEBUG(10, ("%s: empty value\n", __func__
));
593 blob
= data_blob_const(val
.dptr
, val
.dsize
);
595 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
596 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_open_globalB
);
597 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
598 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
599 DEBUG(1,("smbXsrv_open_global_verify_record: "
600 "key '%s' ndr_pull_struct_blob - %s\n",
601 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
607 DEBUG(10,("smbXsrv_open_global_verify_record\n"));
608 if (CHECK_DEBUGLVL(10)) {
609 NDR_PRINT_DEBUG(smbXsrv_open_globalB
, &global_blob
);
612 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
613 DEBUG(0,("smbXsrv_open_global_verify_record: "
614 "key '%s' use unsupported version %u\n",
615 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
616 global_blob
.version
));
617 NDR_PRINT_DEBUG(smbXsrv_open_globalB
, &global_blob
);
622 global
= global_blob
.info
.info0
;
624 if (server_id_is_disconnected(&global
->server_id
)) {
627 exists
= serverid_exists(&global
->server_id
);
630 DEBUG(2,("smbXsrv_open_global_verify_record: "
631 "key '%s' server_id %s does not exist.\n",
632 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
633 server_id_str(frame
, &global
->server_id
)));
634 if (CHECK_DEBUGLVL(2)) {
635 NDR_PRINT_DEBUG(smbXsrv_open_globalB
, &global_blob
);
638 dbwrap_record_delete(db_rec
);
644 *_g
= talloc_move(mem_ctx
, &global
);
649 static NTSTATUS
smbXsrv_open_global_store(struct smbXsrv_open_global0
*global
)
651 struct smbXsrv_open_globalB global_blob
;
652 DATA_BLOB blob
= data_blob_null
;
656 enum ndr_err_code ndr_err
;
659 * TODO: if we use other versions than '0'
660 * we would add glue code here, that would be able to
661 * store the information in the old format.
664 if (global
->db_rec
== NULL
) {
665 return NT_STATUS_INTERNAL_ERROR
;
668 key
= dbwrap_record_get_key(global
->db_rec
);
669 val
= dbwrap_record_get_value(global
->db_rec
);
671 ZERO_STRUCT(global_blob
);
672 global_blob
.version
= smbXsrv_version_global_current();
673 if (val
.dsize
>= 8) {
674 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
676 global_blob
.seqnum
+= 1;
677 global_blob
.info
.info0
= global
;
679 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
680 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_open_globalB
);
681 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
682 status
= ndr_map_error2ntstatus(ndr_err
);
683 DEBUG(1,("smbXsrv_open_global_store: key '%s' ndr_push - %s\n",
684 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
686 TALLOC_FREE(global
->db_rec
);
690 val
= make_tdb_data(blob
.data
, blob
.length
);
691 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
692 if (!NT_STATUS_IS_OK(status
)) {
693 DEBUG(1,("smbXsrv_open_global_store: key '%s' store - %s\n",
694 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
696 TALLOC_FREE(global
->db_rec
);
700 if (CHECK_DEBUGLVL(10)) {
701 DEBUG(10,("smbXsrv_open_global_store: key '%s' stored\n",
702 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
)));
703 NDR_PRINT_DEBUG(smbXsrv_open_globalB
, &global_blob
);
706 TALLOC_FREE(global
->db_rec
);
711 static NTSTATUS
smbXsrv_open_global_lookup(struct smbXsrv_open_table
*table
,
712 uint32_t open_global_id
,
714 struct smbXsrv_open_global0
**_global
)
717 uint8_t key_buf
[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
];
718 struct db_record
*global_rec
= NULL
;
719 bool is_free
= false;
723 if (table
->global
.db_ctx
== NULL
) {
724 return NT_STATUS_INTERNAL_ERROR
;
727 key
= smbXsrv_open_global_id_to_key(open_global_id
, key_buf
);
729 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
, mem_ctx
, key
);
730 if (global_rec
== NULL
) {
731 DEBUG(0, ("smbXsrv_open_global_lookup(0x%08x): "
732 "Failed to lock global key '%s'\n",
734 hex_encode_talloc(talloc_tos(), key
.dptr
,
736 return NT_STATUS_INTERNAL_DB_ERROR
;
739 smbXsrv_open_global_verify_record(global_rec
,
745 DEBUG(10, ("%s: is_free=true\n", __func__
));
746 talloc_free(global_rec
);
747 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
750 (*_global
)->db_rec
= talloc_move(*_global
, &global_rec
);
752 talloc_set_destructor(*_global
, smbXsrv_open_global_destructor
);
757 static int smbXsrv_open_destructor(struct smbXsrv_open
*op
)
761 status
= smbXsrv_open_close(op
, 0);
762 if (!NT_STATUS_IS_OK(status
)) {
763 DEBUG(0, ("smbXsrv_open_destructor: "
764 "smbXsrv_open_close() failed - %s\n",
768 TALLOC_FREE(op
->global
);
773 NTSTATUS
smbXsrv_open_create(struct smbXsrv_connection
*conn
,
774 struct auth_session_info
*session_info
,
776 struct smbXsrv_open
**_open
)
778 struct smbXsrv_open_table
*table
= conn
->client
->open_table
;
779 struct db_record
*local_rec
= NULL
;
780 struct smbXsrv_open
*op
= NULL
;
783 struct smbXsrv_open_global0
*global
= NULL
;
785 struct dom_sid
*current_sid
= NULL
;
786 struct security_token
*current_token
= NULL
;
788 if (session_info
== NULL
) {
789 return NT_STATUS_INVALID_HANDLE
;
791 current_token
= session_info
->security_token
;
793 if (current_token
== NULL
) {
794 return NT_STATUS_INVALID_HANDLE
;
797 if (current_token
->num_sids
> PRIMARY_USER_SID_INDEX
) {
798 current_sid
= ¤t_token
->sids
[PRIMARY_USER_SID_INDEX
];
801 if (current_sid
== NULL
) {
802 return NT_STATUS_INVALID_HANDLE
;
805 if (table
->local
.num_opens
>= table
->local
.max_opens
) {
806 return NT_STATUS_INSUFFICIENT_RESOURCES
;
809 op
= talloc_zero(table
, struct smbXsrv_open
);
811 return NT_STATUS_NO_MEMORY
;
814 op
->status
= NT_STATUS_OK
; /* TODO: start with INTERNAL_ERROR */
817 status
= smbXsrv_open_global_allocate(table
->global
.db_ctx
,
819 if (!NT_STATUS_IS_OK(status
)) {
825 status
= smbXsrv_open_local_allocate_id(table
->local
.db_ctx
,
826 table
->local
.lowest_id
,
827 table
->local
.highest_id
,
831 if (!NT_STATUS_IS_OK(status
)) {
836 global
->open_persistent_id
= global
->open_global_id
;
837 global
->open_volatile_id
= op
->local_id
;
839 global
->server_id
= messaging_server_id(conn
->msg_ctx
);
840 global
->open_time
= now
;
841 global
->open_owner
= *current_sid
;
842 if (conn
->protocol
>= PROTOCOL_SMB2_10
) {
843 global
->client_guid
= conn
->smb2
.client
.guid
;
847 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
848 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
849 TALLOC_FREE(local_rec
);
850 if (!NT_STATUS_IS_OK(status
)) {
854 table
->local
.num_opens
+= 1;
856 talloc_set_destructor(op
, smbXsrv_open_destructor
);
858 status
= smbXsrv_open_global_store(global
);
859 if (!NT_STATUS_IS_OK(status
)) {
860 DEBUG(0,("smbXsrv_open_create: "
861 "global_id (0x%08x) store failed - %s\n",
862 op
->global
->open_global_id
,
868 if (CHECK_DEBUGLVL(10)) {
869 struct smbXsrv_openB open_blob
;
871 ZERO_STRUCT(open_blob
);
872 open_blob
.version
= SMBXSRV_VERSION_0
;
873 open_blob
.info
.info0
= op
;
875 DEBUG(10,("smbXsrv_open_create: global_id (0x%08x) stored\n",
876 op
->global
->open_global_id
));
877 NDR_PRINT_DEBUG(smbXsrv_openB
, &open_blob
);
884 uint32_t smbXsrv_open_hash(struct smbXsrv_open
*_open
)
889 SBVAL(buf
, 0, _open
->global
->open_persistent_id
);
890 SBVAL(buf
, 8, _open
->global
->open_volatile_id
);
891 SBVAL(buf
, 16, _open
->global
->open_time
);
893 ret
= hash(buf
, sizeof(buf
), 0);
902 NTSTATUS
smbXsrv_open_update(struct smbXsrv_open
*op
)
904 struct smbXsrv_open_table
*table
= op
->table
;
906 uint8_t key_buf
[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
];
909 if (op
->global
->db_rec
!= NULL
) {
910 DEBUG(0, ("smbXsrv_open_update(0x%08x): "
911 "Called with db_rec != NULL'\n",
912 op
->global
->open_global_id
));
913 return NT_STATUS_INTERNAL_ERROR
;
916 key
= smbXsrv_open_global_id_to_key(op
->global
->open_global_id
,
919 op
->global
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
921 if (op
->global
->db_rec
== NULL
) {
922 DEBUG(0, ("smbXsrv_open_update(0x%08x): "
923 "Failed to lock global key '%s'\n",
924 op
->global
->open_global_id
,
925 hex_encode_talloc(talloc_tos(), key
.dptr
,
927 return NT_STATUS_INTERNAL_DB_ERROR
;
930 status
= smbXsrv_open_global_store(op
->global
);
931 if (!NT_STATUS_IS_OK(status
)) {
932 DEBUG(0,("smbXsrv_open_update: "
933 "global_id (0x%08x) store failed - %s\n",
934 op
->global
->open_global_id
,
939 if (CHECK_DEBUGLVL(10)) {
940 struct smbXsrv_openB open_blob
;
942 ZERO_STRUCT(open_blob
);
943 open_blob
.version
= SMBXSRV_VERSION_0
;
944 open_blob
.info
.info0
= op
;
946 DEBUG(10,("smbXsrv_open_update: global_id (0x%08x) stored\n",
947 op
->global
->open_global_id
));
948 NDR_PRINT_DEBUG(smbXsrv_openB
, &open_blob
);
954 NTSTATUS
smbXsrv_open_close(struct smbXsrv_open
*op
, NTTIME now
)
956 struct smbXsrv_open_table
*table
;
957 struct db_record
*local_rec
= NULL
;
958 struct db_record
*global_rec
= NULL
;
960 NTSTATUS error
= NT_STATUS_OK
;
962 if (op
->table
== NULL
) {
969 op
->status
= NT_STATUS_FILE_CLOSED
;
970 op
->global
->disconnect_time
= now
;
971 server_id_set_disconnected(&op
->global
->server_id
);
973 global_rec
= op
->global
->db_rec
;
974 op
->global
->db_rec
= NULL
;
975 if (global_rec
== NULL
) {
976 uint8_t key_buf
[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
];
979 key
= smbXsrv_open_global_id_to_key(
980 op
->global
->open_global_id
,
983 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
985 if (global_rec
== NULL
) {
986 DEBUG(0, ("smbXsrv_open_close(0x%08x): "
987 "Failed to lock global key '%s'\n",
988 op
->global
->open_global_id
,
989 hex_encode_talloc(global_rec
, key
.dptr
,
991 error
= NT_STATUS_INTERNAL_ERROR
;
995 if (global_rec
!= NULL
&& op
->global
->durable
) {
997 * If it is a durable open we need to update the global part
998 * instead of deleting it
1000 op
->global
->db_rec
= global_rec
;
1001 status
= smbXsrv_open_global_store(op
->global
);
1002 if (NT_STATUS_IS_OK(status
)) {
1004 * smbXsrv_open_global_store does the free
1005 * of op->global->db_rec
1009 if (!NT_STATUS_IS_OK(status
)) {
1010 DEBUG(0,("smbXsrv_open_close(0x%08x)"
1011 "smbXsrv_open_global_store() failed - %s\n",
1012 op
->global
->open_global_id
,
1013 nt_errstr(status
)));
1017 if (NT_STATUS_IS_OK(status
) && CHECK_DEBUGLVL(10)) {
1018 struct smbXsrv_openB open_blob
;
1020 ZERO_STRUCT(open_blob
);
1021 open_blob
.version
= SMBXSRV_VERSION_0
;
1022 open_blob
.info
.info0
= op
;
1024 DEBUG(10,("smbXsrv_open_close(0x%08x): "
1025 "stored disconnect\n",
1026 op
->global
->open_global_id
));
1027 NDR_PRINT_DEBUG(smbXsrv_openB
, &open_blob
);
1031 if (global_rec
!= NULL
) {
1032 status
= dbwrap_record_delete(global_rec
);
1033 if (!NT_STATUS_IS_OK(status
)) {
1034 TDB_DATA key
= dbwrap_record_get_key(global_rec
);
1036 DEBUG(0, ("smbXsrv_open_close(0x%08x): "
1037 "failed to delete global key '%s': %s\n",
1038 op
->global
->open_global_id
,
1039 hex_encode_talloc(global_rec
, key
.dptr
,
1041 nt_errstr(status
)));
1045 TALLOC_FREE(global_rec
);
1047 local_rec
= op
->db_rec
;
1048 if (local_rec
== NULL
) {
1049 uint8_t key_buf
[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE
];
1052 key
= smbXsrv_open_local_id_to_key(op
->local_id
, key_buf
);
1054 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
1056 if (local_rec
== NULL
) {
1057 DEBUG(0, ("smbXsrv_open_close(0x%08x): "
1058 "Failed to lock local key '%s'\n",
1059 op
->global
->open_global_id
,
1060 hex_encode_talloc(local_rec
, key
.dptr
,
1062 error
= NT_STATUS_INTERNAL_ERROR
;
1066 if (local_rec
!= NULL
) {
1067 status
= dbwrap_record_delete(local_rec
);
1068 if (!NT_STATUS_IS_OK(status
)) {
1069 TDB_DATA key
= dbwrap_record_get_key(local_rec
);
1071 DEBUG(0, ("smbXsrv_open_close(0x%08x): "
1072 "failed to delete local key '%s': %s\n",
1073 op
->global
->open_global_id
,
1074 hex_encode_talloc(local_rec
, key
.dptr
,
1076 nt_errstr(status
)));
1079 table
->local
.num_opens
-= 1;
1081 if (op
->db_rec
== NULL
) {
1082 TALLOC_FREE(local_rec
);
1087 op
->compat
->op
= NULL
;
1088 file_free(NULL
, op
->compat
);
1095 NTSTATUS
smb1srv_open_table_init(struct smbXsrv_connection
*conn
)
1100 * Allow a range from 1..65534.
1102 * With real_max_open_files possible ids,
1103 * truncated to the SMB1 limit of 16-bit.
1105 * 0 and 0xFFFF are no valid ids.
1107 max_opens
= conn
->client
->sconn
->real_max_open_files
;
1108 max_opens
= MIN(max_opens
, UINT16_MAX
- 1);
1110 return smbXsrv_open_table_init(conn
, 1, UINT16_MAX
- 1, max_opens
);
1113 NTSTATUS
smb1srv_open_lookup(struct smbXsrv_connection
*conn
,
1114 uint16_t fnum
, NTTIME now
,
1115 struct smbXsrv_open
**_open
)
1117 struct smbXsrv_open_table
*table
= conn
->client
->open_table
;
1118 uint32_t local_id
= fnum
;
1119 uint32_t global_id
= 0;
1121 return smbXsrv_open_local_lookup(table
, local_id
, global_id
, now
, _open
);
1124 NTSTATUS
smb2srv_open_table_init(struct smbXsrv_connection
*conn
)
1129 * Allow a range from 1..4294967294.
1131 * With real_max_open_files possible ids,
1132 * truncated to 16-bit (the same as SMB1 for now).
1134 * 0 and 0xFFFFFFFF are no valid ids.
1136 * The usage of conn->sconn->real_max_open_files
1137 * is the reason that we use one open table per
1138 * transport connection (as we still have a 1:1 mapping
1139 * between process and transport connection).
1141 max_opens
= conn
->client
->sconn
->real_max_open_files
;
1142 max_opens
= MIN(max_opens
, UINT16_MAX
- 1);
1144 return smbXsrv_open_table_init(conn
, 1, UINT32_MAX
- 1, max_opens
);
1147 NTSTATUS
smb2srv_open_lookup(struct smbXsrv_connection
*conn
,
1148 uint64_t persistent_id
,
1149 uint64_t volatile_id
,
1151 struct smbXsrv_open
**_open
)
1153 struct smbXsrv_open_table
*table
= conn
->client
->open_table
;
1154 uint32_t local_id
= volatile_id
& UINT32_MAX
;
1155 uint64_t local_zeros
= volatile_id
& 0xFFFFFFFF00000000LLU
;
1156 uint32_t global_id
= persistent_id
& UINT32_MAX
;
1157 uint64_t global_zeros
= persistent_id
& 0xFFFFFFFF00000000LLU
;
1159 if (local_zeros
!= 0) {
1160 return NT_STATUS_FILE_CLOSED
;
1163 if (global_zeros
!= 0) {
1164 return NT_STATUS_FILE_CLOSED
;
1167 if (global_id
== 0) {
1168 return NT_STATUS_FILE_CLOSED
;
1171 return smbXsrv_open_local_lookup(table
, local_id
, global_id
, now
, _open
);
1174 NTSTATUS
smb2srv_open_recreate(struct smbXsrv_connection
*conn
,
1175 struct auth_session_info
*session_info
,
1176 uint64_t persistent_id
,
1177 const struct GUID
*create_guid
,
1179 struct smbXsrv_open
**_open
)
1181 struct smbXsrv_open_table
*table
= conn
->client
->open_table
;
1182 struct db_record
*local_rec
= NULL
;
1183 struct smbXsrv_open
*op
= NULL
;
1186 uint32_t global_id
= persistent_id
& UINT32_MAX
;
1187 uint64_t global_zeros
= persistent_id
& 0xFFFFFFFF00000000LLU
;
1189 struct security_token
*current_token
= NULL
;
1191 if (session_info
== NULL
) {
1192 DEBUG(10, ("session_info=NULL\n"));
1193 return NT_STATUS_INVALID_HANDLE
;
1195 current_token
= session_info
->security_token
;
1197 if (current_token
== NULL
) {
1198 DEBUG(10, ("current_token=NULL\n"));
1199 return NT_STATUS_INVALID_HANDLE
;
1202 if (global_zeros
!= 0) {
1203 DEBUG(10, ("global_zeros!=0\n"));
1204 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1207 op
= talloc_zero(table
, struct smbXsrv_open
);
1209 return NT_STATUS_NO_MEMORY
;
1213 status
= smbXsrv_open_global_lookup(table
, global_id
, op
, &op
->global
);
1214 if (!NT_STATUS_IS_OK(status
)) {
1216 DEBUG(10, ("smbXsrv_open_global_lookup returned %s\n",
1217 nt_errstr(status
)));
1222 * If the provided create_guid is NULL, this means that
1223 * the reconnect request was a v1 request. In that case
1224 * we should skipt the create GUID verification, since
1225 * it is valid to v1-reconnect a v2-opened handle.
1227 if ((create_guid
!= NULL
) &&
1228 !GUID_equal(&op
->global
->create_guid
, create_guid
))
1231 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1234 if (!security_token_is_sid(current_token
, &op
->global
->open_owner
)) {
1236 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1239 if (!op
->global
->durable
) {
1241 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1244 if (table
->local
.num_opens
>= table
->local
.max_opens
) {
1246 return NT_STATUS_INSUFFICIENT_RESOURCES
;
1249 status
= smbXsrv_open_local_allocate_id(table
->local
.db_ctx
,
1250 table
->local
.lowest_id
,
1251 table
->local
.highest_id
,
1255 if (!NT_STATUS_IS_OK(status
)) {
1260 op
->idle_time
= now
;
1261 op
->status
= NT_STATUS_FILE_CLOSED
;
1263 op
->global
->open_volatile_id
= op
->local_id
;
1264 op
->global
->server_id
= messaging_server_id(conn
->msg_ctx
);
1267 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
1268 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
1269 TALLOC_FREE(local_rec
);
1270 if (!NT_STATUS_IS_OK(status
)) {
1274 table
->local
.num_opens
+= 1;
1276 talloc_set_destructor(op
, smbXsrv_open_destructor
);
1278 status
= smbXsrv_open_global_store(op
->global
);
1279 if (!NT_STATUS_IS_OK(status
)) {
1284 if (CHECK_DEBUGLVL(10)) {
1285 struct smbXsrv_openB open_blob
;
1287 ZERO_STRUCT(open_blob
);
1288 open_blob
.version
= 0;
1289 open_blob
.info
.info0
= op
;
1291 DEBUG(10,("smbXsrv_open_recreate: global_id (0x%08x) stored\n",
1292 op
->global
->open_global_id
));
1293 NDR_PRINT_DEBUG(smbXsrv_openB
, &open_blob
);
1297 return NT_STATUS_OK
;
1301 static NTSTATUS
smbXsrv_open_global_parse_record(TALLOC_CTX
*mem_ctx
,
1302 struct db_record
*rec
,
1303 struct smbXsrv_open_global0
**global
)
1305 TDB_DATA key
= dbwrap_record_get_key(rec
);
1306 TDB_DATA val
= dbwrap_record_get_value(rec
);
1307 DATA_BLOB blob
= data_blob_const(val
.dptr
, val
.dsize
);
1308 struct smbXsrv_open_globalB global_blob
;
1309 enum ndr_err_code ndr_err
;
1311 TALLOC_CTX
*frame
= talloc_stackframe();
1313 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
1314 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_open_globalB
);
1315 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1316 DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:"
1317 "key '%s' ndr_pull_struct_blob - %s\n",
1318 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1319 ndr_errstr(ndr_err
)));
1320 status
= ndr_map_error2ntstatus(ndr_err
);
1324 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
1325 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
1326 DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:"
1327 "key '%s' unsuported version - %d - %s\n",
1328 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1329 (int)global_blob
.version
,
1330 nt_errstr(status
)));
1334 *global
= talloc_move(mem_ctx
, &global_blob
.info
.info0
);
1335 status
= NT_STATUS_OK
;
1341 struct smbXsrv_open_global_traverse_state
{
1342 int (*fn
)(struct smbXsrv_open_global0
*, void *);
1346 static int smbXsrv_open_global_traverse_fn(struct db_record
*rec
, void *data
)
1348 struct smbXsrv_open_global_traverse_state
*state
=
1349 (struct smbXsrv_open_global_traverse_state
*)data
;
1350 struct smbXsrv_open_global0
*global
= NULL
;
1354 status
= smbXsrv_open_global_parse_record(talloc_tos(), rec
, &global
);
1355 if (!NT_STATUS_IS_OK(status
)) {
1359 global
->db_rec
= rec
;
1360 ret
= state
->fn(global
, state
->private_data
);
1361 talloc_free(global
);
1365 NTSTATUS
smbXsrv_open_global_traverse(
1366 int (*fn
)(struct smbXsrv_open_global0
*, void *),
1372 struct smbXsrv_open_global_traverse_state state
= {
1374 .private_data
= private_data
,
1378 status
= smbXsrv_open_global_init();
1379 if (!NT_STATUS_IS_OK(status
)) {
1381 DEBUG(0, ("Failed to initialize open_global: %s\n",
1382 nt_errstr(status
)));
1386 status
= dbwrap_traverse_read(smbXsrv_open_global_db_ctx
,
1387 smbXsrv_open_global_traverse_fn
,
1395 NTSTATUS
smbXsrv_open_cleanup(uint64_t persistent_id
)
1397 NTSTATUS status
= NT_STATUS_OK
;
1398 TALLOC_CTX
*frame
= talloc_stackframe();
1399 struct smbXsrv_open_global0
*op
= NULL
;
1400 uint8_t key_buf
[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
];
1403 struct db_record
*rec
;
1404 bool delete_open
= false;
1405 uint32_t global_id
= persistent_id
& UINT32_MAX
;
1407 key
= smbXsrv_open_global_id_to_key(global_id
, key_buf
);
1408 rec
= dbwrap_fetch_locked(smbXsrv_open_global_db_ctx
, frame
, key
);
1410 status
= NT_STATUS_NOT_FOUND
;
1411 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
1412 "failed to fetch record from %s - %s\n",
1413 global_id
, dbwrap_name(smbXsrv_open_global_db_ctx
),
1414 nt_errstr(status
)));
1418 val
= dbwrap_record_get_value(rec
);
1419 if (val
.dsize
== 0) {
1420 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1421 "empty record in %s, skipping...\n",
1422 global_id
, dbwrap_name(smbXsrv_open_global_db_ctx
)));
1426 status
= smbXsrv_open_global_parse_record(talloc_tos(), rec
, &op
);
1427 if (!NT_STATUS_IS_OK(status
)) {
1428 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
1429 "failed to read record: %s\n",
1430 global_id
, nt_errstr(status
)));
1434 if (server_id_is_disconnected(&op
->server_id
)) {
1435 struct timeval now
, disconnect_time
;
1437 now
= timeval_current();
1438 nttime_to_timeval(&disconnect_time
, op
->disconnect_time
);
1439 tdiff
= usec_time_diff(&now
, &disconnect_time
);
1440 delete_open
= (tdiff
>= 1000*op
->durable_timeout_msec
);
1442 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1443 "disconnected at [%s] %us ago with "
1444 "timeout of %us -%s reached\n",
1446 nt_time_string(frame
, op
->disconnect_time
),
1447 (unsigned)(tdiff
/1000000),
1448 op
->durable_timeout_msec
/ 1000,
1449 delete_open
? "" : " not"));
1450 } else if (!serverid_exists(&op
->server_id
)) {
1451 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1452 "server[%s] does not exist\n",
1453 global_id
, server_id_str(frame
, &op
->server_id
)));
1461 status
= dbwrap_record_delete(rec
);
1462 if (!NT_STATUS_IS_OK(status
)) {
1463 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
1464 "failed to delete record"
1465 "from %s: %s\n", global_id
,
1466 dbwrap_name(smbXsrv_open_global_db_ctx
),
1467 nt_errstr(status
)));
1471 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1472 "delete record from %s\n",
1474 dbwrap_name(smbXsrv_open_global_db_ctx
)));