LCOV - code coverage report
Current view: top level - source3/smbd - smbXsrv_open.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 502 756 66.4 %
Date: 2021-08-25 13:27:56 Functions: 30 35 85.7 %

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

Generated by: LCOV version 1.13