LCOV - code coverage report
Current view: top level - source3/smbd - smbXsrv_tcon.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 377 565 66.7 %
Date: 2024-04-13 12:30:31 Functions: 29 31 93.5 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Stefan Metzmacher 2011-2012
       5             :    Copyright (C) Michael Adam 2012
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "system/filesys.h"
      23             : #include "lib/util/server_id.h"
      24             : #include "smbd/smbd.h"
      25             : #include "smbd/globals.h"
      26             : #include "dbwrap/dbwrap.h"
      27             : #include "dbwrap/dbwrap_rbt.h"
      28             : #include "dbwrap/dbwrap_open.h"
      29             : #include "messages.h"
      30             : #include "lib/util/util_tdb.h"
      31             : #include "librpc/gen_ndr/ndr_smbXsrv.h"
      32             : #include "serverid.h"
      33             : #include "source3/include/util_tdb.h"
      34             : 
      35             : struct smbXsrv_tcon_table {
      36             :         struct {
      37             :                 struct db_context *db_ctx;
      38             :                 uint32_t lowest_id;
      39             :                 uint32_t highest_id;
      40             :                 uint32_t max_tcons;
      41             :                 uint32_t num_tcons;
      42             :         } local;
      43             :         struct {
      44             :                 struct db_context *db_ctx;
      45             :         } global;
      46             : };
      47             : 
      48             : static struct db_context *smbXsrv_tcon_global_db_ctx = NULL;
      49             : 
      50       31154 : NTSTATUS smbXsrv_tcon_global_init(void)
      51             : {
      52       31154 :         char *global_path = NULL;
      53       31154 :         struct db_context *db_ctx = NULL;
      54             : 
      55       31154 :         if (smbXsrv_tcon_global_db_ctx != NULL) {
      56       31123 :                 return NT_STATUS_OK;
      57             :         }
      58             : 
      59          31 :         global_path = lock_path(talloc_tos(), "smbXsrv_tcon_global.tdb");
      60          31 :         if (global_path == NULL) {
      61           0 :                 return NT_STATUS_NO_MEMORY;
      62             :         }
      63             : 
      64          31 :         db_ctx = db_open(NULL, global_path,
      65             :                          SMBD_VOLATILE_TDB_HASH_SIZE,
      66             :                          SMBD_VOLATILE_TDB_FLAGS,
      67             :                          O_RDWR | O_CREAT, 0600,
      68             :                          DBWRAP_LOCK_ORDER_1,
      69             :                          DBWRAP_FLAG_NONE);
      70          31 :         TALLOC_FREE(global_path);
      71          31 :         if (db_ctx == NULL) {
      72           0 :                 NTSTATUS status;
      73             : 
      74           0 :                 status = map_nt_error_from_unix_common(errno);
      75             : 
      76           0 :                 return status;
      77             :         }
      78             : 
      79          31 :         smbXsrv_tcon_global_db_ctx = db_ctx;
      80             : 
      81          31 :         return NT_STATUS_OK;
      82             : }
      83             : 
      84             : /*
      85             :  * NOTE:
      86             :  * We need to store the keys in big endian so that dbwrap_rbt's memcmp
      87             :  * has the same result as integer comparison between the uint32_t
      88             :  * values.
      89             :  *
      90             :  * TODO: implement string based key
      91             :  */
      92             : 
      93             : #define SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE sizeof(uint32_t)
      94             : 
      95      143309 : static TDB_DATA smbXsrv_tcon_global_id_to_key(uint32_t id,
      96             :                                               uint8_t *key_buf)
      97             : {
      98        2159 :         TDB_DATA key;
      99             : 
     100      143309 :         RSIVAL(key_buf, 0, id);
     101             : 
     102      143309 :         key = make_tdb_data(key_buf, SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE);
     103             : 
     104      143309 :         return key;
     105             : }
     106             : 
     107             : #if 0
     108             : static NTSTATUS smbXsrv_tcon_global_key_to_id(TDB_DATA key, uint32_t *id)
     109             : {
     110             :         if (id == NULL) {
     111             :                 return NT_STATUS_INVALID_PARAMETER;
     112             :         }
     113             : 
     114             :         if (key.dsize != SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE) {
     115             :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     116             :         }
     117             : 
     118             :         *id = RIVAL(key.dptr, 0);
     119             : 
     120             :         return NT_STATUS_OK;
     121             : }
     122             : #endif
     123             : 
     124             : #define SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE sizeof(uint32_t)
     125             : 
     126     2056517 : static TDB_DATA smbXsrv_tcon_local_id_to_key(uint32_t id,
     127             :                                              uint8_t *key_buf)
     128             : {
     129       16867 :         TDB_DATA key;
     130             : 
     131     2056517 :         RSIVAL(key_buf, 0, id);
     132             : 
     133     2056517 :         key = make_tdb_data(key_buf, SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE);
     134             : 
     135     2056517 :         return key;
     136             : }
     137             : 
     138           0 : static NTSTATUS smbXsrv_tcon_local_key_to_id(TDB_DATA key, uint32_t *id)
     139             : {
     140           0 :         if (id == NULL) {
     141           0 :                 return NT_STATUS_INVALID_PARAMETER;
     142             :         }
     143             : 
     144           0 :         if (key.dsize != SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE) {
     145           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     146             :         }
     147             : 
     148           0 :         *id = RIVAL(key.dptr, 0);
     149             : 
     150           0 :         return NT_STATUS_OK;
     151             : }
     152             : 
     153      143309 : static struct db_record *smbXsrv_tcon_global_fetch_locked(
     154             :                         struct db_context *db,
     155             :                         uint32_t id,
     156             :                         TALLOC_CTX *mem_ctx)
     157             : {
     158        2159 :         TDB_DATA key;
     159        2159 :         uint8_t key_buf[SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE];
     160      143309 :         struct db_record *rec = NULL;
     161             : 
     162      143309 :         key = smbXsrv_tcon_global_id_to_key(id, key_buf);
     163             : 
     164      143309 :         rec = dbwrap_fetch_locked(db, mem_ctx, key);
     165             : 
     166      143309 :         if (rec == NULL) {
     167           0 :                 DBG_DEBUG("Failed to lock global id 0x%08x, key '%s'\n", id,
     168             :                           tdb_data_dbg(key));
     169             :         }
     170             : 
     171      143309 :         return rec;
     172             : }
     173             : 
     174       80554 : static struct db_record *smbXsrv_tcon_local_fetch_locked(
     175             :                         struct db_context *db,
     176             :                         uint32_t id,
     177             :                         TALLOC_CTX *mem_ctx)
     178             : {
     179         787 :         TDB_DATA key;
     180         787 :         uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
     181       80554 :         struct db_record *rec = NULL;
     182             : 
     183       80554 :         key = smbXsrv_tcon_local_id_to_key(id, key_buf);
     184             : 
     185       80554 :         rec = dbwrap_fetch_locked(db, mem_ctx, key);
     186             : 
     187       80554 :         if (rec == NULL) {
     188           0 :                 DBG_DEBUG("Failed to lock local id 0x%08x, key '%s'\n", id,
     189             :                           tdb_data_dbg(key));
     190             :         }
     191             : 
     192       80554 :         return rec;
     193             : }
     194             : 
     195       31085 : static NTSTATUS smbXsrv_tcon_table_init(TALLOC_CTX *mem_ctx,
     196             :                                         struct smbXsrv_tcon_table *table,
     197             :                                         uint32_t lowest_id,
     198             :                                         uint32_t highest_id,
     199             :                                         uint32_t max_tcons)
     200             : {
     201         760 :         NTSTATUS status;
     202         760 :         uint64_t max_range;
     203             : 
     204       31085 :         if (lowest_id > highest_id) {
     205           0 :                 return NT_STATUS_INTERNAL_ERROR;
     206             :         }
     207             : 
     208       31085 :         max_range = highest_id;
     209       31085 :         max_range -= lowest_id;
     210       31085 :         max_range += 1;
     211             : 
     212       31085 :         if (max_tcons > max_range) {
     213           0 :                 return NT_STATUS_INTERNAL_ERROR;
     214             :         }
     215             : 
     216       31085 :         ZERO_STRUCTP(table);
     217       31085 :         table->local.db_ctx = db_open_rbt(table);
     218       31085 :         if (table->local.db_ctx == NULL) {
     219           0 :                 return NT_STATUS_NO_MEMORY;
     220             :         }
     221       31085 :         table->local.lowest_id = lowest_id;
     222       31085 :         table->local.highest_id = highest_id;
     223       31085 :         table->local.max_tcons = max_tcons;
     224             : 
     225       31085 :         status = smbXsrv_tcon_global_init();
     226       31085 :         if (!NT_STATUS_IS_OK(status)) {
     227           0 :                 return status;
     228             :         }
     229             : 
     230       31085 :         table->global.db_ctx = smbXsrv_tcon_global_db_ctx;
     231             : 
     232       31085 :         return NT_STATUS_OK;
     233             : }
     234             : 
     235             : struct smb1srv_tcon_local_allocate_state {
     236             :         const uint32_t lowest_id;
     237             :         const uint32_t highest_id;
     238             :         uint32_t last_id;
     239             :         uint32_t useable_id;
     240             :         NTSTATUS status;
     241             : };
     242             : 
     243           0 : static int smb1srv_tcon_local_allocate_traverse(struct db_record *rec,
     244             :                                                    void *private_data)
     245             : {
     246           0 :         struct smb1srv_tcon_local_allocate_state *state =
     247             :                 (struct smb1srv_tcon_local_allocate_state *)private_data;
     248           0 :         TDB_DATA key = dbwrap_record_get_key(rec);
     249           0 :         uint32_t id = 0;
     250           0 :         NTSTATUS status;
     251             : 
     252           0 :         status = smbXsrv_tcon_local_key_to_id(key, &id);
     253           0 :         if (!NT_STATUS_IS_OK(status)) {
     254           0 :                 state->status = status;
     255           0 :                 return -1;
     256             :         }
     257             : 
     258           0 :         if (id <= state->last_id) {
     259           0 :                 state->status = NT_STATUS_INTERNAL_DB_CORRUPTION;
     260           0 :                 return -1;
     261             :         }
     262           0 :         state->last_id = id;
     263             : 
     264           0 :         if (id > state->useable_id) {
     265           0 :                 state->status = NT_STATUS_OK;
     266           0 :                 return -1;
     267             :         }
     268             : 
     269           0 :         if (state->useable_id == state->highest_id) {
     270           0 :                 state->status = NT_STATUS_INSUFFICIENT_RESOURCES;
     271           0 :                 return -1;
     272             :         }
     273             : 
     274           0 :         state->useable_id +=1;
     275           0 :         return 0;
     276             : }
     277             : 
     278        8996 : static NTSTATUS smb1srv_tcon_local_allocate_id(struct db_context *db,
     279             :                                                uint32_t lowest_id,
     280             :                                                uint32_t highest_id,
     281             :                                                TALLOC_CTX *mem_ctx,
     282             :                                                struct db_record **_rec,
     283             :                                                uint32_t *_id)
     284             : {
     285        8996 :         struct smb1srv_tcon_local_allocate_state state = {
     286             :                 .lowest_id = lowest_id,
     287             :                 .highest_id = highest_id,
     288             :                 .last_id = 0,
     289             :                 .useable_id = lowest_id,
     290             :                 .status = NT_STATUS_INTERNAL_ERROR,
     291             :         };
     292         144 :         uint32_t i;
     293         144 :         uint32_t range;
     294         144 :         NTSTATUS status;
     295        8996 :         int count = 0;
     296             : 
     297        8996 :         *_rec = NULL;
     298        8996 :         *_id = 0;
     299             : 
     300        8996 :         if (lowest_id > highest_id) {
     301           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     302             :         }
     303             : 
     304             :         /*
     305             :          * first we try randomly
     306             :          */
     307        8996 :         range = (highest_id - lowest_id) + 1;
     308             : 
     309        8996 :         for (i = 0; i < (range / 2); i++) {
     310         144 :                 uint32_t id;
     311         144 :                 TDB_DATA val;
     312        8996 :                 struct db_record *rec = NULL;
     313             : 
     314        8996 :                 id = generate_random() % range;
     315        8996 :                 id += lowest_id;
     316             : 
     317        8996 :                 if (id < lowest_id) {
     318           0 :                         id = lowest_id;
     319             :                 }
     320        8996 :                 if (id > highest_id) {
     321           0 :                         id = highest_id;
     322             :                 }
     323             : 
     324        8996 :                 rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx);
     325        8996 :                 if (rec == NULL) {
     326           0 :                         return NT_STATUS_INSUFFICIENT_RESOURCES;
     327             :                 }
     328             : 
     329        8996 :                 val = dbwrap_record_get_value(rec);
     330        8996 :                 if (val.dsize != 0) {
     331           0 :                         TALLOC_FREE(rec);
     332           0 :                         continue;
     333             :                 }
     334             : 
     335        8996 :                 *_rec = rec;
     336        8996 :                 *_id = id;
     337        8996 :                 return NT_STATUS_OK;
     338             :         }
     339             : 
     340             :         /*
     341             :          * if the range is almost full,
     342             :          * we traverse the whole table
     343             :          * (this relies on sorted behavior of dbwrap_rbt)
     344             :          */
     345           0 :         status = dbwrap_traverse_read(db, smb1srv_tcon_local_allocate_traverse,
     346             :                                       &state, &count);
     347           0 :         if (NT_STATUS_IS_OK(status)) {
     348           0 :                 if (NT_STATUS_IS_OK(state.status)) {
     349           0 :                         return NT_STATUS_INTERNAL_ERROR;
     350             :                 }
     351             : 
     352           0 :                 if (!NT_STATUS_EQUAL(state.status, NT_STATUS_INTERNAL_ERROR)) {
     353           0 :                         return state.status;
     354             :                 }
     355             : 
     356           0 :                 if (state.useable_id <= state.highest_id) {
     357           0 :                         state.status = NT_STATUS_OK;
     358             :                 } else {
     359           0 :                         return NT_STATUS_INSUFFICIENT_RESOURCES;
     360             :                 }
     361           0 :         } else if (!NT_STATUS_EQUAL(status, NT_STATUS_INTERNAL_DB_CORRUPTION)) {
     362             :                 /*
     363             :                  * Here we really expect NT_STATUS_INTERNAL_DB_CORRUPTION!
     364             :                  *
     365             :                  * If we get anything else it is an error, because it
     366             :                  * means we did not manage to find a free slot in
     367             :                  * the db.
     368             :                  */
     369           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     370             :         }
     371             : 
     372           0 :         if (NT_STATUS_IS_OK(state.status)) {
     373           0 :                 uint32_t id;
     374           0 :                 TDB_DATA val;
     375           0 :                 struct db_record *rec = NULL;
     376             : 
     377           0 :                 id = state.useable_id;
     378             : 
     379           0 :                 rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx);
     380           0 :                 if (rec == NULL) {
     381           0 :                         return NT_STATUS_INSUFFICIENT_RESOURCES;
     382             :                 }
     383             : 
     384           0 :                 val = dbwrap_record_get_value(rec);
     385           0 :                 if (val.dsize != 0) {
     386           0 :                         TALLOC_FREE(rec);
     387           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     388             :                 }
     389             : 
     390           0 :                 *_rec = rec;
     391           0 :                 *_id = id;
     392           0 :                 return NT_STATUS_OK;
     393             :         }
     394             : 
     395           0 :         return state.status;
     396             : }
     397             : 
     398             : struct smbXsrv_tcon_local_fetch_state {
     399             :         struct smbXsrv_tcon *tcon;
     400             :         NTSTATUS status;
     401             : };
     402             : 
     403     1968947 : static void smbXsrv_tcon_local_fetch_parser(TDB_DATA key, TDB_DATA data,
     404             :                                             void *private_data)
     405             : {
     406     1968947 :         struct smbXsrv_tcon_local_fetch_state *state =
     407             :                 (struct smbXsrv_tcon_local_fetch_state *)private_data;
     408       16079 :         void *ptr;
     409             : 
     410     1968947 :         if (data.dsize != sizeof(ptr)) {
     411           0 :                 state->status = NT_STATUS_INTERNAL_DB_ERROR;
     412           0 :                 return;
     413             :         }
     414             : 
     415     1968947 :         memcpy(&ptr, data.dptr, data.dsize);
     416     1968947 :         state->tcon = talloc_get_type_abort(ptr, struct smbXsrv_tcon);
     417     1968947 :         state->status = NT_STATUS_OK;
     418             : }
     419             : 
     420     2015589 : static NTSTATUS smbXsrv_tcon_local_lookup(struct smbXsrv_tcon_table *table,
     421             :                                           uint32_t tcon_local_id,
     422             :                                           NTTIME now,
     423             :                                           struct smbXsrv_tcon **_tcon)
     424             : {
     425     2015589 :         struct smbXsrv_tcon_local_fetch_state state = {
     426             :                 .tcon = NULL,
     427             :                 .status = NT_STATUS_INTERNAL_ERROR,
     428             :         };
     429       17017 :         uint8_t key_buf[SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE];
     430       17017 :         TDB_DATA key;
     431       17017 :         NTSTATUS status;
     432             : 
     433     2015589 :         *_tcon = NULL;
     434             : 
     435     2015589 :         if (tcon_local_id == 0) {
     436       39624 :                 return NT_STATUS_NETWORK_NAME_DELETED;
     437             :         }
     438             : 
     439     1975965 :         if (table == NULL) {
     440             :                 /* this might happen before the end of negprot */
     441           2 :                 return NT_STATUS_NETWORK_NAME_DELETED;
     442             :         }
     443             : 
     444     1975963 :         if (table->local.db_ctx == NULL) {
     445           0 :                 return NT_STATUS_INTERNAL_ERROR;
     446             :         }
     447             : 
     448     1975963 :         key = smbXsrv_tcon_local_id_to_key(tcon_local_id, key_buf);
     449             : 
     450     1975963 :         status = dbwrap_parse_record(table->local.db_ctx, key,
     451             :                                      smbXsrv_tcon_local_fetch_parser,
     452             :                                      &state);
     453     1975963 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     454        7016 :                 return NT_STATUS_NETWORK_NAME_DELETED;
     455     1968947 :         } else if (!NT_STATUS_IS_OK(status)) {
     456           0 :                 return status;
     457             :         }
     458     1968947 :         if (!NT_STATUS_IS_OK(state.status)) {
     459           0 :                 return state.status;
     460             :         }
     461             : 
     462     1968947 :         if (NT_STATUS_EQUAL(state.tcon->status, NT_STATUS_NETWORK_NAME_DELETED)) {
     463           2 :                 return NT_STATUS_NETWORK_NAME_DELETED;
     464             :         }
     465             : 
     466     1968945 :         state.tcon->idle_time = now;
     467             : 
     468     1968945 :         *_tcon = state.tcon;
     469     1968945 :         return state.tcon->status;
     470             : }
     471             : 
     472       48115 : static int smbXsrv_tcon_global_destructor(struct smbXsrv_tcon_global0 *global)
     473             : {
     474       48115 :         return 0;
     475             : }
     476             : 
     477             : static void smbXsrv_tcon_global_verify_record(struct db_record *db_rec,
     478             :                                         bool *is_free,
     479             :                                         bool *was_free,
     480             :                                         TALLOC_CTX *mem_ctx,
     481             :                                         struct smbXsrv_tcon_global0 **_g);
     482             : 
     483       48129 : static NTSTATUS smbXsrv_tcon_global_allocate(struct db_context *db,
     484             :                                         TALLOC_CTX *mem_ctx,
     485             :                                         struct smbXsrv_tcon_global0 **_global)
     486             : {
     487         765 :         uint32_t i;
     488       48129 :         struct smbXsrv_tcon_global0 *global = NULL;
     489       48129 :         uint32_t last_free = 0;
     490       48129 :         const uint32_t min_tries = 3;
     491             : 
     492       48129 :         *_global = NULL;
     493             : 
     494       48129 :         global = talloc_zero(mem_ctx, struct smbXsrv_tcon_global0);
     495       48129 :         if (global == NULL) {
     496           0 :                 return NT_STATUS_NO_MEMORY;
     497             :         }
     498       48129 :         talloc_set_destructor(global, smbXsrv_tcon_global_destructor);
     499             : 
     500             :         /*
     501             :          * Here we just randomly try the whole 32-bit space
     502             :          *
     503             :          * We use just 32-bit, because we want to reuse the
     504             :          * ID for SRVSVC.
     505             :          */
     506       48894 :         for (i = 0; i < UINT32_MAX; i++) {
     507       48129 :                 bool is_free = false;
     508       48129 :                 bool was_free = false;
     509         765 :                 uint32_t id;
     510             : 
     511       48129 :                 if (i >= min_tries && last_free != 0) {
     512           0 :                         id = last_free;
     513             :                 } else {
     514       48129 :                         id = generate_random();
     515             :                 }
     516       48129 :                 if (id == 0) {
     517           0 :                         id++;
     518             :                 }
     519       48129 :                 if (id == UINT32_MAX) {
     520           0 :                         id--;
     521             :                 }
     522             : 
     523       48129 :                 global->db_rec = smbXsrv_tcon_global_fetch_locked(db, id,
     524             :                                                                   mem_ctx);
     525       48129 :                 if (global->db_rec == NULL) {
     526           0 :                         talloc_free(global);
     527           0 :                         return NT_STATUS_INSUFFICIENT_RESOURCES;
     528             :                 }
     529             : 
     530       48129 :                 smbXsrv_tcon_global_verify_record(global->db_rec,
     531             :                                                   &is_free,
     532             :                                                   &was_free,
     533             :                                                   NULL, NULL);
     534             : 
     535       48129 :                 if (!is_free) {
     536           0 :                         TALLOC_FREE(global->db_rec);
     537           0 :                         continue;
     538             :                 }
     539             : 
     540       48129 :                 if (!was_free && i < min_tries) {
     541             :                         /*
     542             :                          * The session_id is free now,
     543             :                          * but was not free before.
     544             :                          *
     545             :                          * This happens if a smbd crashed
     546             :                          * and did not cleanup the record.
     547             :                          *
     548             :                          * If this is one of our first tries,
     549             :                          * then we try to find a real free one.
     550             :                          */
     551           0 :                         if (last_free == 0) {
     552           0 :                                 last_free = id;
     553             :                         }
     554           0 :                         TALLOC_FREE(global->db_rec);
     555           0 :                         continue;
     556             :                 }
     557             : 
     558       48129 :                 global->tcon_global_id = id;
     559             : 
     560       48129 :                 *_global = global;
     561       48129 :                 return NT_STATUS_OK;
     562             :         }
     563             : 
     564             :         /* should not be reached */
     565           0 :         talloc_free(global);
     566           0 :         return NT_STATUS_INTERNAL_ERROR;
     567             : }
     568             : 
     569       48129 : static void smbXsrv_tcon_global_verify_record(struct db_record *db_rec,
     570             :                                         bool *is_free,
     571             :                                         bool *was_free,
     572             :                                         TALLOC_CTX *mem_ctx,
     573             :                                         struct smbXsrv_tcon_global0 **_g)
     574             : {
     575         765 :         TDB_DATA key;
     576         765 :         TDB_DATA val;
     577         765 :         DATA_BLOB blob;
     578         765 :         struct smbXsrv_tcon_globalB global_blob;
     579         765 :         enum ndr_err_code ndr_err;
     580       48129 :         struct smbXsrv_tcon_global0 *global = NULL;
     581         765 :         bool exists;
     582       48129 :         TALLOC_CTX *frame = talloc_stackframe();
     583             : 
     584       48129 :         *is_free = false;
     585             : 
     586       48129 :         if (was_free) {
     587       48129 :                 *was_free = false;
     588             :         }
     589       48129 :         if (_g) {
     590           0 :                 *_g = NULL;
     591             :         }
     592             : 
     593       48129 :         key = dbwrap_record_get_key(db_rec);
     594             : 
     595       48129 :         val = dbwrap_record_get_value(db_rec);
     596       48129 :         if (val.dsize == 0) {
     597       48129 :                 TALLOC_FREE(frame);
     598       48129 :                 *is_free = true;
     599       48129 :                 if (was_free) {
     600       48129 :                         *was_free = true;
     601             :                 }
     602       48129 :                 return;
     603             :         }
     604             : 
     605           0 :         blob = data_blob_const(val.dptr, val.dsize);
     606             : 
     607           0 :         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
     608             :                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_tcon_globalB);
     609           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     610           0 :                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
     611           0 :                 DBG_WARNING("key '%s' ndr_pull_struct_blob - %s\n",
     612             :                             tdb_data_dbg(key),
     613             :                             nt_errstr(status));
     614           0 :                 TALLOC_FREE(frame);
     615           0 :                 return;
     616             :         }
     617             : 
     618           0 :         DBG_DEBUG("smbXsrv_tcon_global_verify_record\n");
     619           0 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
     620           0 :                 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
     621             :         }
     622             : 
     623           0 :         if (global_blob.version != SMBXSRV_VERSION_0) {
     624           0 :                 DBG_ERR("key '%s' uses unsupported version %u\n",
     625             :                         tdb_data_dbg(key),
     626             :                         global_blob.version);
     627           0 :                 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
     628           0 :                 TALLOC_FREE(frame);
     629           0 :                 return;
     630             :         }
     631             : 
     632           0 :         global = global_blob.info.info0;
     633             : 
     634           0 :         exists = serverid_exists(&global->server_id);
     635           0 :         if (!exists) {
     636           0 :                 struct server_id_buf idbuf;
     637           0 :                 DBG_NOTICE("key '%s' server_id %s does not exist.\n",
     638             :                            tdb_data_dbg(key),
     639             :                            server_id_str_buf(global->server_id, &idbuf));
     640           0 :                 if (DEBUGLVL(DBGLVL_NOTICE)) {
     641           0 :                         NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
     642             :                 }
     643           0 :                 TALLOC_FREE(frame);
     644           0 :                 dbwrap_record_delete(db_rec);
     645           0 :                 *is_free = true;
     646           0 :                 return;
     647             :         }
     648             : 
     649           0 :         if (_g) {
     650           0 :                 *_g = talloc_move(mem_ctx, &global);
     651             :         }
     652           0 :         TALLOC_FREE(frame);
     653             : }
     654             : 
     655       95246 : static NTSTATUS smbXsrv_tcon_global_store(struct smbXsrv_tcon_global0 *global)
     656             : {
     657        1394 :         struct smbXsrv_tcon_globalB global_blob;
     658       95246 :         DATA_BLOB blob = data_blob_null;
     659        1394 :         TDB_DATA key;
     660        1394 :         TDB_DATA val;
     661        1394 :         NTSTATUS status;
     662        1394 :         enum ndr_err_code ndr_err;
     663             : 
     664             :         /*
     665             :          * TODO: if we use other versions than '0'
     666             :          * we would add glue code here, that would be able to
     667             :          * store the information in the old format.
     668             :          */
     669             : 
     670       95246 :         if (global->db_rec == NULL) {
     671           0 :                 return NT_STATUS_INTERNAL_ERROR;
     672             :         }
     673             : 
     674       95246 :         key = dbwrap_record_get_key(global->db_rec);
     675       95246 :         val = dbwrap_record_get_value(global->db_rec);
     676             : 
     677       95246 :         ZERO_STRUCT(global_blob);
     678       95246 :         global_blob.version = smbXsrv_version_global_current();
     679       95246 :         if (val.dsize >= 8) {
     680       47117 :                 global_blob.seqnum = IVAL(val.dptr, 4);
     681             :         }
     682       95246 :         global_blob.seqnum += 1;
     683       95246 :         global_blob.info.info0 = global;
     684             : 
     685       95246 :         ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
     686             :                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_tcon_globalB);
     687       95246 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     688           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     689           0 :                 DBG_WARNING("key '%s' ndr_push - %s\n",
     690             :                             tdb_data_dbg(key),
     691             :                             nt_errstr(status));
     692           0 :                 TALLOC_FREE(global->db_rec);
     693           0 :                 return status;
     694             :         }
     695             : 
     696       95246 :         val = make_tdb_data(blob.data, blob.length);
     697       95246 :         status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
     698       95246 :         if (!NT_STATUS_IS_OK(status)) {
     699           0 :                 DBG_WARNING("key '%s' store - %s\n",
     700             :                             tdb_data_dbg(key),
     701             :                             nt_errstr(status));
     702           0 :                 TALLOC_FREE(global->db_rec);
     703           0 :                 return status;
     704             :         }
     705             : 
     706       95246 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
     707           0 :                 DBG_DEBUG("key '%s' stored\n", tdb_data_dbg(key));
     708           0 :                 NDR_PRINT_DEBUG(smbXsrv_tcon_globalB, &global_blob);
     709             :         }
     710             : 
     711       95246 :         TALLOC_FREE(global->db_rec);
     712             : 
     713       95246 :         return NT_STATUS_OK;
     714             : }
     715             : 
     716       48115 : static int smbXsrv_tcon_destructor(struct smbXsrv_tcon *tcon)
     717             : {
     718         765 :         NTSTATUS status;
     719             : 
     720       48115 :         status = smbXsrv_tcon_disconnect(tcon, 0);
     721       48115 :         if (!NT_STATUS_IS_OK(status)) {
     722           0 :                 DBG_ERR("smbXsrv_tcon_disconnect() failed - %s\n",
     723             :                         nt_errstr(status));
     724             :         }
     725             : 
     726       48115 :         TALLOC_FREE(tcon->global);
     727             : 
     728       48115 :         return 0;
     729             : }
     730             : 
     731       48129 : static NTSTATUS smbXsrv_tcon_create(struct smbXsrv_tcon_table *table,
     732             :                                     enum protocol_types protocol,
     733             :                                     struct server_id server_id,
     734             :                                     NTTIME now,
     735             :                                     uint32_t session_global_id,
     736             :                                     uint8_t encryption_flags,
     737             :                                     const char *share_name,
     738             :                                     struct smbXsrv_tcon **_tcon)
     739             : {
     740       48129 :         struct db_record *local_rec = NULL;
     741       48129 :         struct smbXsrv_tcon *tcon = NULL;
     742       48129 :         void *ptr = NULL;
     743         765 :         TDB_DATA val;
     744       48129 :         struct smbXsrv_tcon_global0 *global = NULL;
     745         765 :         NTSTATUS status;
     746             : 
     747       48129 :         if (table->local.num_tcons >= table->local.max_tcons) {
     748           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     749             :         }
     750             : 
     751       48129 :         tcon = talloc_zero(table, struct smbXsrv_tcon);
     752       48129 :         if (tcon == NULL) {
     753           0 :                 return NT_STATUS_NO_MEMORY;
     754             :         }
     755       48129 :         tcon->table = table;
     756       48129 :         tcon->status = NT_STATUS_INTERNAL_ERROR;
     757       48129 :         tcon->idle_time = now;
     758             : 
     759       48129 :         status = smbXsrv_tcon_global_allocate(table->global.db_ctx,
     760             :                                               tcon, &global);
     761       48129 :         if (!NT_STATUS_IS_OK(status)) {
     762           0 :                 TALLOC_FREE(tcon);
     763           0 :                 return status;
     764             :         }
     765       48129 :         tcon->global = global;
     766             : 
     767       48129 :         global->session_global_id = session_global_id;
     768       48129 :         global->encryption_flags = encryption_flags;
     769       48129 :         global->share_name = talloc_strdup(global, share_name);
     770       48129 :         if (global->share_name == NULL) {
     771           0 :                 TALLOC_FREE(tcon);
     772           0 :                 return NT_STATUS_NO_MEMORY;
     773             :         }
     774             : 
     775       48129 :         if (protocol >= PROTOCOL_SMB2_02) {
     776       39133 :                 uint64_t id = global->tcon_global_id;
     777             : 
     778       39133 :                 global->tcon_wire_id = id;
     779             : 
     780       39133 :                 tcon->local_id = global->tcon_global_id;
     781             : 
     782       39133 :                 local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx,
     783             :                                                         tcon->local_id,
     784             :                                                         tcon /* TALLOC_CTX */);
     785       39133 :                 if (local_rec == NULL) {
     786           0 :                         TALLOC_FREE(tcon);
     787           0 :                         return NT_STATUS_NO_MEMORY;
     788             :                 }
     789             : 
     790       39133 :                 val = dbwrap_record_get_value(local_rec);
     791       39133 :                 if (val.dsize != 0) {
     792           0 :                         TALLOC_FREE(tcon);
     793           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     794             :                 }
     795             :         } else {
     796             : 
     797        8996 :                 status = smb1srv_tcon_local_allocate_id(table->local.db_ctx,
     798             :                                                         table->local.lowest_id,
     799             :                                                         table->local.highest_id,
     800             :                                                         tcon,
     801             :                                                         &local_rec,
     802             :                                                         &tcon->local_id);
     803        8996 :                 if (!NT_STATUS_IS_OK(status)) {
     804           0 :                         TALLOC_FREE(tcon);
     805           0 :                         return status;
     806             :                 }
     807             : 
     808        8996 :                 global->tcon_wire_id = tcon->local_id;
     809             :         }
     810             : 
     811       48129 :         global->creation_time = now;
     812             : 
     813       48129 :         global->server_id = server_id;
     814             : 
     815       48129 :         ptr = tcon;
     816       48129 :         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
     817       48129 :         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
     818       48129 :         TALLOC_FREE(local_rec);
     819       48129 :         if (!NT_STATUS_IS_OK(status)) {
     820           0 :                 TALLOC_FREE(tcon);
     821           0 :                 return status;
     822             :         }
     823       48129 :         table->local.num_tcons += 1;
     824             : 
     825       48129 :         talloc_set_destructor(tcon, smbXsrv_tcon_destructor);
     826             : 
     827       48129 :         status = smbXsrv_tcon_global_store(global);
     828       48129 :         if (!NT_STATUS_IS_OK(status)) {
     829           0 :                 DBG_ERR("global_id (0x%08x) store failed - %s\n",
     830             :                         tcon->global->tcon_global_id,
     831             :                         nt_errstr(status));
     832           0 :                 TALLOC_FREE(tcon);
     833           0 :                 return status;
     834             :         }
     835             : 
     836       48129 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
     837           0 :                 struct smbXsrv_tconB tcon_blob = {
     838             :                         .version = SMBXSRV_VERSION_0,
     839             :                         .info.info0 = tcon,
     840             :                 };
     841             : 
     842           0 :                 DBG_DEBUG("global_id (0x%08x) stored\n",
     843             :                           tcon->global->tcon_global_id);
     844           0 :                 NDR_PRINT_DEBUG(smbXsrv_tconB, &tcon_blob);
     845             :         }
     846             : 
     847       48129 :         *_tcon = tcon;
     848       48129 :         return NT_STATUS_OK;
     849             : }
     850             : 
     851       47117 : NTSTATUS smbXsrv_tcon_update(struct smbXsrv_tcon *tcon)
     852             : {
     853       47117 :         struct smbXsrv_tcon_table *table = tcon->table;
     854         629 :         NTSTATUS status;
     855             : 
     856       47117 :         if (tcon->global->db_rec != NULL) {
     857           0 :                 DBG_ERR("update(0x%08x): "
     858             :                         "Called with db_rec != NULL'\n",
     859             :                         tcon->global->tcon_global_id);
     860           0 :                 return NT_STATUS_INTERNAL_ERROR;
     861             :         }
     862             : 
     863       93605 :         tcon->global->db_rec = smbXsrv_tcon_global_fetch_locked(
     864             :                                                 table->global.db_ctx,
     865       46488 :                                                 tcon->global->tcon_global_id,
     866       46488 :                                                 tcon->global /* TALLOC_CTX */);
     867       47117 :         if (tcon->global->db_rec == NULL) {
     868           0 :                 return NT_STATUS_INTERNAL_DB_ERROR;
     869             :         }
     870             : 
     871       47117 :         status = smbXsrv_tcon_global_store(tcon->global);
     872       47117 :         if (!NT_STATUS_IS_OK(status)) {
     873           0 :                 DBG_ERR("global_id (0x%08x) store failed - %s\n",
     874             :                         tcon->global->tcon_global_id,
     875             :                         nt_errstr(status));
     876           0 :                 return status;
     877             :         }
     878             : 
     879       47117 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
     880           0 :                 struct smbXsrv_tconB tcon_blob = {
     881             :                         .version = SMBXSRV_VERSION_0,
     882             :                         .info.info0 = tcon,
     883             :                 };
     884             : 
     885           0 :                 DBG_DEBUG("global_id (0x%08x) stored\n",
     886             :                           tcon->global->tcon_global_id);
     887           0 :                 NDR_PRINT_DEBUG(smbXsrv_tconB, &tcon_blob);
     888             :         }
     889             : 
     890       47117 :         return NT_STATUS_OK;
     891             : }
     892             : 
     893       96114 : NTSTATUS smbXsrv_tcon_disconnect(struct smbXsrv_tcon *tcon, uint64_t vuid)
     894             : {
     895        1524 :         struct smbXsrv_tcon_table *table;
     896       96114 :         struct db_record *local_rec = NULL;
     897       96114 :         struct db_record *global_rec = NULL;
     898        1524 :         NTSTATUS status;
     899       96114 :         NTSTATUS error = NT_STATUS_OK;
     900             : 
     901       96114 :         if (tcon->table == NULL) {
     902       47999 :                 return NT_STATUS_OK;
     903             :         }
     904             : 
     905       48115 :         table = tcon->table;
     906       48115 :         tcon->table = NULL;
     907             : 
     908       48115 :         if (tcon->compat) {
     909         759 :                 bool ok;
     910             : 
     911       47999 :                 ok = chdir_current_service(tcon->compat);
     912       47999 :                 if (!ok) {
     913          52 :                         status = NT_STATUS_INTERNAL_ERROR;
     914          52 :                         DBG_ERR("disconnect(0x%08x, '%s'): "
     915             :                                 "chdir_current_service() failed: %s\n",
     916             :                                 tcon->global->tcon_global_id,
     917             :                                 tcon->global->share_name,
     918             :                                 nt_errstr(status));
     919             :                         /*
     920             :                          * We must call close_cnum() on
     921             :                          * error, as the caller is going
     922             :                          * to free tcon and tcon->compat
     923             :                          * so we must ensure tcon->compat is
     924             :                          * removed from the linked list
     925             :                          * conn->sconn->connections.
     926             :                          */
     927          52 :                         close_cnum(tcon->compat, vuid, ERROR_CLOSE);
     928          52 :                         tcon->compat = NULL;
     929          52 :                         return status;
     930             :                 }
     931             : 
     932       47947 :                 close_cnum(tcon->compat, vuid, SHUTDOWN_CLOSE);
     933       47947 :                 tcon->compat = NULL;
     934             :         }
     935             : 
     936       48063 :         tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
     937             : 
     938       48063 :         global_rec = tcon->global->db_rec;
     939       48063 :         tcon->global->db_rec = NULL;
     940       48063 :         if (global_rec == NULL) {
     941       48063 :                 global_rec = smbXsrv_tcon_global_fetch_locked(
     942             :                                                 table->global.db_ctx,
     943       47298 :                                                 tcon->global->tcon_global_id,
     944       47298 :                                                 tcon->global /* TALLOC_CTX */);
     945       48063 :                 if (global_rec == NULL) {
     946           0 :                         error = NT_STATUS_INTERNAL_ERROR;
     947             :                 }
     948             :         }
     949             : 
     950       48063 :         if (global_rec != NULL) {
     951       48063 :                 status = dbwrap_record_delete(global_rec);
     952       48063 :                 if (!NT_STATUS_IS_OK(status)) {
     953           0 :                         TDB_DATA key = dbwrap_record_get_key(global_rec);
     954             : 
     955           0 :                         DBG_ERR("disconnect(0x%08x, '%s'): "
     956             :                                 "failed to delete global key '%s': %s\n",
     957             :                                 tcon->global->tcon_global_id,
     958             :                                 tcon->global->share_name,
     959             :                                 tdb_data_dbg(key),
     960             :                                 nt_errstr(status));
     961           0 :                         error = status;
     962             :                 }
     963             :         }
     964       48063 :         TALLOC_FREE(global_rec);
     965             : 
     966       48063 :         local_rec = tcon->db_rec;
     967       48063 :         if (local_rec == NULL) {
     968       32425 :                 local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx,
     969             :                                                         tcon->local_id,
     970             :                                                         tcon /* TALLOC_CTX */);
     971       32425 :                 if (local_rec == NULL) {
     972           0 :                         error = NT_STATUS_INTERNAL_ERROR;
     973             :                 }
     974             :         }
     975             : 
     976       48063 :         if (local_rec != NULL) {
     977       48063 :                 status = dbwrap_record_delete(local_rec);
     978       48063 :                 if (!NT_STATUS_IS_OK(status)) {
     979           0 :                         TDB_DATA key = dbwrap_record_get_key(local_rec);
     980             : 
     981           0 :                         DBG_ERR("disconnect(0x%08x, '%s'): "
     982             :                                 "failed to delete local key '%s': %s\n",
     983             :                                 tcon->global->tcon_global_id,
     984             :                                 tcon->global->share_name,
     985             :                                 tdb_data_dbg(key),
     986             :                                 nt_errstr(status));
     987           0 :                         error = status;
     988             :                 }
     989       48063 :                 table->local.num_tcons -= 1;
     990             :         }
     991       48063 :         if (tcon->db_rec == NULL) {
     992       32425 :                 TALLOC_FREE(local_rec);
     993             :         }
     994       48063 :         tcon->db_rec = NULL;
     995             : 
     996       48063 :         return error;
     997             : }
     998             : 
     999             : struct smbXsrv_tcon_disconnect_all_state {
    1000             :         uint64_t vuid;
    1001             :         NTSTATUS first_status;
    1002             :         int errors;
    1003             : };
    1004             : 
    1005             : static int smbXsrv_tcon_disconnect_all_callback(struct db_record *local_rec,
    1006             :                                                 void *private_data);
    1007             : 
    1008       56510 : static NTSTATUS smbXsrv_tcon_disconnect_all(struct smbXsrv_tcon_table *table,
    1009             :                                             uint64_t vuid)
    1010             : {
    1011       56510 :         struct smbXsrv_tcon_disconnect_all_state state = { .vuid = vuid };
    1012        1469 :         NTSTATUS status;
    1013       56510 :         int count = 0;
    1014             : 
    1015       56510 :         if (table == NULL) {
    1016       25439 :                 return NT_STATUS_OK;
    1017             :         }
    1018             : 
    1019       31071 :         status = dbwrap_traverse(table->local.db_ctx,
    1020             :                                  smbXsrv_tcon_disconnect_all_callback,
    1021             :                                  &state, &count);
    1022       31071 :         if (!NT_STATUS_IS_OK(status)) {
    1023           0 :                 DBG_ERR("dbwrap_traverse() failed: %s\n", nt_errstr(status));
    1024           0 :                 return status;
    1025             :         }
    1026             : 
    1027       31071 :         if (!NT_STATUS_IS_OK(state.first_status)) {
    1028          52 :                 DBG_ERR("count[%d] errors[%d] first[%s]\n",
    1029             :                         count,
    1030             :                         state.errors,
    1031             :                         nt_errstr(state.first_status));
    1032          52 :                 return state.first_status;
    1033             :         }
    1034             : 
    1035       31019 :         return NT_STATUS_OK;
    1036             : }
    1037             : 
    1038       15690 : static int smbXsrv_tcon_disconnect_all_callback(struct db_record *local_rec,
    1039             :                                                 void *private_data)
    1040             : {
    1041       15690 :         struct smbXsrv_tcon_disconnect_all_state *state =
    1042             :                 (struct smbXsrv_tcon_disconnect_all_state *)private_data;
    1043         743 :         TDB_DATA val;
    1044       15690 :         void *ptr = NULL;
    1045       15690 :         struct smbXsrv_tcon *tcon = NULL;
    1046         743 :         uint64_t vuid;
    1047         743 :         NTSTATUS status;
    1048             : 
    1049       15690 :         val = dbwrap_record_get_value(local_rec);
    1050       15690 :         if (val.dsize != sizeof(ptr)) {
    1051           0 :                 status = NT_STATUS_INTERNAL_ERROR;
    1052           0 :                 if (NT_STATUS_IS_OK(state->first_status)) {
    1053           0 :                         state->first_status = status;
    1054             :                 }
    1055           0 :                 state->errors++;
    1056           0 :                 return 0;
    1057             :         }
    1058             : 
    1059       15690 :         memcpy(&ptr, val.dptr, val.dsize);
    1060       15690 :         tcon = talloc_get_type_abort(ptr, struct smbXsrv_tcon);
    1061             : 
    1062       15690 :         vuid = state->vuid;
    1063       15690 :         if (vuid == 0 && tcon->compat) {
    1064        2116 :                 vuid = tcon->compat->vuid;
    1065             :         }
    1066             : 
    1067       15690 :         tcon->db_rec = local_rec;
    1068       15690 :         status = smbXsrv_tcon_disconnect(tcon, vuid);
    1069       15690 :         tcon->db_rec = NULL;
    1070       15690 :         if (!NT_STATUS_IS_OK(status)) {
    1071          52 :                 if (NT_STATUS_IS_OK(state->first_status)) {
    1072          52 :                         state->first_status = status;
    1073             :                 }
    1074          52 :                 state->errors++;
    1075          52 :                 return 0;
    1076             :         }
    1077             : 
    1078       14895 :         return 0;
    1079             : }
    1080             : 
    1081        5625 : NTSTATUS smb1srv_tcon_table_init(struct smbXsrv_connection *conn)
    1082             : {
    1083        5625 :         struct smbXsrv_client *client = conn->client;
    1084             : 
    1085             :         /*
    1086             :          * Allow a range from 1..65534 with 65534 values.
    1087             :          */
    1088        5625 :         client->tcon_table = talloc_zero(client, struct smbXsrv_tcon_table);
    1089        5625 :         if (client->tcon_table == NULL) {
    1090           0 :                 return NT_STATUS_NO_MEMORY;
    1091             :         }
    1092             : 
    1093        5625 :         return smbXsrv_tcon_table_init(client, client->tcon_table,
    1094             :                                        1, UINT16_MAX - 1,
    1095             :                                        UINT16_MAX - 1);
    1096             : }
    1097             : 
    1098        8996 : NTSTATUS smb1srv_tcon_create(struct smbXsrv_connection *conn,
    1099             :                              uint32_t session_global_id,
    1100             :                              const char *share_name,
    1101             :                              NTTIME now,
    1102             :                              struct smbXsrv_tcon **_tcon)
    1103             : {
    1104        8996 :         struct server_id id = messaging_server_id(conn->client->msg_ctx);
    1105        8996 :         const uint8_t encryption_flags = 0;
    1106             : 
    1107        8996 :         return smbXsrv_tcon_create(conn->client->tcon_table,
    1108             :                                    conn->protocol,
    1109             :                                    id, now,
    1110             :                                    session_global_id,
    1111             :                                    encryption_flags,
    1112             :                                    share_name,
    1113             :                                    _tcon);
    1114             : }
    1115             : 
    1116      671949 : NTSTATUS smb1srv_tcon_lookup(struct smbXsrv_connection *conn,
    1117             :                              uint16_t tree_id, NTTIME now,
    1118             :                              struct smbXsrv_tcon **tcon)
    1119             : {
    1120      671949 :         uint32_t local_id = tree_id;
    1121             : 
    1122      671949 :         return smbXsrv_tcon_local_lookup(conn->client->tcon_table,
    1123             :                                          local_id, now, tcon);
    1124             : }
    1125             : 
    1126       31052 : NTSTATUS smb1srv_tcon_disconnect_all(struct smbXsrv_client *client)
    1127             : {
    1128             : 
    1129             :         /*
    1130             :          * We do not pass a vuid here,
    1131             :          * which means the vuid is taken from
    1132             :          * the tcon->compat->vuid.
    1133             :          *
    1134             :          * NOTE: that tcon->compat->vuid may point to
    1135             :          * a none existing vuid (or the wrong one)
    1136             :          * as the tcon can exist without a session
    1137             :          * in SMB1.
    1138             :          *
    1139             :          * This matches the old behavior of
    1140             :          * conn_close_all(), but we should think
    1141             :          * about how to fix this in future.
    1142             :          */
    1143       31052 :         return smbXsrv_tcon_disconnect_all(client->tcon_table, 0);
    1144             : }
    1145             : 
    1146       25460 : NTSTATUS smb2srv_tcon_table_init(struct smbXsrv_session *session)
    1147             : {
    1148             :         /*
    1149             :          * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
    1150             :          */
    1151       25460 :         session->tcon_table = talloc_zero(session, struct smbXsrv_tcon_table);
    1152       25460 :         if (session->tcon_table == NULL) {
    1153           0 :                 return NT_STATUS_NO_MEMORY;
    1154             :         }
    1155             : 
    1156       25460 :         return smbXsrv_tcon_table_init(session, session->tcon_table,
    1157             :                                        1, UINT32_MAX - 1,
    1158             :                                        UINT16_MAX - 1);
    1159             : }
    1160             : 
    1161       39133 : NTSTATUS smb2srv_tcon_create(struct smbXsrv_session *session,
    1162             :                              uint32_t session_global_id,
    1163             :                              uint8_t encryption_flags,
    1164             :                              const char *share_name,
    1165             :                              NTTIME now,
    1166             :                              struct smbXsrv_tcon **_tcon)
    1167             : {
    1168       39133 :         struct server_id id = messaging_server_id(session->client->msg_ctx);
    1169             : 
    1170       39133 :         return smbXsrv_tcon_create(session->tcon_table,
    1171             :                                    PROTOCOL_SMB2_02,
    1172             :                                    id, now,
    1173             :                                    session_global_id,
    1174             :                                    encryption_flags,
    1175             :                                    share_name,
    1176             :                                    _tcon);
    1177             : }
    1178             : 
    1179     1343640 : NTSTATUS smb2srv_tcon_lookup(struct smbXsrv_session *session,
    1180             :                              uint32_t tree_id, NTTIME now,
    1181             :                              struct smbXsrv_tcon **tcon)
    1182             : {
    1183     1343640 :         uint32_t local_id = tree_id;
    1184             : 
    1185     1343640 :         return smbXsrv_tcon_local_lookup(session->tcon_table,
    1186             :                                          local_id, now, tcon);
    1187             : }
    1188             : 
    1189       25458 : NTSTATUS smb2srv_tcon_disconnect_all(struct smbXsrv_session *session)
    1190             : {
    1191       25458 :         uint64_t vuid = session->global->session_wire_id;
    1192             : 
    1193       25458 :         return smbXsrv_tcon_disconnect_all(session->tcon_table, vuid);
    1194             : }
    1195             : 
    1196             : struct smbXsrv_tcon_global_traverse_state {
    1197             :         int (*fn)(struct smbXsrv_tcon_global0 *, void *);
    1198             :         void *private_data;
    1199             : };
    1200             : 
    1201         189 : static int smbXsrv_tcon_global_traverse_fn(struct db_record *rec, void *data)
    1202             : {
    1203         189 :         int ret = -1;
    1204         189 :         struct smbXsrv_tcon_global_traverse_state *state =
    1205             :                 (struct smbXsrv_tcon_global_traverse_state*)data;
    1206         189 :         TDB_DATA key = dbwrap_record_get_key(rec);
    1207         189 :         TDB_DATA val = dbwrap_record_get_value(rec);
    1208         189 :         DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
    1209           0 :         struct smbXsrv_tcon_globalB global_blob;
    1210           0 :         enum ndr_err_code ndr_err;
    1211         189 :         TALLOC_CTX *frame = talloc_stackframe();
    1212             : 
    1213         189 :         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
    1214             :                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_tcon_globalB);
    1215         189 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1216           0 :                 DBG_WARNING("Invalid record in smbXsrv_tcon_global.tdb:"
    1217             :                          "key '%s' ndr_pull_struct_blob - %s\n",
    1218             :                          tdb_data_dbg(key),
    1219             :                          ndr_errstr(ndr_err));
    1220           0 :                 goto done;
    1221             :         }
    1222             : 
    1223         189 :         if (global_blob.version != SMBXSRV_VERSION_0) {
    1224           0 :                 DBG_WARNING("Invalid record in smbXsrv_tcon_global.tdb:"
    1225             :                          "key '%s' unsupported version - %d\n",
    1226             :                          tdb_data_dbg(key),
    1227             :                          (int)global_blob.version);
    1228           0 :                 goto done;
    1229             :         }
    1230             : 
    1231         189 :         if (global_blob.info.info0 == NULL) {
    1232           0 :                 DBG_WARNING("Invalid record in smbXsrv_tcon_global.tdb:"
    1233             :                          "key '%s' info0 NULL pointer\n",
    1234             :                          tdb_data_dbg(key));
    1235           0 :                 goto done;
    1236             :         }
    1237             : 
    1238         189 :         global_blob.info.info0->db_rec = rec;
    1239         189 :         ret = state->fn(global_blob.info.info0, state->private_data);
    1240         189 : done:
    1241         189 :         TALLOC_FREE(frame);
    1242         189 :         return ret;
    1243             : }
    1244             : 
    1245          69 : NTSTATUS smbXsrv_tcon_global_traverse(
    1246             :                         int (*fn)(struct smbXsrv_tcon_global0 *, void *),
    1247             :                         void *private_data)
    1248             : {
    1249           0 :         NTSTATUS status;
    1250          69 :         int count = 0;
    1251          69 :         struct smbXsrv_tcon_global_traverse_state state = {
    1252             :                 .fn = fn,
    1253             :                 .private_data = private_data,
    1254             :         };
    1255             : 
    1256          69 :         become_root();
    1257          69 :         status = smbXsrv_tcon_global_init();
    1258          69 :         if (!NT_STATUS_IS_OK(status)) {
    1259           0 :                 unbecome_root();
    1260           0 :                 DBG_ERR("Failed to initialize tcon_global: %s\n",
    1261             :                           nt_errstr(status));
    1262           0 :                 return status;
    1263             :         }
    1264             : 
    1265          69 :         status = dbwrap_traverse_read(smbXsrv_tcon_global_db_ctx,
    1266             :                                       smbXsrv_tcon_global_traverse_fn,
    1267             :                                       &state,
    1268             :                                       &count);
    1269          69 :         unbecome_root();
    1270             : 
    1271          69 :         return status;
    1272             : }

Generated by: LCOV version 1.14