LCOV - code coverage report
Current view: top level - source3/smbd - smbXsrv_open.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 274 756 36.2 %
Date: 2024-06-13 04:01:37 Functions: 20 33 60.6 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Stefan Metzmacher 2012
       5             :    Copyright (C) Michael Adam 2012
       6             : 
       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.
      11             : 
      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.
      16             : 
      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/>.
      19             : */
      20             : 
      21             : #include "smbXsrv_open.h"
      22             : #include "includes.h"
      23             : #include "system/filesys.h"
      24             : #include "lib/util/server_id.h"
      25             : #include "smbd/smbd.h"
      26             : #include "smbd/globals.h"
      27             : #include "dbwrap/dbwrap.h"
      28             : #include "dbwrap/dbwrap_rbt.h"
      29             : #include "dbwrap/dbwrap_open.h"
      30             : #include "../libcli/security/security.h"
      31             : #include "messages.h"
      32             : #include "lib/util/util_tdb.h"
      33             : #include "librpc/gen_ndr/ndr_smbXsrv.h"
      34             : #include "serverid.h"
      35             : 
      36             : struct smbXsrv_open_table {
      37             :         struct {
      38             :                 struct db_context *db_ctx;
      39             :                 struct db_context *replay_cache_db_ctx;
      40             :                 uint32_t lowest_id;
      41             :                 uint32_t highest_id;
      42             :                 uint32_t max_opens;
      43             :                 uint32_t num_opens;
      44             :         } local;
      45             :         struct {
      46             :                 struct db_context *db_ctx;
      47             :         } global;
      48             : };
      49             : 
      50             : static struct db_context *smbXsrv_open_global_db_ctx = NULL;
      51             : 
      52        5079 : NTSTATUS smbXsrv_open_global_init(void)
      53             : {
      54        5079 :         char *global_path = NULL;
      55        5079 :         struct db_context *db_ctx = NULL;
      56             : 
      57        5079 :         if (smbXsrv_open_global_db_ctx != NULL) {
      58        5040 :                 return NT_STATUS_OK;
      59             :         }
      60             : 
      61          39 :         global_path = lock_path(talloc_tos(), "smbXsrv_open_global.tdb");
      62          39 :         if (global_path == NULL) {
      63           0 :                 return NT_STATUS_NO_MEMORY;
      64             :         }
      65             : 
      66          39 :         db_ctx = db_open(NULL, global_path,
      67             :                          0, /* hash_size */
      68             :                          TDB_DEFAULT |
      69             :                          TDB_CLEAR_IF_FIRST |
      70             :                          TDB_INCOMPATIBLE_HASH,
      71             :                          O_RDWR | O_CREAT, 0600,
      72             :                          DBWRAP_LOCK_ORDER_1,
      73             :                          DBWRAP_FLAG_NONE);
      74          39 :         TALLOC_FREE(global_path);
      75          39 :         if (db_ctx == NULL) {
      76             :                 NTSTATUS status;
      77             : 
      78           0 :                 status = map_nt_error_from_unix_common(errno);
      79             : 
      80           0 :                 return status;
      81             :         }
      82             : 
      83          39 :         smbXsrv_open_global_db_ctx = db_ctx;
      84             : 
      85          39 :         return NT_STATUS_OK;
      86             : }
      87             : 
      88             : /*
      89             :  * NOTE:
      90             :  * We need to store the keys in big endian so that dbwrap_rbt's memcmp
      91             :  * has the same result as integer comparison between the uint32_t
      92             :  * values.
      93             :  *
      94             :  * TODO: implement string based key
      95             :  */
      96             : 
      97             : #define SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
      98             : 
      99       32678 : static TDB_DATA smbXsrv_open_global_id_to_key(uint32_t id,
     100             :                                               uint8_t *key_buf)
     101             : {
     102             :         TDB_DATA key;
     103             : 
     104       32678 :         RSIVAL(key_buf, 0, id);
     105             : 
     106       32678 :         key = make_tdb_data(key_buf, SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE);
     107             : 
     108       32678 :         return key;
     109             : }
     110             : 
     111             : #if 0
     112             : static NTSTATUS smbXsrv_open_global_key_to_id(TDB_DATA key, uint32_t *id)
     113             : {
     114             :         if (id == NULL) {
     115             :                 return NT_STATUS_INVALID_PARAMETER;
     116             :         }
     117             : 
     118             :         if (key.dsize != SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE) {
     119             :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     120             :         }
     121             : 
     122             :         *id = RIVAL(key.dptr, 0);
     123             : 
     124             :         return NT_STATUS_OK;
     125             : }
     126             : #endif
     127             : 
     128             : #define SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
     129             : 
     130      145157 : static TDB_DATA smbXsrv_open_local_id_to_key(uint32_t id,
     131             :                                              uint8_t *key_buf)
     132             : {
     133             :         TDB_DATA key;
     134             : 
     135      145157 :         RSIVAL(key_buf, 0, id);
     136             : 
     137      145157 :         key = make_tdb_data(key_buf, SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE);
     138             : 
     139      145157 :         return key;
     140             : }
     141             : 
     142           0 : static NTSTATUS smbXsrv_open_local_key_to_id(TDB_DATA key, uint32_t *id)
     143             : {
     144           0 :         if (id == NULL) {
     145           0 :                 return NT_STATUS_INVALID_PARAMETER;
     146             :         }
     147             : 
     148           0 :         if (key.dsize != SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE) {
     149           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     150             :         }
     151             : 
     152           0 :         *id = RIVAL(key.dptr, 0);
     153             : 
     154           0 :         return NT_STATUS_OK;
     155             : }
     156             : 
     157       32678 : static struct db_record *smbXsrv_open_global_fetch_locked(
     158             :                         struct db_context *db,
     159             :                         uint32_t id,
     160             :                         TALLOC_CTX *mem_ctx)
     161             : {
     162             :         TDB_DATA key;
     163             :         uint8_t key_buf[SMBXSRV_OPEN_GLOBAL_TDB_KEY_SIZE];
     164       32678 :         struct db_record *rec = NULL;
     165             : 
     166       32678 :         key = smbXsrv_open_global_id_to_key(id, key_buf);
     167             : 
     168       32678 :         rec = dbwrap_fetch_locked(db, mem_ctx, key);
     169             : 
     170       32678 :         if (rec == NULL) {
     171           0 :                 DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id,
     172             :                           hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
     173             :         }
     174             : 
     175       32678 :         return rec;
     176             : }
     177             : 
     178       32678 : static struct db_record *smbXsrv_open_local_fetch_locked(
     179             :                         struct db_context *db,
     180             :                         uint32_t id,
     181             :                         TALLOC_CTX *mem_ctx)
     182             : {
     183             :         TDB_DATA key;
     184             :         uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
     185       32678 :         struct db_record *rec = NULL;
     186             : 
     187       32678 :         key = smbXsrv_open_local_id_to_key(id, key_buf);
     188             : 
     189       32678 :         rec = dbwrap_fetch_locked(db, mem_ctx, key);
     190             : 
     191       32678 :         if (rec == NULL) {
     192           0 :                 DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
     193             :                           hex_encode_talloc(talloc_tos(), key.dptr, key.dsize));
     194             :         }
     195             : 
     196       32678 :         return rec;
     197             : }
     198             : 
     199        5040 : static NTSTATUS smbXsrv_open_table_init(struct smbXsrv_connection *conn,
     200             :                                         uint32_t lowest_id,
     201             :                                         uint32_t highest_id,
     202             :                                         uint32_t max_opens)
     203             : {
     204        5040 :         struct smbXsrv_client *client = conn->client;
     205             :         struct smbXsrv_open_table *table;
     206             :         NTSTATUS status;
     207             :         uint64_t max_range;
     208             : 
     209        5040 :         if (lowest_id > highest_id) {
     210           0 :                 return NT_STATUS_INTERNAL_ERROR;
     211             :         }
     212             : 
     213        5040 :         max_range = highest_id;
     214        5040 :         max_range -= lowest_id;
     215        5040 :         max_range += 1;
     216             : 
     217        5040 :         if (max_opens > max_range) {
     218           0 :                 return NT_STATUS_INTERNAL_ERROR;
     219             :         }
     220             : 
     221        5040 :         table = talloc_zero(client, struct smbXsrv_open_table);
     222        5040 :         if (table == NULL) {
     223           0 :                 return NT_STATUS_NO_MEMORY;
     224             :         }
     225             : 
     226        5040 :         table->local.db_ctx = db_open_rbt(table);
     227        5040 :         if (table->local.db_ctx == NULL) {
     228           0 :                 TALLOC_FREE(table);
     229           0 :                 return NT_STATUS_NO_MEMORY;
     230             :         }
     231        5040 :         table->local.replay_cache_db_ctx = db_open_rbt(table);
     232        5040 :         if (table->local.replay_cache_db_ctx == NULL) {
     233           0 :                 TALLOC_FREE(table);
     234           0 :                 return NT_STATUS_NO_MEMORY;
     235             :         }
     236        5040 :         table->local.lowest_id = lowest_id;
     237        5040 :         table->local.highest_id = highest_id;
     238        5040 :         table->local.max_opens = max_opens;
     239             : 
     240        5040 :         status = smbXsrv_open_global_init();
     241        5040 :         if (!NT_STATUS_IS_OK(status)) {
     242           0 :                 TALLOC_FREE(table);
     243           0 :                 return status;
     244             :         }
     245             : 
     246        5040 :         table->global.db_ctx = smbXsrv_open_global_db_ctx;
     247             : 
     248        5040 :         client->open_table = table;
     249        5040 :         return NT_STATUS_OK;
     250             : }
     251             : 
     252             : struct smbXsrv_open_local_allocate_state {
     253             :         const uint32_t lowest_id;
     254             :         const uint32_t highest_id;
     255             :         uint32_t last_id;
     256             :         uint32_t useable_id;
     257             :         NTSTATUS status;
     258             : };
     259             : 
     260           0 : static int smbXsrv_open_local_allocate_traverse(struct db_record *rec,
     261             :                                                    void *private_data)
     262             : {
     263           0 :         struct smbXsrv_open_local_allocate_state *state =
     264             :                 (struct smbXsrv_open_local_allocate_state *)private_data;
     265           0 :         TDB_DATA key = dbwrap_record_get_key(rec);
     266           0 :         uint32_t id = 0;
     267             :         NTSTATUS status;
     268             : 
     269           0 :         status = smbXsrv_open_local_key_to_id(key, &id);
     270           0 :         if (!NT_STATUS_IS_OK(status)) {
     271           0 :                 state->status = status;
     272           0 :                 return -1;
     273             :         }
     274             : 
     275           0 :         if (id <= state->last_id) {
     276           0 :                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     277           0 :                 return -1;
     278             :         }
     279           0 :         state->last_id = id;
     280             : 
     281           0 :         if (id > state->useable_id) {
     282           0 :                 state->status = NT_STATUS_OK;
     283           0 :                 return -1;
     284             :         }
     285             : 
     286           0 :         if (state->useable_id == state->highest_id) {
     287           0 :                 state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
     288           0 :                 return -1;
     289             :         }
     290             : 
     291           0 :         state->useable_id +=1;
     292           0 :         return 0;
     293             : }
     294             : 
     295       16339 : static NTSTATUS smbXsrv_open_local_allocate_id(struct db_context *db,
     296             :                                                uint32_t lowest_id,
     297             :                                                uint32_t highest_id,
     298             :                                                TALLOC_CTX *mem_ctx,
     299             :                                                struct db_record **_rec,
     300             :                                                uint32_t *_id)
     301             : {
     302       16339 :         struct smbXsrv_open_local_allocate_state state = {
     303             :                 .lowest_id = lowest_id,
     304             :                 .highest_id = highest_id,
     305             :                 .last_id = 0,
     306             :                 .useable_id = lowest_id,
     307             :                 .status = NT_STATUS_INTERNAL_ERROR,
     308             :         };
     309             :         uint32_t i;
     310             :         uint32_t range;
     311             :         NTSTATUS status;
     312       16339 :         int count = 0;
     313             : 
     314       16339 :         *_rec = NULL;
     315       16339 :         *_id = 0;
     316             : 
     317       16339 :         if (lowest_id > highest_id) {
     318           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     319             :         }
     320             : 
     321             :         /*
     322             :          * first we try randomly
     323             :          */
     324       16339 :         range = (highest_id - lowest_id) + 1;
     325             : 
     326       30524 :         for (i = 0; i < (range / 2); i++) {
     327             :                 uint32_t id;
     328             :                 TDB_DATA val;
     329       16339 :                 struct db_record *rec = NULL;
     330             : 
     331       16339 :                 id = generate_random() % range;
     332       16339 :                 id += lowest_id;
     333             : 
     334       16339 :                 if (id < lowest_id) {
     335           0 :                         id = lowest_id;
     336             :                 }
     337       16339 :                 if (id > highest_id) {
     338           0 :                         id = highest_id;
     339             :                 }
     340             : 
     341       16339 :                 rec = smbXsrv_open_local_fetch_locked(db, id, mem_ctx);
     342       16339 :                 if (rec == NULL) {
     343       14185 :                         return NT_STATUS_INSUFFICIENT_RESOURCES;
     344             :                 }
     345             : 
     346       16339 :                 val = dbwrap_record_get_value(rec);
     347       16339 :                 if (val.dsize != 0) {
     348           0 :                         TALLOC_FREE(rec);
     349           0 :                         continue;
     350             :                 }
     351             : 
     352       16339 :                 *_rec = rec;
     353       16339 :                 *_id = id;
     354       16339 :                 return NT_STATUS_OK;
     355             :         }
     356             : 
     357             :         /*
     358             :          * if the range is almost full,
     359             :          * we traverse the whole table
     360             :          * (this relies on sorted behavior of dbwrap_rbt)
     361             :          */
     362           0 :         status = dbwrap_traverse_read(db, smbXsrv_open_local_allocate_traverse,
     363             :                                       &state, &count);
     364           0 :         if (NT_STATUS_IS_OK(status)) {
     365           0 :                 if (NT_STATUS_IS_OK(state.status)) {
     366           0 :                         return NT_STATUS_INTERNAL_ERROR;
     367             :                 }
     368             : 
     369           0 :                 if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
     370           0 :                         return state.status;
     371             :                 }
     372             : 
     373           0 :                 if (state.useable_id <= state.highest_id) {
     374           0 :                         state.status = NT_STATUS_OK;
     375             :                 } else {
     376           0 :                         return NT_STATUS_INSUFFICIENT_RESOURCES;
     377             :                 }
     378           0 :         } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
     379             :                 /*
     380             :                  * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
     381             :                  *
     382             :                  * If we get anything else it is an error, because it
     383             :                  * means we did not manage to find a free slot in
     384             :                  * the db.
     385             :                  */
     386           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     387             :         }
     388             : 
     389           0 :         if (NT_STATUS_IS_OK(state.status)) {
     390             :                 uint32_t id;
     391             :                 TDB_DATA val;
     392           0 :                 struct db_record *rec = NULL;
     393             : 
     394           0 :                 id = state.useable_id;
     395             : 
     396           0 :                 rec = smbXsrv_open_local_fetch_locked(db, id, mem_ctx);
     397           0 :                 if (rec == NULL) {
     398           0 :                         return NT_STATUS_INSUFFICIENT_RESOURCES;
     399             :                 }
     400             : 
     401           0 :                 val = dbwrap_record_get_value(rec);
     402           0 :                 if (val.dsize != 0) {
     403           0 :                         TALLOC_FREE(rec);
     404           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     405             :                 }
     406             : 
     407           0 :                 *_rec = rec;
     408           0 :                 *_id = id;
     409           0 :                 return NT_STATUS_OK;
     410             :         }
     411             : 
     412           0 :         return state.status;
     413             : }
     414             : 
     415             : struct smbXsrv_open_local_fetch_state {
     416             :         struct smbXsrv_open *op;
     417             :         NTSTATUS status;
     418             : };
     419             : 
     420      112477 : static void smbXsrv_open_local_fetch_parser(TDB_DATA key, TDB_DATA data,
     421             :                                             void *private_data)
     422             : {
     423      112477 :         struct smbXsrv_open_local_fetch_state *state =
     424             :                 (struct smbXsrv_open_local_fetch_state *)private_data;
     425             :         void *ptr;
     426             : 
     427      112477 :         if (data.dsize != sizeof(ptr)) {
     428           0 :                 state->status = NT_STATUS_INTERNAL_DB_ERROR;
     429           0 :                 return;
     430             :         }
     431             : 
     432      112477 :         memcpy(&ptr, data.dptr, data.dsize);
     433      112477 :         state->op = talloc_get_type_abort(ptr, struct smbXsrv_open);
     434      112477 :         state->status = NT_STATUS_OK;
     435             : }
     436             : 
     437      112479 : static NTSTATUS smbXsrv_open_local_lookup(struct smbXsrv_open_table *table,
     438             :                                           uint32_t open_local_id,
     439             :                                           uint32_t open_global_id,
     440             :                                           NTTIME now,
     441             :                                           struct smbXsrv_open **_open)
     442             : {
     443      112479 :         struct smbXsrv_open_local_fetch_state state = {
     444             :                 .op = NULL,
     445             :                 .status = NT_STATUS_INTERNAL_ERROR,
     446             :         };
     447             :         uint8_t key_buf[SMBXSRV_OPEN_LOCAL_TDB_KEY_SIZE];
     448             :         TDB_DATA key;
     449             :         NTSTATUS status;
     450             : 
     451      112479 :         *_open = NULL;
     452             : 
     453      112479 :         if (open_local_id == 0) {
     454           0 :                 return NT_STATUS_FILE_CLOSED;
     455             :         }
     456             : 
     457      112479 :         if (table == NULL) {
     458             :                 /* this might happen before the end of negprot */
     459           0 :                 return NT_STATUS_FILE_CLOSED;
     460             :         }
     461             : 
     462      112479 :         if (table->local.db_ctx == NULL) {
     463           0 :                 return NT_STATUS_INTERNAL_ERROR;
     464             :         }
     465             : 
     466      112479 :         key = smbXsrv_open_local_id_to_key(open_local_id, key_buf);
     467             : 
     468      112479 :         status = dbwrap_parse_record(table->local.db_ctx, key,
     469             :                                      smbXsrv_open_local_fetch_parser,
     470             :                                      &state);
     471      112479 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     472           2 :                 return NT_STATUS_FILE_CLOSED;
     473             :         }
     474      112477 :         if (!NT_STATUS_IS_OK(status)) {
     475           0 :                 return status;
     476             :         }
     477      112477 :         if (!NT_STATUS_IS_OK(state.status)) {
     478           0 :                 return state.status;
     479             :         }
     480             : 
     481      112477 :         if (NT_STATUS_EQUAL(state.op->status, NT_STATUS_FILE_CLOSED)) {
     482           0 :                 return NT_STATUS_FILE_CLOSED;
     483             :         }
     484             : 
     485      112477 :         if (open_global_id == 0) {
     486             :                 /* make the global check a no-op for SMB1 */
     487           0 :                 open_global_id = state.op->global->open_global_id;
     488             :         }
     489             : 
     490      112477 :         if (state.op->global->open_global_id != open_global_id) {
     491           0 :                 return NT_STATUS_FILE_CLOSED;
     492             :         }
     493             : 
     494      112477 :         if (now != 0) {
     495      112477 :                 state.op->idle_time = now;
     496             :         }
     497             : 
     498      112477 :         *_open = state.op;
     499      112477 :         return state.op->status;
     500             : }
     501             : 
     502       16339 : static int smbXsrv_open_global_destructor(struct smbXsrv_open_global0 *global)
     503             : {
     504       16339 :         return 0;
     505             : }
     506             : 
     507             : static void smbXsrv_open_global_verify_record(struct db_record *db_rec,
     508             :                                         bool *is_free,
     509             :                                         bool *was_free,
     510             :                                         TALLOC_CTX *mem_ctx,
     511             :                                         struct smbXsrv_open_global0 **_g);
     512             : 
     513       16339 : static NTSTATUS smbXsrv_open_global_allocate(struct db_context *db,
     514             :                                         TALLOC_CTX *mem_ctx,
     515             :                                         struct smbXsrv_open_global0 **_global)
     516             : {
     517             :         uint32_t i;
     518       16339 :         struct smbXsrv_open_global0 *global = NULL;
     519       16339 :         uint32_t last_free = 0;
     520       16339 :         const uint32_t min_tries = 3;
     521             : 
     522       16339 :         *_global = NULL;
     523             : 
     524       16339 :         global = talloc_zero(mem_ctx, struct smbXsrv_open_global0);
     525       16339 :         if (global == NULL) {
     526           0 :                 return NT_STATUS_NO_MEMORY;
     527             :         }
     528       16339 :         talloc_set_destructor(global, smbXsrv_open_global_destructor);
     529             : 
     530             :         /*
     531             :          * We mark every slot as invalid using 0xFF.
     532             :          * Valid values are masked with 0xF.
     533             :          */
     534       16339 :         memset(global->lock_sequence_array, 0xFF,
     535             :                sizeof(global->lock_sequence_array));
     536             : 
     537             :         /*
     538             :          * Here we just randomly try the whole 32-bit space
     539             :          *
     540             :          * We use just 32-bit, because we want to reuse the
     541             :          * ID for SRVSVC.
     542             :          */
     543       16339 :         for (i = 0; i < UINT32_MAX; i++) {
     544       16339 :                 bool is_free = false;
     545       16339 :                 bool was_free = false;
     546             :                 uint32_t id;
     547             : 
     548       16339 :                 if (i >= min_tries && last_free != 0) {
     549           0 :                         id = last_free;
     550             :                 } else {
     551       16339 :                         id = generate_random();
     552             :                 }
     553       16339 :                 if (id == 0) {
     554           0 :                         id++;
     555             :                 }
     556       16339 :                 if (id == UINT32_MAX) {
     557           0 :                         id--;
     558             :                 }
     559             : 
     560       16339 :                 global->db_rec = smbXsrv_open_global_fetch_locked(db, id, mem_ctx);
     561       16339 :                 if (global->db_rec == NULL) {
     562           0 :                         talloc_free(global);
     563       14185 :                         return NT_STATUS_INSUFFICIENT_RESOURCES;
     564             :                 }
     565             : 
     566       16339 :                 smbXsrv_open_global_verify_record(global->db_rec,
     567             :                                                   &is_free,
     568             :                                                   &was_free,
     569             :                                                   NULL, NULL);
     570             : 
     571       16339 :                 if (!is_free) {
     572           0 :                         TALLOC_FREE(global->db_rec);
     573           0 :                         continue;
     574             :                 }
     575             : 
     576       16339 :                 if (!was_free && i < min_tries) {
     577             :                         /*
     578             :                          * The session_id is free now,
     579             :                          * but was not free before.
     580             :                          *
     581             :                          * This happens if a smbd crashed
     582             :                          * and did not cleanup the record.
     583             :                          *
     584             :                          * If this is one of our first tries,
     585             :                          * then we try to find a real free one.
     586             :                          */
     587           0 :                         if (last_free == 0) {
     588           0 :                                 last_free = id;
     589             :                         }
     590           0 :                         TALLOC_FREE(global->db_rec);
     591           0 :                         continue;
     592             :                 }
     593             : 
     594       16339 :                 global->open_global_id = id;
     595             : 
     596       16339 :                 *_global = global;
     597       16339 :                 return NT_STATUS_OK;
     598             :         }
     599             : 
     600             :         /* should not be reached */
     601           0 :         talloc_free(global);
     602           0 :         return NT_STATUS_INTERNAL_ERROR;
     603             : }
     604             : 
     605       16339 : static void smbXsrv_open_global_verify_record(struct db_record *db_rec,
     606             :                                         bool *is_free,
     607             :                                         bool *was_free,
     608             :                                         TALLOC_CTX *mem_ctx,
     609             :                                         struct smbXsrv_open_global0 **_g)
     610             : {
     611             :         TDB_DATA key;
     612             :         TDB_DATA val;
     613             :         DATA_BLOB blob;
     614             :         struct smbXsrv_open_globalB global_blob;
     615             :         enum ndr_err_code ndr_err;
     616       16339 :         struct smbXsrv_open_global0 *global = NULL;
     617             :         bool exists;
     618       16339 :         TALLOC_CTX *frame = talloc_stackframe();
     619             : 
     620       16339 :         *is_free = false;
     621             : 
     622       16339 :         if (was_free) {
     623       16339 :                 *was_free = false;
     624             :         }
     625       16339 :         if (_g) {
     626           0 :                 *_g = NULL;
     627             :         }
     628             : 
     629       16339 :         key = dbwrap_record_get_key(db_rec);
     630             : 
     631       16339 :         val = dbwrap_record_get_value(db_rec);
     632       16339 :         if (val.dsize == 0) {
     633       16339 :                 DEBUG(10, ("%s: empty value\n", __func__));
     634       16339 :                 TALLOC_FREE(frame);
     635       16339 :                 *is_free = true;
     636       16339 :                 if (was_free) {
     637       16339 :                         *was_free = true;
     638             :                 }
     639       30524 :                 return;
     640             :         }
     641             : 
     642           0 :         blob = data_blob_const(val.dptr, val.dsize);
     643             : 
     644           0 :         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
     645             :                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_globalB);
     646           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     647           0 :                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
     648           0 :                 DEBUG(1,("smbXsrv_open_global_verify_record: "
     649             :                          "key '%s' ndr_pull_struct_blob - %s\n",
     650             :                          hex_encode_talloc(frame, key.dptr, key.dsize),
     651             :                          nt_errstr(status)));
     652           0 :                 TALLOC_FREE(frame);
     653           0 :                 return;
     654             :         }
     655             : 
     656           0 :         DEBUG(10,("smbXsrv_open_global_verify_record\n"));
     657           0 :         if (CHECK_DEBUGLVL(10)) {
     658           0 :                 NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
     659             :         }
     660             : 
     661           0 :         if (global_blob.version != SMBXSRV_VERSION_0) {
     662           0 :                 DEBUG(0,("smbXsrv_open_global_verify_record: "
     663             :                          "key '%s' use unsupported version %u\n",
     664             :                          hex_encode_talloc(frame, key.dptr, key.dsize),
     665             :                          global_blob.version));
     666           0 :                 NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
     667           0 :                 TALLOC_FREE(frame);
     668           0 :                 return;
     669             :         }
     670             : 
     671           0 :         global = global_blob.info.info0;
     672             : 
     673           0 :         if (server_id_is_disconnected(&global->server_id)) {
     674           0 :                 exists = true;
     675             :         } else {
     676           0 :                 exists = serverid_exists(&global->server_id);
     677             :         }
     678           0 :         if (!exists) {
     679             :                 struct server_id_buf idbuf;
     680           0 :                 DEBUG(2,("smbXsrv_open_global_verify_record: "
     681             :                          "key '%s' server_id %s does not exist.\n",
     682             :                          hex_encode_talloc(frame, key.dptr, key.dsize),
     683             :                          server_id_str_buf(global->server_id, &idbuf)));
     684           0 :                 if (CHECK_DEBUGLVL(2)) {
     685           0 :                         NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
     686             :                 }
     687           0 :                 TALLOC_FREE(frame);
     688           0 :                 dbwrap_record_delete(db_rec);
     689           0 :                 *is_free = true;
     690           0 :                 return;
     691             :         }
     692             : 
     693           0 :         if (_g) {
     694           0 :                 *_g = talloc_move(mem_ctx, &global);
     695             :         }
     696           0 :         TALLOC_FREE(frame);
     697             : }
     698             : 
     699       16339 : static NTSTATUS smbXsrv_open_global_store(struct smbXsrv_open_global0 *global)
     700             : {
     701             :         struct smbXsrv_open_globalB global_blob;
     702       16339 :         DATA_BLOB blob = data_blob_null;
     703             :         TDB_DATA key;
     704             :         TDB_DATA val;
     705             :         NTSTATUS status;
     706             :         enum ndr_err_code ndr_err;
     707             : 
     708             :         /*
     709             :          * TODO: if we use other versions than '0'
     710             :          * we would add glue code here, that would be able to
     711             :          * store the information in the old format.
     712             :          */
     713             : 
     714       16339 :         if (global->db_rec == NULL) {
     715           0 :                 return NT_STATUS_INTERNAL_ERROR;
     716             :         }
     717             : 
     718       16339 :         key = dbwrap_record_get_key(global->db_rec);
     719       16339 :         val = dbwrap_record_get_value(global->db_rec);
     720             : 
     721       16339 :         ZERO_STRUCT(global_blob);
     722       16339 :         global_blob.version = smbXsrv_version_global_current();
     723       16339 :         if (val.dsize >= 8) {
     724           0 :                 global_blob.seqnum = IVAL(val.dptr, 4);
     725             :         }
     726       16339 :         global_blob.seqnum += 1;
     727       16339 :         global_blob.info.info0 = global;
     728             : 
     729       16339 :         ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
     730             :                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_globalB);
     731       16339 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     732           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     733           0 :                 DEBUG(1,("smbXsrv_open_global_store: key '%s' ndr_push - %s\n",
     734             :                          hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
     735             :                          nt_errstr(status)));
     736           0 :                 TALLOC_FREE(global->db_rec);
     737           0 :                 return status;
     738             :         }
     739             : 
     740       16339 :         val = make_tdb_data(blob.data, blob.length);
     741       16339 :         status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
     742       16339 :         if (!NT_STATUS_IS_OK(status)) {
     743           0 :                 DEBUG(1,("smbXsrv_open_global_store: key '%s' store - %s\n",
     744             :                          hex_encode_talloc(global->db_rec, key.dptr, key.dsize),
     745             :                          nt_errstr(status)));
     746           0 :                 TALLOC_FREE(global->db_rec);
     747           0 :                 return status;
     748             :         }
     749             : 
     750       16339 :         if (CHECK_DEBUGLVL(10)) {
     751           0 :                 DEBUG(10,("smbXsrv_open_global_store: key '%s' stored\n",
     752             :                          hex_encode_talloc(global->db_rec, key.dptr, key.dsize)));
     753           0 :                 NDR_PRINT_DEBUG(smbXsrv_open_globalB, &global_blob);
     754             :         }
     755             : 
     756       16339 :         TALLOC_FREE(global->db_rec);
     757             : 
     758       16339 :         return NT_STATUS_OK;
     759             : }
     760             : 
     761           0 : static NTSTATUS smbXsrv_open_global_lookup(struct smbXsrv_open_table *table,
     762             :                                            uint32_t open_global_id,
     763             :                                            TALLOC_CTX *mem_ctx,
     764             :                                            struct smbXsrv_open_global0 **_global)
     765             : {
     766           0 :         struct db_record *global_rec = NULL;
     767           0 :         bool is_free = false;
     768             : 
     769           0 :         *_global = NULL;
     770             : 
     771           0 :         if (table->global.db_ctx == NULL) {
     772           0 :                 return NT_STATUS_INTERNAL_ERROR;
     773             :         }
     774             : 
     775           0 :         global_rec = smbXsrv_open_global_fetch_locked(table->global.db_ctx,
     776             :                                                       open_global_id,
     777             :                                                       mem_ctx);
     778           0 :         if (global_rec == NULL) {
     779           0 :                 return NT_STATUS_INTERNAL_DB_ERROR;
     780             :         }
     781             : 
     782           0 :         smbXsrv_open_global_verify_record(global_rec,
     783             :                                           &is_free,
     784             :                                           NULL,
     785             :                                           mem_ctx,
     786             :                                           _global);
     787           0 :         if (is_free) {
     788           0 :                 DEBUG(10, ("%s: is_free=true\n", __func__));
     789           0 :                 talloc_free(global_rec);
     790           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     791             :         }
     792             : 
     793           0 :         (*_global)->db_rec = talloc_move(*_global, &global_rec);
     794             : 
     795           0 :         talloc_set_destructor(*_global, smbXsrv_open_global_destructor);
     796             : 
     797           0 :         return NT_STATUS_OK;
     798             : }
     799             : 
     800       16339 : static int smbXsrv_open_destructor(struct smbXsrv_open *op)
     801             : {
     802             :         NTSTATUS status;
     803             : 
     804       16339 :         status = smbXsrv_open_close(op, 0);
     805       16339 :         if (!NT_STATUS_IS_OK(status)) {
     806           0 :                 DEBUG(0, ("smbXsrv_open_destructor: "
     807             :                           "smbXsrv_open_close() failed - %s\n",
     808             :                           nt_errstr(status)));
     809             :         }
     810             : 
     811       16339 :         TALLOC_FREE(op->global);
     812             : 
     813       16339 :         return 0;
     814             : }
     815             : 
     816       16339 : NTSTATUS smbXsrv_open_create(struct smbXsrv_connection *conn,
     817             :                              struct auth_session_info *session_info,
     818             :                              NTTIME now,
     819             :                              struct smbXsrv_open **_open)
     820             : {
     821       16339 :         struct smbXsrv_open_table *table = conn->client->open_table;
     822       16339 :         struct db_record *local_rec = NULL;
     823       16339 :         struct smbXsrv_open *op = NULL;
     824       16339 :         void *ptr = NULL;
     825             :         TDB_DATA val;
     826       16339 :         struct smbXsrv_open_global0 *global = NULL;
     827             :         NTSTATUS status;
     828       16339 :         struct dom_sid *current_sid = NULL;
     829       16339 :         struct security_token *current_token = NULL;
     830             : 
     831       16339 :         if (session_info == NULL) {
     832           0 :                 return NT_STATUS_INVALID_HANDLE;
     833             :         }
     834       16339 :         current_token = session_info->security_token;
     835             : 
     836       16339 :         if (current_token == NULL) {
     837           0 :                 return NT_STATUS_INVALID_HANDLE;
     838             :         }
     839             : 
     840       16339 :         if (current_token->num_sids > PRIMARY_USER_SID_INDEX) {
     841       16339 :                 current_sid = &current_token->sids[PRIMARY_USER_SID_INDEX];
     842             :         }
     843             : 
     844       16339 :         if (current_sid == NULL) {
     845           0 :                 return NT_STATUS_INVALID_HANDLE;
     846             :         }
     847             : 
     848       16339 :         if (table->local.num_opens >= table->local.max_opens) {
     849           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     850             :         }
     851             : 
     852       16339 :         op = talloc_zero(table, struct smbXsrv_open);
     853       16339 :         if (op == NULL) {
     854           0 :                 return NT_STATUS_NO_MEMORY;
     855             :         }
     856       16339 :         op->table = table;
     857       16339 :         op->status = NT_STATUS_OK; /* TODO: start with INTERNAL_ERROR */
     858       16339 :         op->idle_time = now;
     859             : 
     860       16339 :         status = smbXsrv_open_global_allocate(table->global.db_ctx,
     861             :                                               op, &global);
     862       16339 :         if (!NT_STATUS_IS_OK(status)) {
     863           0 :                 TALLOC_FREE(op);
     864           0 :                 return status;
     865             :         }
     866       16339 :         op->global = global;
     867             : 
     868       16339 :         status = smbXsrv_open_local_allocate_id(table->local.db_ctx,
     869             :                                                 table->local.lowest_id,
     870             :                                                 table->local.highest_id,
     871             :                                                 op,
     872             :                                                 &local_rec,
     873             :                                                 &op->local_id);
     874       16339 :         if (!NT_STATUS_IS_OK(status)) {
     875           0 :                 TALLOC_FREE(op);
     876           0 :                 return status;
     877             :         }
     878             : 
     879       16339 :         global->open_persistent_id = global->open_global_id;
     880       16339 :         global->open_volatile_id = op->local_id;
     881             : 
     882       16339 :         global->server_id = messaging_server_id(conn->client->msg_ctx);
     883       16339 :         global->open_time = now;
     884       16339 :         global->open_owner = *current_sid;
     885       16339 :         if (conn->protocol >= PROTOCOL_SMB2_10) {
     886       16335 :                 global->client_guid = conn->smb2.client.guid;
     887             :         }
     888             : 
     889       16339 :         ptr = op;
     890       16339 :         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
     891       16339 :         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
     892       16339 :         TALLOC_FREE(local_rec);
     893       16339 :         if (!NT_STATUS_IS_OK(status)) {
     894           0 :                 TALLOC_FREE(op);
     895           0 :                 return status;
     896             :         }
     897       16339 :         table->local.num_opens += 1;
     898             : 
     899       16339 :         talloc_set_destructor(op, smbXsrv_open_destructor);
     900             : 
     901       16339 :         status = smbXsrv_open_global_store(global);
     902       16339 :         if (!NT_STATUS_IS_OK(status)) {
     903           0 :                 DEBUG(0,("smbXsrv_open_create: "
     904             :                          "global_id (0x%08x) store failed - %s\n",
     905             :                          op->global->open_global_id,
     906             :                          nt_errstr(status)));
     907           0 :                 TALLOC_FREE(op);
     908           0 :                 return status;
     909             :         }
     910             : 
     911       16339 :         if (CHECK_DEBUGLVL(10)) {
     912           0 :                 struct smbXsrv_openB open_blob = {
     913             :                         .version = SMBXSRV_VERSION_0,
     914             :                         .info.info0 = op,
     915             :                 };
     916             : 
     917           0 :                 DEBUG(10,("smbXsrv_open_create: global_id (0x%08x) stored\n",
     918             :                          op->global->open_global_id));
     919           0 :                 NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
     920             :         }
     921             : 
     922       16339 :         *_open = op;
     923       16339 :         return NT_STATUS_OK;
     924             : }
     925             : 
     926           0 : static NTSTATUS smbXsrv_open_set_replay_cache(struct smbXsrv_open *op)
     927             : {
     928             :         struct GUID *create_guid;
     929             :         struct GUID_txt_buf buf;
     930             :         char *guid_string;
     931           0 :         struct db_context *db = op->table->local.replay_cache_db_ctx;
     932           0 :         struct smbXsrv_open_replay_cache rc = {
     933           0 :                 .idle_time = op->idle_time,
     934           0 :                 .local_id = op->local_id,
     935             :         };
     936           0 :         uint8_t data[SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE] = { 0 };
     937           0 :         DATA_BLOB blob = data_blob_const(data, ARRAY_SIZE(data));
     938             :         enum ndr_err_code ndr_err;
     939             :         NTSTATUS status;
     940             :         TDB_DATA key;
     941             :         TDB_DATA val;
     942             : 
     943           0 :         if (!(op->flags & SMBXSRV_OPEN_NEED_REPLAY_CACHE)) {
     944           0 :                 return NT_STATUS_OK;
     945             :         }
     946             : 
     947           0 :         if (op->flags & SMBXSRV_OPEN_HAVE_REPLAY_CACHE) {
     948           0 :                 return NT_STATUS_OK;
     949             :         }
     950             : 
     951           0 :         create_guid = &op->global->create_guid;
     952           0 :         guid_string = GUID_buf_string(create_guid, &buf);
     953           0 :         key = string_term_tdb_data(guid_string);
     954             : 
     955           0 :         ndr_err = ndr_push_struct_into_fixed_blob(&blob, &rc,
     956             :                 (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_replay_cache);
     957           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     958           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     959           0 :                 return status;
     960             :         }
     961           0 :         val = make_tdb_data(blob.data, blob.length);
     962             : 
     963           0 :         status = dbwrap_store(db, key, val, TDB_REPLACE);
     964             : 
     965           0 :         if (NT_STATUS_IS_OK(status)) {
     966           0 :                 op->flags |= SMBXSRV_OPEN_HAVE_REPLAY_CACHE;
     967           0 :                 op->flags &= ~SMBXSRV_OPEN_NEED_REPLAY_CACHE;
     968             :         }
     969             : 
     970           0 :         return status;
     971             : }
     972             : 
     973           0 : NTSTATUS smbXsrv_open_purge_replay_cache(struct smbXsrv_client *client,
     974             :                                          const struct GUID *create_guid)
     975             : {
     976             :         struct GUID_txt_buf buf;
     977             :         char *guid_string;
     978             :         struct db_context *db;
     979             : 
     980           0 :         if (client->open_table == NULL) {
     981           0 :                 return NT_STATUS_OK;
     982             :         }
     983             : 
     984           0 :         db = client->open_table->local.replay_cache_db_ctx;
     985             : 
     986           0 :         guid_string = GUID_buf_string(create_guid, &buf);
     987           0 :         if (guid_string == NULL) {
     988           0 :                 return NT_STATUS_INVALID_PARAMETER;
     989             :         }
     990             : 
     991           0 :         return dbwrap_purge_bystring(db, guid_string);
     992             : }
     993             : 
     994      128816 : static NTSTATUS smbXsrv_open_clear_replay_cache(struct smbXsrv_open *op)
     995             : {
     996             :         struct GUID *create_guid;
     997             :         struct GUID_txt_buf buf;
     998             :         char *guid_string;
     999             :         struct db_context *db;
    1000             :         NTSTATUS status;
    1001             : 
    1002      128816 :         if (op->table == NULL) {
    1003           0 :                 return NT_STATUS_OK;
    1004             :         }
    1005             : 
    1006      128816 :         db = op->table->local.replay_cache_db_ctx;
    1007             : 
    1008      128816 :         if (!(op->flags & SMBXSRV_OPEN_HAVE_REPLAY_CACHE)) {
    1009      128816 :                 return NT_STATUS_OK;
    1010             :         }
    1011             : 
    1012           0 :         create_guid = &op->global->create_guid;
    1013           0 :         if (GUID_all_zero(create_guid)) {
    1014           0 :                 return NT_STATUS_OK;
    1015             :         }
    1016             : 
    1017           0 :         guid_string = GUID_buf_string(create_guid, &buf);
    1018           0 :         if (guid_string == NULL) {
    1019           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1020             :         }
    1021             : 
    1022           0 :         status = dbwrap_purge_bystring(db, guid_string);
    1023             : 
    1024           0 :         if (NT_STATUS_IS_OK(status)) {
    1025           0 :                 op->flags &= ~SMBXSRV_OPEN_HAVE_REPLAY_CACHE;
    1026             :         }
    1027             : 
    1028           0 :         return status;
    1029             : }
    1030             : 
    1031           0 : NTSTATUS smbXsrv_open_update(struct smbXsrv_open *op)
    1032             : {
    1033           0 :         struct smbXsrv_open_table *table = op->table;
    1034             :         NTSTATUS status;
    1035             : 
    1036           0 :         if (op->global->db_rec != NULL) {
    1037           0 :                 DEBUG(0, ("smbXsrv_open_update(0x%08x): "
    1038             :                           "Called with db_rec != NULL'\n",
    1039             :                           op->global->open_global_id));
    1040           0 :                 return NT_STATUS_INTERNAL_ERROR;
    1041             :         }
    1042             : 
    1043           0 :         op->global->db_rec = smbXsrv_open_global_fetch_locked(
    1044             :                                                 table->global.db_ctx,
    1045           0 :                                                 op->global->open_global_id,
    1046           0 :                                                 op->global /* TALLOC_CTX */);
    1047           0 :         if (op->global->db_rec == NULL) {
    1048           0 :                 return NT_STATUS_INTERNAL_DB_ERROR;
    1049             :         }
    1050             : 
    1051           0 :         status = smbXsrv_open_global_store(op->global);
    1052           0 :         if (!NT_STATUS_IS_OK(status)) {
    1053           0 :                 DEBUG(0,("smbXsrv_open_update: "
    1054             :                          "global_id (0x%08x) store failed - %s\n",
    1055             :                          op->global->open_global_id,
    1056             :                          nt_errstr(status)));
    1057           0 :                 return status;
    1058             :         }
    1059             : 
    1060           0 :         status = smbXsrv_open_set_replay_cache(op);
    1061           0 :         if (!NT_STATUS_IS_OK(status)) {
    1062           0 :                 DBG_ERR("smbXsrv_open_set_replay_cache failed: %s\n",
    1063             :                         nt_errstr(status));
    1064           0 :                 return status;
    1065             :         }
    1066             : 
    1067           0 :         if (CHECK_DEBUGLVL(10)) {
    1068           0 :                 struct smbXsrv_openB open_blob = {
    1069             :                         .version = SMBXSRV_VERSION_0,
    1070             :                         .info.info0 = op,
    1071             :                 };
    1072             : 
    1073           0 :                 DEBUG(10,("smbXsrv_open_update: global_id (0x%08x) stored\n",
    1074             :                           op->global->open_global_id));
    1075           0 :                 NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
    1076             :         }
    1077             : 
    1078           0 :         return NT_STATUS_OK;
    1079             : }
    1080             : 
    1081       16339 : NTSTATUS smbXsrv_open_close(struct smbXsrv_open *op, NTTIME now)
    1082             : {
    1083             :         struct smbXsrv_open_table *table;
    1084       16339 :         struct db_record *local_rec = NULL;
    1085       16339 :         struct db_record *global_rec = NULL;
    1086             :         NTSTATUS status;
    1087       16339 :         NTSTATUS error = NT_STATUS_OK;
    1088             : 
    1089       16339 :         error = smbXsrv_open_clear_replay_cache(op);
    1090       16339 :         if (!NT_STATUS_IS_OK(error)) {
    1091           0 :                 DBG_ERR("smbXsrv_open_clear_replay_cache failed: %s\n",
    1092             :                         nt_errstr(error));
    1093             :         }
    1094             : 
    1095       16339 :         if (op->table == NULL) {
    1096           0 :                 return error;
    1097             :         }
    1098             : 
    1099       16339 :         table = op->table;
    1100       16339 :         op->table = NULL;
    1101             : 
    1102       16339 :         op->status = NT_STATUS_FILE_CLOSED;
    1103       16339 :         op->global->disconnect_time = now;
    1104       16339 :         server_id_set_disconnected(&op->global->server_id);
    1105             : 
    1106       16339 :         global_rec = op->global->db_rec;
    1107       16339 :         op->global->db_rec = NULL;
    1108       16339 :         if (global_rec == NULL) {
    1109       16339 :                 global_rec = smbXsrv_open_global_fetch_locked(
    1110             :                                         table->global.db_ctx,
    1111       16339 :                                         op->global->open_global_id,
    1112       16339 :                                         op->global /* TALLOC_CTX */);
    1113       16339 :                 if (global_rec == NULL) {
    1114           0 :                         error = NT_STATUS_INTERNAL_ERROR;
    1115             :                 }
    1116             :         }
    1117             : 
    1118       16339 :         if (global_rec != NULL && op->global->durable) {
    1119             :                 /*
    1120             :                  * If it is a durable open we need to update the global part
    1121             :                  * instead of deleting it
    1122             :                  */
    1123           0 :                 op->global->db_rec = global_rec;
    1124           0 :                 status = smbXsrv_open_global_store(op->global);
    1125           0 :                 if (NT_STATUS_IS_OK(status)) {
    1126             :                         /*
    1127             :                          * smbXsrv_open_global_store does the free
    1128             :                          * of op->global->db_rec
    1129             :                          */
    1130           0 :                         global_rec = NULL;
    1131             :                 }
    1132           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1133           0 :                         DEBUG(0,("smbXsrv_open_close(0x%08x)"
    1134             :                                  "smbXsrv_open_global_store() failed - %s\n",
    1135             :                                  op->global->open_global_id,
    1136             :                                  nt_errstr(status)));
    1137           0 :                         error = status;
    1138             :                 }
    1139             : 
    1140           0 :                 if (NT_STATUS_IS_OK(status) && CHECK_DEBUGLVL(10)) {
    1141           0 :                         struct smbXsrv_openB open_blob = {
    1142             :                                 .version = SMBXSRV_VERSION_0,
    1143             :                                 .info.info0 = op,
    1144             :                         };
    1145             : 
    1146           0 :                         DEBUG(10,("smbXsrv_open_close(0x%08x): "
    1147             :                                   "stored disconnect\n",
    1148             :                                   op->global->open_global_id));
    1149           0 :                         NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
    1150             :                 }
    1151             :         }
    1152             : 
    1153       16339 :         if (global_rec != NULL) {
    1154       16339 :                 status = dbwrap_record_delete(global_rec);
    1155       16339 :                 if (!NT_STATUS_IS_OK(status)) {
    1156           0 :                         TDB_DATA key = dbwrap_record_get_key(global_rec);
    1157             : 
    1158           0 :                         DEBUG(0, ("smbXsrv_open_close(0x%08x): "
    1159             :                                   "failed to delete global key '%s': %s\n",
    1160             :                                   op->global->open_global_id,
    1161             :                                   hex_encode_talloc(global_rec, key.dptr,
    1162             :                                                     key.dsize),
    1163             :                                   nt_errstr(status)));
    1164           0 :                         error = status;
    1165             :                 }
    1166             :         }
    1167       16339 :         TALLOC_FREE(global_rec);
    1168             : 
    1169       16339 :         local_rec = op->db_rec;
    1170       16339 :         if (local_rec == NULL) {
    1171       16339 :                 local_rec = smbXsrv_open_local_fetch_locked(table->local.db_ctx,
    1172             :                                                             op->local_id,
    1173             :                                                             op /* TALLOC_CTX*/);
    1174       16339 :                 if (local_rec == NULL) {
    1175           0 :                         error = NT_STATUS_INTERNAL_ERROR;
    1176             :                 }
    1177             :         }
    1178             : 
    1179       16339 :         if (local_rec != NULL) {
    1180       16339 :                 status = dbwrap_record_delete(local_rec);
    1181       16339 :                 if (!NT_STATUS_IS_OK(status)) {
    1182           0 :                         TDB_DATA key = dbwrap_record_get_key(local_rec);
    1183             : 
    1184           0 :                         DEBUG(0, ("smbXsrv_open_close(0x%08x): "
    1185             :                                   "failed to delete local key '%s': %s\n",
    1186             :                                   op->global->open_global_id,
    1187             :                                   hex_encode_talloc(local_rec, key.dptr,
    1188             :                                                     key.dsize),
    1189             :                                   nt_errstr(status)));
    1190           0 :                         error = status;
    1191             :                 }
    1192       16339 :                 table->local.num_opens -= 1;
    1193             :         }
    1194       16339 :         if (op->db_rec == NULL) {
    1195       16339 :                 TALLOC_FREE(local_rec);
    1196             :         }
    1197       16339 :         op->db_rec = NULL;
    1198             : 
    1199       16339 :         if (op->compat) {
    1200           0 :                 op->compat->op = NULL;
    1201           0 :                 file_free(NULL, op->compat);
    1202           0 :                 op->compat = NULL;
    1203             :         }
    1204             : 
    1205       16339 :         return error;
    1206             : }
    1207             : 
    1208          38 : NTSTATUS smb1srv_open_table_init(struct smbXsrv_connection *conn)
    1209             : {
    1210             :         uint32_t max_opens;
    1211             : 
    1212             :         /*
    1213             :          * Allow a range from 1..65534.
    1214             :          *
    1215             :          * With real_max_open_files possible ids,
    1216             :          * truncated to the SMB1 limit of 16-bit.
    1217             :          *
    1218             :          * 0 and 0xFFFF are no valid ids.
    1219             :          */
    1220          38 :         max_opens = conn->client->sconn->real_max_open_files;
    1221          38 :         max_opens = MIN(max_opens, UINT16_MAX - 1);
    1222             : 
    1223          38 :         return smbXsrv_open_table_init(conn, 1, UINT16_MAX - 1, max_opens);
    1224             : }
    1225             : 
    1226           0 : NTSTATUS smb1srv_open_lookup(struct smbXsrv_connection *conn,
    1227             :                              uint16_t fnum, NTTIME now,
    1228             :                              struct smbXsrv_open **_open)
    1229             : {
    1230           0 :         struct smbXsrv_open_table *table = conn->client->open_table;
    1231           0 :         uint32_t local_id = fnum;
    1232           0 :         uint32_t global_id = 0;
    1233             : 
    1234           0 :         return smbXsrv_open_local_lookup(table, local_id, global_id, now, _open);
    1235             : }
    1236             : 
    1237        5002 : NTSTATUS smb2srv_open_table_init(struct smbXsrv_connection *conn)
    1238             : {
    1239             :         uint32_t max_opens;
    1240             : 
    1241             :         /*
    1242             :          * Allow a range from 1..4294967294.
    1243             :          *
    1244             :          * With real_max_open_files possible ids,
    1245             :          * truncated to 16-bit (the same as SMB1 for now).
    1246             :          *
    1247             :          * 0 and 0xFFFFFFFF are no valid ids.
    1248             :          *
    1249             :          * The usage of conn->sconn->real_max_open_files
    1250             :          * is the reason that we use one open table per
    1251             :          * transport connection (as we still have a 1:1 mapping
    1252             :          * between process and transport connection).
    1253             :          */
    1254        5002 :         max_opens = conn->client->sconn->real_max_open_files;
    1255        5002 :         max_opens = MIN(max_opens, UINT16_MAX - 1);
    1256             : 
    1257        5002 :         return smbXsrv_open_table_init(conn, 1, UINT32_MAX - 1, max_opens);
    1258             : }
    1259             : 
    1260      114138 : NTSTATUS smb2srv_open_lookup(struct smbXsrv_connection *conn,
    1261             :                              uint64_t persistent_id,
    1262             :                              uint64_t volatile_id,
    1263             :                              NTTIME now,
    1264             :                              struct smbXsrv_open **_open)
    1265             : {
    1266      114138 :         struct smbXsrv_open_table *table = conn->client->open_table;
    1267      114138 :         uint32_t local_id = volatile_id & UINT32_MAX;
    1268      114138 :         uint64_t local_zeros = volatile_id & 0xFFFFFFFF00000000LLU;
    1269      114138 :         uint32_t global_id = persistent_id & UINT32_MAX;
    1270      114138 :         uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU;
    1271             :         NTSTATUS status;
    1272             : 
    1273      114138 :         if (local_zeros != 0) {
    1274        1659 :                 return NT_STATUS_FILE_CLOSED;
    1275             :         }
    1276             : 
    1277      112479 :         if (global_zeros != 0) {
    1278           0 :                 return NT_STATUS_FILE_CLOSED;
    1279             :         }
    1280             : 
    1281      112479 :         if (global_id == 0) {
    1282           0 :                 return NT_STATUS_FILE_CLOSED;
    1283             :         }
    1284             : 
    1285      112479 :         status = smbXsrv_open_local_lookup(table, local_id, global_id, now,
    1286             :                                            _open);
    1287      112479 :         if (!NT_STATUS_IS_OK(status)) {
    1288           2 :                 return status;
    1289             :         }
    1290             : 
    1291             :         /*
    1292             :          * Clear the replay cache for this create_guid if it exists:
    1293             :          * This is based on the assumption that this lookup will be
    1294             :          * triggered by a client request using the file-id for lookup.
    1295             :          * Hence the client has proven that it has in fact seen the
    1296             :          * reply to its initial create call. So subsequent create replays
    1297             :          * should be treated as invalid. Hence the index for create_guid
    1298             :          * lookup needs to be removed.
    1299             :          */
    1300      112477 :         status = smbXsrv_open_clear_replay_cache(*_open);
    1301             : 
    1302      112477 :         return status;
    1303             : }
    1304             : 
    1305             : /*
    1306             :  * This checks or marks the replay cache, we have the following
    1307             :  * cases:
    1308             :  *
    1309             :  * 1. There is no record in the cache
    1310             :  *    => we add the passes caller_req_guid as holder_req_guid
    1311             :  *       together with local_id as 0.
    1312             :  *    => We return STATUS_FWP_RESERVED in order to indicate
    1313             :  *       that the caller holds the current reservation
    1314             :  *
    1315             :  * 2. There is a record in the cache and holder_req_guid
    1316             :  *    is already the same as caller_req_guid and local_id is 0
    1317             :  *    => We return STATUS_FWP_RESERVED in order to indicate
    1318             :  *       that the caller holds the current reservation
    1319             :  *
    1320             :  * 3. There is a record in the cache with a holder_req_guid
    1321             :  *    other than caller_req_guid (and local_id is 0):
    1322             :  *    => We return NT_STATUS_FILE_NOT_AVAILABLE to indicate
    1323             :  *       the original request is still pending
    1324             :  *
    1325             :  * 4. There is a record in the cache with a zero holder_req_guid
    1326             :  *    and a valid local_id:
    1327             :  *    => We lookup the existing open by local_id
    1328             :  *    => We return NT_STATUS_OK together with the smbXsrv_open
    1329             :  *
    1330             :  *
    1331             :  * With NT_STATUS_OK the caller can continue the replay processing.
    1332             :  *
    1333             :  * With STATUS_FWP_RESERVED the caller should continue the normal
    1334             :  * open processing:
    1335             :  * - On success:
    1336             :  *   - smbXsrv_open_update()/smbXsrv_open_set_replay_cache()
    1337             :  *     will convert the record to a zero holder_req_guid
    1338             :  *     with a valid local_id.
    1339             :  * - On failure:
    1340             :  *   - smbXsrv_open_purge_replay_cache() should cleanup
    1341             :  *     the reservation.
    1342             :  *
    1343             :  * All other values should be returned to the client,
    1344             :  * while NT_STATUS_FILE_NOT_AVAILABLE will trigger the
    1345             :  * retry loop on the client.
    1346             :  */
    1347           0 : NTSTATUS smb2srv_open_lookup_replay_cache(struct smbXsrv_connection *conn,
    1348             :                                           struct GUID caller_req_guid,
    1349             :                                           struct GUID create_guid,
    1350             :                                           const char *name,
    1351             :                                           NTTIME now,
    1352             :                                           struct smbXsrv_open **_open)
    1353             : {
    1354           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1355             :         NTSTATUS status;
    1356           0 :         struct smbXsrv_open_table *table = conn->client->open_table;
    1357           0 :         struct db_context *db = table->local.replay_cache_db_ctx;
    1358             :         struct GUID_txt_buf _create_guid_buf;
    1359             :         struct GUID_txt_buf tmp_guid_buf;
    1360           0 :         const char *create_guid_str = NULL;
    1361             :         TDB_DATA create_guid_key;
    1362           0 :         struct db_record *db_rec = NULL;
    1363           0 :         struct smbXsrv_open *op = NULL;
    1364           0 :         struct smbXsrv_open_replay_cache rc = {
    1365             :                 .holder_req_guid = caller_req_guid,
    1366             :                 .idle_time = now,
    1367             :                 .local_id = 0,
    1368             :         };
    1369             :         enum ndr_err_code ndr_err;
    1370           0 :         DATA_BLOB blob = data_blob_null;
    1371             :         TDB_DATA val;
    1372             : 
    1373           0 :         *_open = NULL;
    1374             : 
    1375           0 :         create_guid_str = GUID_buf_string(&create_guid, &_create_guid_buf);
    1376           0 :         create_guid_key = string_term_tdb_data(create_guid_str);
    1377             : 
    1378           0 :         db_rec = dbwrap_fetch_locked(db, frame, create_guid_key);
    1379           0 :         if (db_rec == NULL) {
    1380           0 :                 TALLOC_FREE(frame);
    1381           0 :                 return NT_STATUS_INTERNAL_DB_ERROR;
    1382             :         }
    1383             : 
    1384           0 :         val = dbwrap_record_get_value(db_rec);
    1385           0 :         if (val.dsize == 0) {
    1386             :                 uint8_t data[SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE];
    1387             : 
    1388           0 :                 blob = data_blob_const(data, ARRAY_SIZE(data));
    1389           0 :                 ndr_err = ndr_push_struct_into_fixed_blob(&blob, &rc,
    1390             :                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_open_replay_cache);
    1391           0 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1392           0 :                         status = ndr_map_error2ntstatus(ndr_err);
    1393           0 :                         TALLOC_FREE(frame);
    1394           0 :                         return status;
    1395             :                 }
    1396             : 
    1397           0 :                 val = make_tdb_data(blob.data, blob.length);
    1398           0 :                 status = dbwrap_record_store(db_rec, val, TDB_REPLACE);
    1399           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1400           0 :                         TALLOC_FREE(frame);
    1401           0 :                         return status;
    1402             :                 }
    1403             : 
    1404             :                 /*
    1405             :                  * We're the new holder
    1406             :                  */
    1407           0 :                 *_open = NULL;
    1408           0 :                 TALLOC_FREE(frame);
    1409           0 :                 return NT_STATUS_FWP_RESERVED;
    1410             :         }
    1411             : 
    1412           0 :         if (val.dsize != SMBXSRV_OPEN_REPLAY_CACHE_FIXED_SIZE) {
    1413           0 :                 TALLOC_FREE(frame);
    1414           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1415             :         }
    1416             : 
    1417           0 :         blob = data_blob_const(val.dptr, val.dsize);
    1418           0 :         ndr_err = ndr_pull_struct_blob_all_noalloc(&blob, &rc,
    1419             :                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_replay_cache);
    1420           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1421           0 :                 status = ndr_map_error2ntstatus(ndr_err);
    1422           0 :                 TALLOC_FREE(frame);
    1423           0 :                 return status;
    1424             :         }
    1425           0 :         if (rc.local_id != 0) {
    1426           0 :                 if (GUID_equal(&rc.holder_req_guid, &caller_req_guid)) {
    1427             :                         /*
    1428             :                          * This should not happen
    1429             :                          */
    1430           0 :                         status = NT_STATUS_INTERNAL_ERROR;
    1431           0 :                         DBG_ERR("caller %s already holds local_id %u for create %s [%s] - %s\n",
    1432             :                                 GUID_buf_string(&caller_req_guid, &tmp_guid_buf),
    1433             :                                 (unsigned)rc.local_id,
    1434             :                                 create_guid_str,
    1435             :                                 name,
    1436             :                                 nt_errstr(status));
    1437             : 
    1438           0 :                         TALLOC_FREE(frame);
    1439           0 :                         return status;
    1440             :                 }
    1441             : 
    1442           0 :                 status = smbXsrv_open_local_lookup(table,
    1443             :                                                    rc.local_id,
    1444             :                                                    0, /* global_id */
    1445             :                                                    now,
    1446             :                                                    &op);
    1447           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1448           0 :                         DBG_ERR("holder %s stale for local_id %u for create %s [%s] - %s\n",
    1449             :                                 GUID_buf_string(&rc.holder_req_guid, &tmp_guid_buf),
    1450             :                                 (unsigned)rc.local_id,
    1451             :                                 create_guid_str,
    1452             :                                 name,
    1453             :                                 nt_errstr(status));
    1454             : 
    1455           0 :                         TALLOC_FREE(frame);
    1456           0 :                         return status;
    1457             :                 }
    1458             : 
    1459             :                 /*
    1460             :                  * We found an open the caller can reuse.
    1461             :                  */
    1462           0 :                 SMB_ASSERT(op != NULL);
    1463           0 :                 *_open = op;
    1464           0 :                 TALLOC_FREE(frame);
    1465           0 :                 return NT_STATUS_OK;
    1466             :         }
    1467             : 
    1468           0 :         if (GUID_equal(&rc.holder_req_guid, &caller_req_guid)) {
    1469             :                 /*
    1470             :                  * We're still the holder
    1471             :                  */
    1472           0 :                 *_open = NULL;
    1473           0 :                 TALLOC_FREE(frame);
    1474           0 :                 return NT_STATUS_FWP_RESERVED;
    1475             :         }
    1476             : 
    1477             :         /*
    1478             :          * The original request (or a former replay) is still
    1479             :          * pending, ask the client to retry by sending FILE_NOT_AVAILABLE.
    1480             :          */
    1481           0 :         status = NT_STATUS_FILE_NOT_AVAILABLE;
    1482           0 :         DBG_DEBUG("holder %s still pending for create %s [%s] - %s\n",
    1483             :                    GUID_buf_string(&rc.holder_req_guid, &tmp_guid_buf),
    1484             :                    create_guid_str,
    1485             :                    name,
    1486             :                    nt_errstr(status));
    1487           0 :         TALLOC_FREE(frame);
    1488           0 :         return status;
    1489             : }
    1490             : 
    1491           0 : NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
    1492             :                                struct auth_session_info *session_info,
    1493             :                                uint64_t persistent_id,
    1494             :                                const struct GUID *create_guid,
    1495             :                                NTTIME now,
    1496             :                                struct smbXsrv_open **_open)
    1497             : {
    1498           0 :         struct smbXsrv_open_table *table = conn->client->open_table;
    1499           0 :         struct db_record *local_rec = NULL;
    1500           0 :         struct smbXsrv_open *op = NULL;
    1501           0 :         void *ptr = NULL;
    1502             :         TDB_DATA val;
    1503           0 :         uint32_t global_id = persistent_id & UINT32_MAX;
    1504           0 :         uint64_t global_zeros = persistent_id & 0xFFFFFFFF00000000LLU;
    1505             :         NTSTATUS status;
    1506           0 :         struct security_token *current_token = NULL;
    1507             : 
    1508           0 :         if (session_info == NULL) {
    1509           0 :                 DEBUG(10, ("session_info=NULL\n"));
    1510           0 :                 return NT_STATUS_INVALID_HANDLE;
    1511             :         }
    1512           0 :         current_token = session_info->security_token;
    1513             : 
    1514           0 :         if (current_token == NULL) {
    1515           0 :                 DEBUG(10, ("current_token=NULL\n"));
    1516           0 :                 return NT_STATUS_INVALID_HANDLE;
    1517             :         }
    1518             : 
    1519           0 :         if (global_zeros != 0) {
    1520           0 :                 DEBUG(10, ("global_zeros!=0\n"));
    1521           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    1522             :         }
    1523             : 
    1524           0 :         op = talloc_zero(table, struct smbXsrv_open);
    1525           0 :         if (op == NULL) {
    1526           0 :                 return NT_STATUS_NO_MEMORY;
    1527             :         }
    1528           0 :         op->table = table;
    1529             : 
    1530           0 :         status = smbXsrv_open_global_lookup(table, global_id, op, &op->global);
    1531           0 :         if (!NT_STATUS_IS_OK(status)) {
    1532           0 :                 TALLOC_FREE(op);
    1533           0 :                 DEBUG(10, ("smbXsrv_open_global_lookup returned %s\n",
    1534             :                            nt_errstr(status)));
    1535           0 :                 return status;
    1536             :         }
    1537             : 
    1538             :         /*
    1539             :          * If the provided create_guid is NULL, this means that
    1540             :          * the reconnect request was a v1 request. In that case
    1541             :          * we should skipt the create GUID verification, since
    1542             :          * it is valid to v1-reconnect a v2-opened handle.
    1543             :          */
    1544           0 :         if ((create_guid != NULL) &&
    1545           0 :             !GUID_equal(&op->global->create_guid, create_guid))
    1546             :         {
    1547           0 :                 TALLOC_FREE(op);
    1548           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    1549             :         }
    1550             : 
    1551           0 :         if (!security_token_is_sid(current_token, &op->global->open_owner)) {
    1552           0 :                 TALLOC_FREE(op);
    1553           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    1554             :         }
    1555             : 
    1556           0 :         if (!op->global->durable) {
    1557           0 :                 TALLOC_FREE(op);
    1558           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    1559             :         }
    1560             : 
    1561           0 :         if (table->local.num_opens >= table->local.max_opens) {
    1562           0 :                 TALLOC_FREE(op);
    1563           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
    1564             :         }
    1565             : 
    1566           0 :         status = smbXsrv_open_local_allocate_id(table->local.db_ctx,
    1567             :                                                 table->local.lowest_id,
    1568             :                                                 table->local.highest_id,
    1569             :                                                 op,
    1570             :                                                 &local_rec,
    1571             :                                                 &op->local_id);
    1572           0 :         if (!NT_STATUS_IS_OK(status)) {
    1573           0 :                 TALLOC_FREE(op);
    1574           0 :                 return status;
    1575             :         }
    1576             : 
    1577           0 :         op->idle_time = now;
    1578           0 :         op->status = NT_STATUS_FILE_CLOSED;
    1579             : 
    1580           0 :         op->global->open_volatile_id = op->local_id;
    1581           0 :         op->global->server_id = messaging_server_id(conn->client->msg_ctx);
    1582             : 
    1583           0 :         ptr = op;
    1584           0 :         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
    1585           0 :         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
    1586           0 :         TALLOC_FREE(local_rec);
    1587           0 :         if (!NT_STATUS_IS_OK(status)) {
    1588           0 :                 TALLOC_FREE(op);
    1589           0 :                 return status;
    1590             :         }
    1591           0 :         table->local.num_opens += 1;
    1592             : 
    1593           0 :         talloc_set_destructor(op, smbXsrv_open_destructor);
    1594             : 
    1595           0 :         status = smbXsrv_open_global_store(op->global);
    1596           0 :         if (!NT_STATUS_IS_OK(status)) {
    1597           0 :                 TALLOC_FREE(op);
    1598           0 :                 return status;
    1599             :         }
    1600             : 
    1601           0 :         if (CHECK_DEBUGLVL(10)) {
    1602           0 :                 struct smbXsrv_openB open_blob = {
    1603             :                         .info.info0 = op,
    1604             :                 };
    1605             : 
    1606           0 :                 DEBUG(10,("smbXsrv_open_recreate: global_id (0x%08x) stored\n",
    1607             :                          op->global->open_global_id));
    1608           0 :                 NDR_PRINT_DEBUG(smbXsrv_openB, &open_blob);
    1609             :         }
    1610             : 
    1611           0 :         *_open = op;
    1612           0 :         return NT_STATUS_OK;
    1613             : }
    1614             : 
    1615             : 
    1616           0 : static NTSTATUS smbXsrv_open_global_parse_record(TALLOC_CTX *mem_ctx,
    1617             :                                                  struct db_record *rec,
    1618             :                                                  struct smbXsrv_open_global0 **global)
    1619             : {
    1620           0 :         TDB_DATA key = dbwrap_record_get_key(rec);
    1621           0 :         TDB_DATA val = dbwrap_record_get_value(rec);
    1622           0 :         DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
    1623             :         struct smbXsrv_open_globalB global_blob;
    1624             :         enum ndr_err_code ndr_err;
    1625             :         NTSTATUS status;
    1626           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1627             : 
    1628           0 :         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
    1629             :                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_globalB);
    1630           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1631           0 :                 DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:"
    1632             :                          "key '%s' ndr_pull_struct_blob - %s\n",
    1633             :                          hex_encode_talloc(frame, key.dptr, key.dsize),
    1634             :                          ndr_errstr(ndr_err)));
    1635           0 :                 status = ndr_map_error2ntstatus(ndr_err);
    1636           0 :                 goto done;
    1637             :         }
    1638             : 
    1639           0 :         if (global_blob.version != SMBXSRV_VERSION_0) {
    1640           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
    1641           0 :                 DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:"
    1642             :                          "key '%s' unsupported version - %d - %s\n",
    1643             :                          hex_encode_talloc(frame, key.dptr, key.dsize),
    1644             :                          (int)global_blob.version,
    1645             :                          nt_errstr(status)));
    1646           0 :                 goto done;
    1647             :         }
    1648             : 
    1649           0 :         if (global_blob.info.info0 == NULL) {
    1650           0 :                 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
    1651           0 :                 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
    1652             :                          "key '%s' info0 NULL pointer - %s\n",
    1653             :                          hex_encode_talloc(frame, key.dptr, key.dsize),
    1654             :                          nt_errstr(status)));
    1655           0 :                 goto done;
    1656             :         }
    1657             : 
    1658           0 :         *global = talloc_move(mem_ctx, &global_blob.info.info0);
    1659           0 :         status = NT_STATUS_OK;
    1660           0 : done:
    1661           0 :         talloc_free(frame);
    1662           0 :         return status;
    1663             : }
    1664             : 
    1665             : struct smbXsrv_open_global_traverse_state {
    1666             :         int (*fn)(struct smbXsrv_open_global0 *, void *);
    1667             :         void *private_data;
    1668             : };
    1669             : 
    1670           0 : static int smbXsrv_open_global_traverse_fn(struct db_record *rec, void *data)
    1671             : {
    1672           0 :         struct smbXsrv_open_global_traverse_state *state =
    1673             :                 (struct smbXsrv_open_global_traverse_state*)data;
    1674           0 :         struct smbXsrv_open_global0 *global = NULL;
    1675             :         NTSTATUS status;
    1676           0 :         int ret = -1;
    1677             : 
    1678           0 :         status = smbXsrv_open_global_parse_record(talloc_tos(), rec, &global);
    1679           0 :         if (!NT_STATUS_IS_OK(status)) {
    1680           0 :                 return -1;
    1681             :         }
    1682             : 
    1683           0 :         global->db_rec = rec;
    1684           0 :         ret = state->fn(global, state->private_data);
    1685           0 :         talloc_free(global);
    1686           0 :         return ret;
    1687             : }
    1688             : 
    1689           0 : NTSTATUS smbXsrv_open_global_traverse(
    1690             :                         int (*fn)(struct smbXsrv_open_global0 *, void *),
    1691             :                         void *private_data)
    1692             : {
    1693             : 
    1694             :         NTSTATUS status;
    1695           0 :         int count = 0;
    1696           0 :         struct smbXsrv_open_global_traverse_state state = {
    1697             :                 .fn = fn,
    1698             :                 .private_data = private_data,
    1699             :         };
    1700             : 
    1701           0 :         become_root();
    1702           0 :         status = smbXsrv_open_global_init();
    1703           0 :         if (!NT_STATUS_IS_OK(status)) {
    1704           0 :                 unbecome_root();
    1705           0 :                 DEBUG(0, ("Failed to initialize open_global: %s\n",
    1706             :                           nt_errstr(status)));
    1707           0 :                 return status;
    1708             :         }
    1709             : 
    1710           0 :         status = dbwrap_traverse_read(smbXsrv_open_global_db_ctx,
    1711             :                                       smbXsrv_open_global_traverse_fn,
    1712             :                                       &state,
    1713             :                                       &count);
    1714           0 :         unbecome_root();
    1715             : 
    1716           0 :         return status;
    1717             : }
    1718             : 
    1719           0 : NTSTATUS smbXsrv_open_cleanup(uint64_t persistent_id)
    1720             : {
    1721           0 :         NTSTATUS status = NT_STATUS_OK;
    1722           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1723           0 :         struct smbXsrv_open_global0 *op = NULL;
    1724             :         TDB_DATA val;
    1725             :         struct db_record *rec;
    1726           0 :         bool delete_open = false;
    1727           0 :         uint32_t global_id = persistent_id & UINT32_MAX;
    1728             : 
    1729           0 :         rec = smbXsrv_open_global_fetch_locked(smbXsrv_open_global_db_ctx,
    1730             :                                                global_id,
    1731             :                                                frame);
    1732           0 :         if (rec == NULL) {
    1733           0 :                 status = NT_STATUS_NOT_FOUND;
    1734           0 :                 goto done;
    1735             :         }
    1736             : 
    1737           0 :         val = dbwrap_record_get_value(rec);
    1738           0 :         if (val.dsize == 0) {
    1739           0 :                 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
    1740             :                           "empty record in %s, skipping...\n",
    1741             :                            global_id, dbwrap_name(smbXsrv_open_global_db_ctx)));
    1742           0 :                 goto done;
    1743             :         }
    1744             : 
    1745           0 :         status = smbXsrv_open_global_parse_record(talloc_tos(), rec, &op);
    1746           0 :         if (!NT_STATUS_IS_OK(status)) {
    1747           0 :                 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
    1748             :                           "failed to read record: %s\n",
    1749             :                           global_id, nt_errstr(status)));
    1750           0 :                 goto done;
    1751             :         }
    1752             : 
    1753           0 :         if (server_id_is_disconnected(&op->server_id)) {
    1754             :                 struct timeval now, disconnect_time;
    1755             :                 int64_t tdiff;
    1756           0 :                 now = timeval_current();
    1757           0 :                 nttime_to_timeval(&disconnect_time, op->disconnect_time);
    1758           0 :                 tdiff = usec_time_diff(&now, &disconnect_time);
    1759           0 :                 delete_open = (tdiff >= 1000*op->durable_timeout_msec);
    1760             : 
    1761           0 :                 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
    1762             :                            "disconnected at [%s] %us ago with "
    1763             :                            "timeout of %us -%s reached\n",
    1764             :                            global_id,
    1765             :                            nt_time_string(frame, op->disconnect_time),
    1766             :                            (unsigned)(tdiff/1000000),
    1767             :                            op->durable_timeout_msec / 1000,
    1768             :                            delete_open ? "" : " not"));
    1769           0 :         } else if (!serverid_exists(&op->server_id)) {
    1770             :                 struct server_id_buf idbuf;
    1771           0 :                 DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
    1772             :                            "server[%s] does not exist\n",
    1773             :                            global_id,
    1774             :                            server_id_str_buf(op->server_id, &idbuf)));
    1775           0 :                 delete_open = true;
    1776             :         }
    1777             : 
    1778           0 :         if (!delete_open) {
    1779           0 :                 goto done;
    1780             :         }
    1781             : 
    1782           0 :         status = dbwrap_record_delete(rec);
    1783           0 :         if (!NT_STATUS_IS_OK(status)) {
    1784           0 :                 DEBUG(1, ("smbXsrv_open_cleanup[global: 0x%08x] "
    1785             :                           "failed to delete record"
    1786             :                           "from %s: %s\n", global_id,
    1787             :                           dbwrap_name(smbXsrv_open_global_db_ctx),
    1788             :                           nt_errstr(status)));
    1789           0 :                 goto done;
    1790             :         }
    1791             : 
    1792           0 :         DEBUG(10, ("smbXsrv_open_cleanup[global: 0x%08x] "
    1793             :                    "delete record from %s\n",
    1794             :                    global_id,
    1795             :                    dbwrap_name(smbXsrv_open_global_db_ctx)));
    1796             : 
    1797           0 : done:
    1798           0 :         talloc_free(frame);
    1799           0 :         return status;
    1800             : }

Generated by: LCOV version 1.13