LCOV - code coverage report
Current view: top level - source3/smbd - smbXsrv_open.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 453 676 67.0 %
Date: 2024-01-11 09:59:51 Functions: 27 29 93.1 %

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

Generated by: LCOV version 1.14