LCOV - code coverage report
Current view: top level - source3/smbd - smbXsrv_tcon.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 332 509 65.2 %
Date: 2021-08-25 13:27:56 Functions: 30 32 93.8 %

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

Generated by: LCOV version 1.13