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_open_table
*table
;
160 if (lowest_id
> highest_id
) {
161 return NT_STATUS_INTERNAL_ERROR
;
164 max_range
= highest_id
;
165 max_range
-= lowest_id
;
168 if (max_opens
> max_range
) {
169 return NT_STATUS_INTERNAL_ERROR
;
172 table
= talloc_zero(conn
, struct smbXsrv_open_table
);
174 return NT_STATUS_NO_MEMORY
;
177 table
->local
.db_ctx
= db_open_rbt(table
);
178 if (table
->local
.db_ctx
== NULL
) {
180 return NT_STATUS_NO_MEMORY
;
182 table
->local
.lowest_id
= lowest_id
;
183 table
->local
.highest_id
= highest_id
;
184 table
->local
.max_opens
= max_opens
;
186 status
= smbXsrv_open_global_init();
187 if (!NT_STATUS_IS_OK(status
)) {
192 table
->global
.db_ctx
= smbXsrv_open_global_db_ctx
;
194 conn
->open_table
= table
;
198 struct smbXsrv_open_local_allocate_state
{
199 const uint32_t lowest_id
;
200 const uint32_t highest_id
;
206 static int smbXsrv_open_local_allocate_traverse(struct db_record
*rec
,
209 struct smbXsrv_open_local_allocate_state
*state
=
210 (struct smbXsrv_open_local_allocate_state
*)private_data
;
211 TDB_DATA key
= dbwrap_record_get_key(rec
);
215 status
= smbXsrv_open_local_key_to_id(key
, &id
);
216 if (!NT_STATUS_IS_OK(status
)) {
217 state
->status
= status
;
221 if (id
<= state
->last_id
) {
222 state
->status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
227 if (id
> state
->useable_id
) {
228 state
->status
= NT_STATUS_OK
;
232 if (state
->useable_id
== state
->highest_id
) {
233 state
->status
= NT_STATUS_INSUFFICIENT_RESOURCES
;
237 state
->useable_id
+=1;
241 static NTSTATUS
smbXsrv_open_local_allocate_id(struct db_context
*db
,
245 struct db_record
**_rec
,
248 struct smbXsrv_open_local_allocate_state state
= {
249 .lowest_id
= lowest_id
,
250 .highest_id
= highest_id
,
252 .useable_id
= lowest_id
,
253 .status
= NT_STATUS_INTERNAL_ERROR
,
263 if (lowest_id
> highest_id
) {
264 return NT_STATUS_INSUFFICIENT_RESOURCES
;
268 * first we try randomly
270 range
= (highest_id
- lowest_id
) + 1;
272 for (i
= 0; i
< (range
/ 2); i
++) {
274 uint8_t key_buf
[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE
];
277 struct db_record
*rec
= NULL
;
279 id
= generate_random() % range
;
282 if (id
< lowest_id
) {
285 if (id
> highest_id
) {
289 key
= smbXsrv_open_local_id_to_key(id
, key_buf
);
291 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
293 return NT_STATUS_INSUFFICIENT_RESOURCES
;
296 val
= dbwrap_record_get_value(rec
);
297 if (val
.dsize
!= 0) {
308 * if the range is almost full,
309 * we traverse the whole table
310 * (this relies on sorted behavior of dbwrap_rbt)
312 status
= dbwrap_traverse_read(db
, smbXsrv_open_local_allocate_traverse
,
314 if (NT_STATUS_IS_OK(status
)) {
315 if (NT_STATUS_IS_OK(state
.status
)) {
316 return NT_STATUS_INTERNAL_ERROR
;
319 if (!NT_STATUS_EQUAL(state
.status
, NT_STATUS_INTERNAL_ERROR
)) {
323 if (state
.useable_id
<= state
.highest_id
) {
324 state
.status
= NT_STATUS_OK
;
326 return NT_STATUS_INSUFFICIENT_RESOURCES
;
328 } else if (!NT_STATUS_EQUAL(status
, NT_STATUS_INTERNAL_DB_CORRUPTION
)) {
330 * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
332 * If we get anything else it is an error, because it
333 * means we did not manage to find a free slot in
336 return NT_STATUS_INSUFFICIENT_RESOURCES
;
339 if (NT_STATUS_IS_OK(state
.status
)) {
341 uint8_t key_buf
[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE
];
344 struct db_record
*rec
= NULL
;
346 id
= state
.useable_id
;
348 key
= smbXsrv_open_local_id_to_key(id
, key_buf
);
350 rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
352 return NT_STATUS_INSUFFICIENT_RESOURCES
;
355 val
= dbwrap_record_get_value(rec
);
356 if (val
.dsize
!= 0) {
358 return NT_STATUS_INTERNAL_DB_CORRUPTION
;
369 struct smbXsrv_open_local_fetch_state
{
370 struct smbXsrv_open
*op
;
374 static void smbXsrv_open_local_fetch_parser(TDB_DATA key
, TDB_DATA data
,
377 struct smbXsrv_open_local_fetch_state
*state
=
378 (struct smbXsrv_open_local_fetch_state
*)private_data
;
381 if (data
.dsize
!= sizeof(ptr
)) {
382 state
->status
= NT_STATUS_INTERNAL_DB_ERROR
;
386 memcpy(&ptr
, data
.dptr
, data
.dsize
);
387 state
->op
= talloc_get_type_abort(ptr
, struct smbXsrv_open
);
388 state
->status
= NT_STATUS_OK
;
391 static NTSTATUS
smbXsrv_open_local_lookup(struct smbXsrv_open_table
*table
,
392 uint32_t open_local_id
,
393 uint32_t open_global_id
,
395 struct smbXsrv_open
**_open
)
397 struct smbXsrv_open_local_fetch_state state
= {
399 .status
= NT_STATUS_INTERNAL_ERROR
,
401 uint8_t key_buf
[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE
];
407 if (open_local_id
== 0) {
408 return NT_STATUS_FILE_CLOSED
;
412 /* this might happen before the end of negprot */
413 return NT_STATUS_FILE_CLOSED
;
416 if (table
->local
.db_ctx
== NULL
) {
417 return NT_STATUS_INTERNAL_ERROR
;
420 key
= smbXsrv_open_local_id_to_key(open_local_id
, key_buf
);
422 status
= dbwrap_parse_record(table
->local
.db_ctx
, key
,
423 smbXsrv_open_local_fetch_parser
,
425 if (NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
426 return NT_STATUS_FILE_CLOSED
;
427 } else if (!NT_STATUS_IS_OK(status
)) {
430 if (!NT_STATUS_IS_OK(state
.status
)) {
434 if (NT_STATUS_EQUAL(state
.op
->status
, NT_STATUS_FILE_CLOSED
)) {
435 return NT_STATUS_FILE_CLOSED
;
438 if (open_global_id
== 0) {
439 /* make the global check a no-op for SMB1 */
440 open_global_id
= state
.op
->global
->open_global_id
;
443 if (state
.op
->global
->open_global_id
!= open_global_id
) {
444 return NT_STATUS_FILE_CLOSED
;
448 state
.op
->idle_time
= now
;
452 return state
.op
->status
;
455 static int smbXsrv_open_global_destructor(struct smbXsrv_open_global0
*global
)
460 static void smbXsrv_open_global_verify_record(struct db_record
*db_rec
,
464 struct smbXsrv_open_global0
**_g
);
466 static NTSTATUS
smbXsrv_open_global_allocate(struct db_context
*db
,
468 struct smbXsrv_open_global0
**_global
)
471 struct smbXsrv_open_global0
*global
= NULL
;
472 uint32_t last_free
= 0;
473 const uint32_t min_tries
= 3;
477 global
= talloc_zero(mem_ctx
, struct smbXsrv_open_global0
);
478 if (global
== NULL
) {
479 return NT_STATUS_NO_MEMORY
;
481 talloc_set_destructor(global
, smbXsrv_open_global_destructor
);
484 * Here we just randomly try the whole 32-bit space
486 * We use just 32-bit, because we want to reuse the
489 for (i
= 0; i
< UINT32_MAX
; i
++) {
490 bool is_free
= false;
491 bool was_free
= false;
493 uint8_t key_buf
[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
];
496 if (i
>= min_tries
&& last_free
!= 0) {
499 id
= generate_random();
504 if (id
== UINT32_MAX
) {
508 key
= smbXsrv_open_global_id_to_key(id
, key_buf
);
510 global
->db_rec
= dbwrap_fetch_locked(db
, mem_ctx
, key
);
511 if (global
->db_rec
== NULL
) {
513 return NT_STATUS_INSUFFICIENT_RESOURCES
;
516 smbXsrv_open_global_verify_record(global
->db_rec
,
522 TALLOC_FREE(global
->db_rec
);
526 if (!was_free
&& i
< min_tries
) {
528 * The session_id is free now,
529 * but was not free before.
531 * This happens if a smbd crashed
532 * and did not cleanup the record.
534 * If this is one of our first tries,
535 * then we try to find a real free one.
537 if (last_free
== 0) {
540 TALLOC_FREE(global
->db_rec
);
544 global
->open_global_id
= id
;
550 /* should not be reached */
552 return NT_STATUS_INTERNAL_ERROR
;
555 static void smbXsrv_open_global_verify_record(struct db_record
*db_rec
,
559 struct smbXsrv_open_global0
**_g
)
564 struct smbXsrv_open_globalB global_blob
;
565 enum ndr_err_code ndr_err
;
566 struct smbXsrv_open_global0
*global
= NULL
;
568 TALLOC_CTX
*frame
= talloc_stackframe();
579 key
= dbwrap_record_get_key(db_rec
);
581 val
= dbwrap_record_get_value(db_rec
);
582 if (val
.dsize
== 0) {
591 blob
= data_blob_const(val
.dptr
, val
.dsize
);
593 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
594 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_open_globalB
);
595 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
596 NTSTATUS status
= ndr_map_error2ntstatus(ndr_err
);
597 DEBUG(1,("smbXsrv_open_global_verify_record: "
598 "key '%s' ndr_pull_struct_blob - %s\n",
599 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
605 DEBUG(10,("smbXsrv_open_global_verify_record\n"));
606 if (CHECK_DEBUGLVL(10)) {
607 NDR_PRINT_DEBUG(smbXsrv_open_globalB
, &global_blob
);
610 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
611 DEBUG(0,("smbXsrv_open_global_verify_record: "
612 "key '%s' use unsupported version %u\n",
613 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
614 global_blob
.version
));
615 NDR_PRINT_DEBUG(smbXsrv_open_globalB
, &global_blob
);
620 global
= global_blob
.info
.info0
;
622 if (server_id_is_disconnected(&global
->server_id
)) {
625 exists
= serverid_exists(&global
->server_id
);
628 DEBUG(2,("smbXsrv_open_global_verify_record: "
629 "key '%s' server_id %s does not exist.\n",
630 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
631 server_id_str(frame
, &global
->server_id
)));
632 if (CHECK_DEBUGLVL(2)) {
633 NDR_PRINT_DEBUG(smbXsrv_open_globalB
, &global_blob
);
636 dbwrap_record_delete(db_rec
);
642 *_g
= talloc_move(mem_ctx
, &global
);
647 static NTSTATUS
smbXsrv_open_global_store(struct smbXsrv_open_global0
*global
)
649 struct smbXsrv_open_globalB global_blob
;
650 DATA_BLOB blob
= data_blob_null
;
654 enum ndr_err_code ndr_err
;
657 * TODO: if we use other versions than '0'
658 * we would add glue code here, that would be able to
659 * store the information in the old format.
662 if (global
->db_rec
== NULL
) {
663 return NT_STATUS_INTERNAL_ERROR
;
666 key
= dbwrap_record_get_key(global
->db_rec
);
667 val
= dbwrap_record_get_value(global
->db_rec
);
669 ZERO_STRUCT(global_blob
);
670 global_blob
.version
= smbXsrv_version_global_current();
671 if (val
.dsize
>= 8) {
672 global_blob
.seqnum
= IVAL(val
.dptr
, 4);
674 global_blob
.seqnum
+= 1;
675 global_blob
.info
.info0
= global
;
677 ndr_err
= ndr_push_struct_blob(&blob
, global
->db_rec
, &global_blob
,
678 (ndr_push_flags_fn_t
)ndr_push_smbXsrv_open_globalB
);
679 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
680 status
= ndr_map_error2ntstatus(ndr_err
);
681 DEBUG(1,("smbXsrv_open_global_store: key '%s' ndr_push - %s\n",
682 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
684 TALLOC_FREE(global
->db_rec
);
688 val
= make_tdb_data(blob
.data
, blob
.length
);
689 status
= dbwrap_record_store(global
->db_rec
, val
, TDB_REPLACE
);
690 if (!NT_STATUS_IS_OK(status
)) {
691 DEBUG(1,("smbXsrv_open_global_store: key '%s' store - %s\n",
692 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
),
694 TALLOC_FREE(global
->db_rec
);
698 if (CHECK_DEBUGLVL(10)) {
699 DEBUG(10,("smbXsrv_open_global_store: key '%s' stored\n",
700 hex_encode_talloc(global
->db_rec
, key
.dptr
, key
.dsize
)));
701 NDR_PRINT_DEBUG(smbXsrv_open_globalB
, &global_blob
);
704 TALLOC_FREE(global
->db_rec
);
709 static NTSTATUS
smbXsrv_open_global_lookup(struct smbXsrv_open_table
*table
,
710 uint32_t open_global_id
,
712 struct smbXsrv_open_global0
**_global
)
715 uint8_t key_buf
[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
];
716 struct db_record
*global_rec
= NULL
;
717 bool is_free
= false;
721 if (table
->global
.db_ctx
== NULL
) {
722 return NT_STATUS_INTERNAL_ERROR
;
725 key
= smbXsrv_open_global_id_to_key(open_global_id
, key_buf
);
727 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
, mem_ctx
, key
);
728 if (global_rec
== NULL
) {
729 DEBUG(0, ("smbXsrv_open_global_lookup(0x%08x): "
730 "Failed to lock global key '%s'\n",
732 hex_encode_talloc(talloc_tos(), key
.dptr
,
734 return NT_STATUS_INTERNAL_DB_ERROR
;
737 smbXsrv_open_global_verify_record(global_rec
,
743 talloc_free(global_rec
);
744 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
747 (*_global
)->db_rec
= talloc_move(*_global
, &global_rec
);
749 talloc_set_destructor(*_global
, smbXsrv_open_global_destructor
);
754 static int smbXsrv_open_destructor(struct smbXsrv_open
*op
)
758 status
= smbXsrv_open_close(op
, 0);
759 if (!NT_STATUS_IS_OK(status
)) {
760 DEBUG(0, ("smbXsrv_open_destructor: "
761 "smbXsrv_open_close() failed - %s\n",
765 TALLOC_FREE(op
->global
);
770 NTSTATUS
smbXsrv_open_create(struct smbXsrv_connection
*conn
,
771 struct auth_session_info
*session_info
,
773 struct smbXsrv_open
**_open
)
775 struct smbXsrv_open_table
*table
= conn
->open_table
;
776 struct db_record
*local_rec
= NULL
;
777 struct smbXsrv_open
*op
= NULL
;
780 struct smbXsrv_open_global0
*global
= NULL
;
782 struct dom_sid
*current_sid
= NULL
;
783 struct security_token
*current_token
= NULL
;
785 if (session_info
== NULL
) {
786 return NT_STATUS_INVALID_HANDLE
;
788 current_token
= session_info
->security_token
;
790 if (current_token
== NULL
) {
791 return NT_STATUS_INVALID_HANDLE
;
794 if (current_token
->num_sids
> PRIMARY_USER_SID_INDEX
) {
795 current_sid
= ¤t_token
->sids
[PRIMARY_USER_SID_INDEX
];
798 if (current_sid
== NULL
) {
799 return NT_STATUS_INVALID_HANDLE
;
802 if (table
->local
.num_opens
>= table
->local
.max_opens
) {
803 return NT_STATUS_INSUFFICIENT_RESOURCES
;
806 op
= talloc_zero(table
, struct smbXsrv_open
);
808 return NT_STATUS_NO_MEMORY
;
811 op
->status
= NT_STATUS_OK
; /* TODO: start with INTERNAL_ERROR */
814 status
= smbXsrv_open_global_allocate(table
->global
.db_ctx
,
816 if (!NT_STATUS_IS_OK(status
)) {
822 status
= smbXsrv_open_local_allocate_id(table
->local
.db_ctx
,
823 table
->local
.lowest_id
,
824 table
->local
.highest_id
,
828 if (!NT_STATUS_IS_OK(status
)) {
833 global
->open_persistent_id
= global
->open_global_id
;
834 global
->open_volatile_id
= op
->local_id
;
836 global
->server_id
= messaging_server_id(conn
->msg_ctx
);
837 global
->open_time
= now
;
838 global
->open_owner
= *current_sid
;
839 if (conn
->protocol
>= PROTOCOL_SMB2_10
) {
840 global
->client_guid
= conn
->smb2
.client
.guid
;
844 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
845 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
846 TALLOC_FREE(local_rec
);
847 if (!NT_STATUS_IS_OK(status
)) {
851 table
->local
.num_opens
+= 1;
853 talloc_set_destructor(op
, smbXsrv_open_destructor
);
855 status
= smbXsrv_open_global_store(global
);
856 if (!NT_STATUS_IS_OK(status
)) {
857 DEBUG(0,("smbXsrv_open_create: "
858 "global_id (0x%08x) store failed - %s\n",
859 op
->global
->open_global_id
,
865 if (CHECK_DEBUGLVL(10)) {
866 struct smbXsrv_openB open_blob
;
868 ZERO_STRUCT(open_blob
);
869 open_blob
.version
= SMBXSRV_VERSION_0
;
870 open_blob
.info
.info0
= op
;
872 DEBUG(10,("smbXsrv_open_create: global_id (0x%08x) stored\n",
873 op
->global
->open_global_id
));
874 NDR_PRINT_DEBUG(smbXsrv_openB
, &open_blob
);
881 uint32_t smbXsrv_open_hash(struct smbXsrv_open
*_open
)
886 SBVAL(buf
, 0, _open
->global
->open_persistent_id
);
887 SBVAL(buf
, 8, _open
->global
->open_volatile_id
);
888 SBVAL(buf
, 16, _open
->global
->open_time
);
890 ret
= hash(buf
, sizeof(buf
), 0);
899 NTSTATUS
smbXsrv_open_update(struct smbXsrv_open
*op
)
901 struct smbXsrv_open_table
*table
= op
->table
;
903 uint8_t key_buf
[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
];
906 if (op
->global
->db_rec
!= NULL
) {
907 DEBUG(0, ("smbXsrv_open_update(0x%08x): "
908 "Called with db_rec != NULL'\n",
909 op
->global
->open_global_id
));
910 return NT_STATUS_INTERNAL_ERROR
;
913 key
= smbXsrv_open_global_id_to_key(op
->global
->open_global_id
,
916 op
->global
->db_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
918 if (op
->global
->db_rec
== NULL
) {
919 DEBUG(0, ("smbXsrv_open_update(0x%08x): "
920 "Failed to lock global key '%s'\n",
921 op
->global
->open_global_id
,
922 hex_encode_talloc(talloc_tos(), key
.dptr
,
924 return NT_STATUS_INTERNAL_DB_ERROR
;
927 status
= smbXsrv_open_global_store(op
->global
);
928 if (!NT_STATUS_IS_OK(status
)) {
929 DEBUG(0,("smbXsrv_open_update: "
930 "global_id (0x%08x) store failed - %s\n",
931 op
->global
->open_global_id
,
936 if (CHECK_DEBUGLVL(10)) {
937 struct smbXsrv_openB open_blob
;
939 ZERO_STRUCT(open_blob
);
940 open_blob
.version
= SMBXSRV_VERSION_0
;
941 open_blob
.info
.info0
= op
;
943 DEBUG(10,("smbXsrv_open_update: global_id (0x%08x) stored\n",
944 op
->global
->open_global_id
));
945 NDR_PRINT_DEBUG(smbXsrv_openB
, &open_blob
);
951 NTSTATUS
smbXsrv_open_close(struct smbXsrv_open
*op
, NTTIME now
)
953 struct smbXsrv_open_table
*table
;
954 struct db_record
*local_rec
= NULL
;
955 struct db_record
*global_rec
= NULL
;
957 NTSTATUS error
= NT_STATUS_OK
;
959 if (op
->table
== NULL
) {
966 op
->status
= NT_STATUS_FILE_CLOSED
;
967 op
->global
->disconnect_time
= now
;
968 server_id_set_disconnected(&op
->global
->server_id
);
970 global_rec
= op
->global
->db_rec
;
971 op
->global
->db_rec
= NULL
;
972 if (global_rec
== NULL
) {
973 uint8_t key_buf
[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
];
976 key
= smbXsrv_open_global_id_to_key(
977 op
->global
->open_global_id
,
980 global_rec
= dbwrap_fetch_locked(table
->global
.db_ctx
,
982 if (global_rec
== NULL
) {
983 DEBUG(0, ("smbXsrv_open_close(0x%08x): "
984 "Failed to lock global key '%s'\n",
985 op
->global
->open_global_id
,
986 hex_encode_talloc(global_rec
, key
.dptr
,
988 error
= NT_STATUS_INTERNAL_ERROR
;
992 if (global_rec
!= NULL
&& op
->global
->durable
) {
994 * If it is a durable open we need to update the global part
995 * instead of deleting it
997 op
->global
->db_rec
= global_rec
;
998 status
= smbXsrv_open_global_store(op
->global
);
999 if (NT_STATUS_IS_OK(status
)) {
1001 * smbXsrv_open_global_store does the free
1002 * of op->global->db_rec
1006 if (!NT_STATUS_IS_OK(status
)) {
1007 DEBUG(0,("smbXsrv_open_close(0x%08x)"
1008 "smbXsrv_open_global_store() failed - %s\n",
1009 op
->global
->open_global_id
,
1010 nt_errstr(status
)));
1014 if (NT_STATUS_IS_OK(status
) && CHECK_DEBUGLVL(10)) {
1015 struct smbXsrv_openB open_blob
;
1017 ZERO_STRUCT(open_blob
);
1018 open_blob
.version
= SMBXSRV_VERSION_0
;
1019 open_blob
.info
.info0
= op
;
1021 DEBUG(10,("smbXsrv_open_close(0x%08x): "
1022 "stored disconnect\n",
1023 op
->global
->open_global_id
));
1024 NDR_PRINT_DEBUG(smbXsrv_openB
, &open_blob
);
1028 if (global_rec
!= NULL
) {
1029 status
= dbwrap_record_delete(global_rec
);
1030 if (!NT_STATUS_IS_OK(status
)) {
1031 TDB_DATA key
= dbwrap_record_get_key(global_rec
);
1033 DEBUG(0, ("smbXsrv_open_close(0x%08x): "
1034 "failed to delete global key '%s': %s\n",
1035 op
->global
->open_global_id
,
1036 hex_encode_talloc(global_rec
, key
.dptr
,
1038 nt_errstr(status
)));
1042 TALLOC_FREE(global_rec
);
1044 local_rec
= op
->db_rec
;
1045 if (local_rec
== NULL
) {
1046 uint8_t key_buf
[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE
];
1049 key
= smbXsrv_open_local_id_to_key(op
->local_id
, key_buf
);
1051 local_rec
= dbwrap_fetch_locked(table
->local
.db_ctx
,
1053 if (local_rec
== NULL
) {
1054 DEBUG(0, ("smbXsrv_open_close(0x%08x): "
1055 "Failed to lock local key '%s'\n",
1056 op
->global
->open_global_id
,
1057 hex_encode_talloc(local_rec
, key
.dptr
,
1059 error
= NT_STATUS_INTERNAL_ERROR
;
1063 if (local_rec
!= NULL
) {
1064 status
= dbwrap_record_delete(local_rec
);
1065 if (!NT_STATUS_IS_OK(status
)) {
1066 TDB_DATA key
= dbwrap_record_get_key(local_rec
);
1068 DEBUG(0, ("smbXsrv_open_close(0x%08x): "
1069 "failed to delete local key '%s': %s\n",
1070 op
->global
->open_global_id
,
1071 hex_encode_talloc(local_rec
, key
.dptr
,
1073 nt_errstr(status
)));
1076 table
->local
.num_opens
-= 1;
1078 if (op
->db_rec
== NULL
) {
1079 TALLOC_FREE(local_rec
);
1084 op
->compat
->op
= NULL
;
1085 file_free(NULL
, op
->compat
);
1092 NTSTATUS
smb1srv_open_table_init(struct smbXsrv_connection
*conn
)
1097 * Allow a range from 1..65534.
1099 * With real_max_open_files possible ids,
1100 * truncated to the SMB1 limit of 16-bit.
1102 * 0 and 0xFFFF are no valid ids.
1104 max_opens
= conn
->sconn
->real_max_open_files
;
1105 max_opens
= MIN(max_opens
, UINT16_MAX
- 1);
1107 return smbXsrv_open_table_init(conn
, 1, UINT16_MAX
- 1, max_opens
);
1110 NTSTATUS
smb1srv_open_lookup(struct smbXsrv_connection
*conn
,
1111 uint16_t fnum
, NTTIME now
,
1112 struct smbXsrv_open
**_open
)
1114 struct smbXsrv_open_table
*table
= conn
->open_table
;
1115 uint32_t local_id
= fnum
;
1116 uint32_t global_id
= 0;
1118 return smbXsrv_open_local_lookup(table
, local_id
, global_id
, now
, _open
);
1121 NTSTATUS
smb2srv_open_table_init(struct smbXsrv_connection
*conn
)
1126 * Allow a range from 1..4294967294.
1128 * With real_max_open_files possible ids,
1129 * truncated to 16-bit (the same as SMB1 for now).
1131 * 0 and 0xFFFFFFFF are no valid ids.
1133 * The usage of conn->sconn->real_max_open_files
1134 * is the reason that we use one open table per
1135 * transport connection (as we still have a 1:1 mapping
1136 * between process and transport connection).
1138 max_opens
= conn
->sconn
->real_max_open_files
;
1139 max_opens
= MIN(max_opens
, UINT16_MAX
- 1);
1141 return smbXsrv_open_table_init(conn
, 1, UINT32_MAX
- 1, max_opens
);
1144 NTSTATUS
smb2srv_open_lookup(struct smbXsrv_connection
*conn
,
1145 uint64_t persistent_id
,
1146 uint64_t volatile_id
,
1148 struct smbXsrv_open
**_open
)
1150 struct smbXsrv_open_table
*table
= conn
->open_table
;
1151 uint32_t local_id
= volatile_id
& UINT32_MAX
;
1152 uint64_t local_zeros
= volatile_id
& 0xFFFFFFFF00000000LLU
;
1153 uint32_t global_id
= persistent_id
& UINT32_MAX
;
1154 uint64_t global_zeros
= persistent_id
& 0xFFFFFFFF00000000LLU
;
1156 if (local_zeros
!= 0) {
1157 return NT_STATUS_FILE_CLOSED
;
1160 if (global_zeros
!= 0) {
1161 return NT_STATUS_FILE_CLOSED
;
1164 if (global_id
== 0) {
1165 return NT_STATUS_FILE_CLOSED
;
1168 return smbXsrv_open_local_lookup(table
, local_id
, global_id
, now
, _open
);
1171 NTSTATUS
smb2srv_open_recreate(struct smbXsrv_connection
*conn
,
1172 struct auth_session_info
*session_info
,
1173 uint64_t persistent_id
,
1174 const struct GUID
*create_guid
,
1176 struct smbXsrv_open
**_open
)
1178 struct smbXsrv_open_table
*table
= conn
->open_table
;
1179 struct db_record
*local_rec
= NULL
;
1180 struct smbXsrv_open
*op
= NULL
;
1183 uint32_t global_id
= persistent_id
& UINT32_MAX
;
1184 uint64_t global_zeros
= persistent_id
& 0xFFFFFFFF00000000LLU
;
1186 struct security_token
*current_token
= NULL
;
1188 if (session_info
== NULL
) {
1189 return NT_STATUS_INVALID_HANDLE
;
1191 current_token
= session_info
->security_token
;
1193 if (current_token
== NULL
) {
1194 return NT_STATUS_INVALID_HANDLE
;
1197 if (global_zeros
!= 0) {
1198 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1201 op
= talloc_zero(table
, struct smbXsrv_open
);
1203 return NT_STATUS_NO_MEMORY
;
1207 status
= smbXsrv_open_global_lookup(table
, global_id
, op
, &op
->global
);
1208 if (!NT_STATUS_IS_OK(status
)) {
1214 * If the provided create_guid is NULL, this means that
1215 * the reconnect request was a v1 request. In that case
1216 * we should skipt the create GUID verification, since
1217 * it is valid to v1-reconnect a v2-opened handle.
1219 if ((create_guid
!= NULL
) &&
1220 !GUID_equal(&op
->global
->create_guid
, create_guid
))
1223 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1226 if (!security_token_is_sid(current_token
, &op
->global
->open_owner
)) {
1228 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1231 if (!op
->global
->durable
) {
1233 return NT_STATUS_OBJECT_NAME_NOT_FOUND
;
1236 if (table
->local
.num_opens
>= table
->local
.max_opens
) {
1238 return NT_STATUS_INSUFFICIENT_RESOURCES
;
1241 status
= smbXsrv_open_local_allocate_id(table
->local
.db_ctx
,
1242 table
->local
.lowest_id
,
1243 table
->local
.highest_id
,
1247 if (!NT_STATUS_IS_OK(status
)) {
1252 op
->idle_time
= now
;
1253 op
->status
= NT_STATUS_FILE_CLOSED
;
1255 op
->global
->open_volatile_id
= op
->local_id
;
1256 op
->global
->server_id
= messaging_server_id(conn
->msg_ctx
);
1259 val
= make_tdb_data((uint8_t const *)&ptr
, sizeof(ptr
));
1260 status
= dbwrap_record_store(local_rec
, val
, TDB_REPLACE
);
1261 TALLOC_FREE(local_rec
);
1262 if (!NT_STATUS_IS_OK(status
)) {
1266 table
->local
.num_opens
+= 1;
1268 talloc_set_destructor(op
, smbXsrv_open_destructor
);
1270 status
= smbXsrv_open_global_store(op
->global
);
1271 if (!NT_STATUS_IS_OK(status
)) {
1276 if (CHECK_DEBUGLVL(10)) {
1277 struct smbXsrv_openB open_blob
;
1279 ZERO_STRUCT(open_blob
);
1280 open_blob
.version
= 0;
1281 open_blob
.info
.info0
= op
;
1283 DEBUG(10,("smbXsrv_open_recreate: global_id (0x%08x) stored\n",
1284 op
->global
->open_global_id
));
1285 NDR_PRINT_DEBUG(smbXsrv_openB
, &open_blob
);
1289 return NT_STATUS_OK
;
1293 static NTSTATUS
smbXsrv_open_global_parse_record(TALLOC_CTX
*mem_ctx
,
1294 struct db_record
*rec
,
1295 struct smbXsrv_open_global0
**global
)
1297 TDB_DATA key
= dbwrap_record_get_key(rec
);
1298 TDB_DATA val
= dbwrap_record_get_value(rec
);
1299 DATA_BLOB blob
= data_blob_const(val
.dptr
, val
.dsize
);
1300 struct smbXsrv_open_globalB global_blob
;
1301 enum ndr_err_code ndr_err
;
1303 TALLOC_CTX
*frame
= talloc_stackframe();
1305 ndr_err
= ndr_pull_struct_blob(&blob
, frame
, &global_blob
,
1306 (ndr_pull_flags_fn_t
)ndr_pull_smbXsrv_open_globalB
);
1307 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
1308 DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:"
1309 "key '%s' ndr_pull_struct_blob - %s\n",
1310 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1311 ndr_errstr(ndr_err
)));
1312 status
= ndr_map_error2ntstatus(ndr_err
);
1316 if (global_blob
.version
!= SMBXSRV_VERSION_0
) {
1317 status
= NT_STATUS_INTERNAL_DB_CORRUPTION
;
1318 DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:"
1319 "key '%s' unsuported version - %d - %s\n",
1320 hex_encode_talloc(frame
, key
.dptr
, key
.dsize
),
1321 (int)global_blob
.version
,
1322 nt_errstr(status
)));
1326 *global
= talloc_move(mem_ctx
, &global_blob
.info
.info0
);
1327 status
= NT_STATUS_OK
;
1333 struct smbXsrv_open_global_traverse_state
{
1334 int (*fn
)(struct smbXsrv_open_global0
*, void *);
1338 static int smbXsrv_open_global_traverse_fn(struct db_record
*rec
, void *data
)
1340 struct smbXsrv_open_global_traverse_state
*state
=
1341 (struct smbXsrv_open_global_traverse_state
*)data
;
1342 struct smbXsrv_open_global0
*global
= NULL
;
1346 status
= smbXsrv_open_global_parse_record(talloc_tos(), rec
, &global
);
1347 if (!NT_STATUS_IS_OK(status
)) {
1351 global
->db_rec
= rec
;
1352 ret
= state
->fn(global
, state
->private_data
);
1353 talloc_free(global
);
1357 NTSTATUS
smbXsrv_open_global_traverse(
1358 int (*fn
)(struct smbXsrv_open_global0
*, void *),
1364 struct smbXsrv_open_global_traverse_state state
= {
1366 .private_data
= private_data
,
1370 status
= smbXsrv_open_global_init();
1371 if (!NT_STATUS_IS_OK(status
)) {
1373 DEBUG(0, ("Failed to initialize open_global: %s\n",
1374 nt_errstr(status
)));
1378 status
= dbwrap_traverse_read(smbXsrv_open_global_db_ctx
,
1379 smbXsrv_open_global_traverse_fn
,
1387 NTSTATUS
smbXsrv_open_cleanup(uint64_t persistent_id
)
1389 NTSTATUS status
= NT_STATUS_OK
;
1390 TALLOC_CTX
*frame
= talloc_stackframe();
1391 struct smbXsrv_open_global0
*op
= NULL
;
1392 uint8_t key_buf
[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE
];
1395 struct db_record
*rec
;
1396 bool delete_open
= false;
1397 uint32_t global_id
= persistent_id
& UINT32_MAX
;
1399 key
= smbXsrv_open_global_id_to_key(global_id
, key_buf
);
1400 rec
= dbwrap_fetch_locked(smbXsrv_open_global_db_ctx
, frame
, key
);
1402 status
= NT_STATUS_NOT_FOUND
;
1403 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
1404 "failed to fetch record from %s - %s\n",
1405 global_id
, dbwrap_name(smbXsrv_open_global_db_ctx
),
1406 nt_errstr(status
)));
1410 val
= dbwrap_record_get_value(rec
);
1411 if (val
.dsize
== 0) {
1412 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1413 "empty record in %s, skipping...\n",
1414 global_id
, dbwrap_name(smbXsrv_open_global_db_ctx
)));
1418 status
= smbXsrv_open_global_parse_record(talloc_tos(), rec
, &op
);
1419 if (!NT_STATUS_IS_OK(status
)) {
1420 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
1421 "failed to read record: %s\n",
1422 global_id
, nt_errstr(status
)));
1426 if (server_id_is_disconnected(&op
->server_id
)) {
1427 struct timeval now
, disconnect_time
;
1429 now
= timeval_current();
1430 nttime_to_timeval(&disconnect_time
, op
->disconnect_time
);
1431 tdiff
= usec_time_diff(&now
, &disconnect_time
);
1432 delete_open
= (tdiff
>= 1000*op
->durable_timeout_msec
);
1434 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1435 "disconnected at [%s] %us ago with "
1436 "timeout of %us -%s reached\n",
1438 nt_time_string(frame
, op
->disconnect_time
),
1439 (unsigned)(tdiff
/1000000),
1440 op
->durable_timeout_msec
/ 1000,
1441 delete_open
? "" : " not"));
1442 } else if (!serverid_exists(&op
->server_id
)) {
1443 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1444 "server[%s] does not exist\n",
1445 global_id
, server_id_str(frame
, &op
->server_id
)));
1453 status
= dbwrap_record_delete(rec
);
1454 if (!NT_STATUS_IS_OK(status
)) {
1455 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
1456 "failed to delete record"
1457 "from %s: %s\n", global_id
,
1458 dbwrap_name(smbXsrv_open_global_db_ctx
),
1459 nt_errstr(status
)));
1463 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
1464 "delete record from %s\n",
1466 dbwrap_name(smbXsrv_open_global_db_ctx
)));