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

Generated by: LCOV version 1.14