LCOV - code coverage report
Current view: top level - source3/smbd - smbXsrv_tcon.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 336 517 65.0 %
Date: 2024-06-13 04:01:37 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             : 
      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        5023 : NTSTATUS smbXsrv_tcon_global_init(void)
      50             : {
      51        5023 :         char *global_path = NULL;
      52        5023 :         struct db_context *db_ctx = NULL;
      53             : 
      54        5023 :         if (smbXsrv_tcon_global_db_ctx != NULL) {
      55        4972 :                 return NT_STATUS_OK;
      56             :         }
      57             : 
      58          51 :         global_path = lock_path(talloc_tos(), "smbXsrv_tcon_global.tdb");
      59          51 :         if (global_path == NULL) {
      60           0 :                 return NT_STATUS_NO_MEMORY;
      61             :         }
      62             : 
      63          51 :         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          51 :         TALLOC_FREE(global_path);
      72          51 :         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          51 :         smbXsrv_tcon_global_db_ctx = db_ctx;
      81             : 
      82          51 :         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       16737 : static TDB_DATA smbXsrv_tcon_global_id_to_key(uint32_t id,
      97             :                                               uint8_t *key_buf)
      98             : {
      99             :         TDB_DATA key;
     100             : 
     101       16737 :         RSIVAL(key_buf, 0, id);
     102             : 
     103       16737 :         key = make_tdb_data(key_buf, SMBXSRV_TCON_GLOBAL_TDB_KEY_SIZE);
     104             : 
     105       16737 :         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      141914 : static TDB_DATA smbXsrv_tcon_local_id_to_key(uint32_t id,
     128             :                                              uint8_t *key_buf)
     129             : {
     130             :         TDB_DATA key;
     131             : 
     132      141914 :         RSIVAL(key_buf, 0, id);
     133             : 
     134      141914 :         key = make_tdb_data(key_buf, SMBXSRV_TCON_LOCAL_TDB_KEY_SIZE);
     135             : 
     136      141914 :         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       16737 : 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       16737 :         struct db_record *rec = NULL;
     162             : 
     163       16737 :         key = smbXsrv_tcon_global_id_to_key(id, key_buf);
     164             : 
     165       16737 :         rec = dbwrap_fetch_locked(db, mem_ctx, key);
     166             : 
     167       16737 :         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       16737 :         return rec;
     173             : }
     174             : 
     175        8076 : 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        8076 :         struct db_record *rec = NULL;
     183             : 
     184        8076 :         key = smbXsrv_tcon_local_id_to_key(id, key_buf);
     185             : 
     186        8076 :         rec = dbwrap_fetch_locked(db, mem_ctx, key);
     187             : 
     188        8076 :         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        8076 :         return rec;
     194             : }
     195             : 
     196        4958 : 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        4958 :         if (lowest_id > highest_id) {
     206           0 :                 return NT_STATUS_INTERNAL_ERROR;
     207             :         }
     208             : 
     209        4958 :         max_range = highest_id;
     210        4958 :         max_range -= lowest_id;
     211        4958 :         max_range += 1;
     212             : 
     213        4958 :         if (max_tcons > max_range) {
     214           0 :                 return NT_STATUS_INTERNAL_ERROR;
     215             :         }
     216             : 
     217        4958 :         ZERO_STRUCTP(table);
     218        4958 :         table->local.db_ctx = db_open_rbt(table);
     219        4958 :         if (table->local.db_ctx == NULL) {
     220           0 :                 return NT_STATUS_NO_MEMORY;
     221             :         }
     222        4958 :         table->local.lowest_id = lowest_id;
     223        4958 :         table->local.highest_id = highest_id;
     224        4958 :         table->local.max_tcons = max_tcons;
     225             : 
     226        4958 :         status = smbXsrv_tcon_global_init();
     227        4958 :         if (!NT_STATUS_IS_OK(status)) {
     228           0 :                 return status;
     229             :         }
     230             : 
     231        4958 :         table->global.db_ctx = smbXsrv_tcon_global_db_ctx;
     232             : 
     233        4958 :         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          28 : 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          28 :         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          28 :         int count = 0;
     297             : 
     298          28 :         *_rec = NULL;
     299          28 :         *_id = 0;
     300             : 
     301          28 :         if (lowest_id > highest_id) {
     302           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     303             :         }
     304             : 
     305             :         /*
     306             :          * first we try randomly
     307             :          */
     308          28 :         range = (highest_id - lowest_id) + 1;
     309             : 
     310          51 :         for (i = 0; i < (range / 2); i++) {
     311             :                 uint32_t id;
     312             :                 TDB_DATA val;
     313          28 :                 struct db_record *rec = NULL;
     314             : 
     315          28 :                 id = generate_random() % range;
     316          28 :                 id += lowest_id;
     317             : 
     318          28 :                 if (id < lowest_id) {
     319           0 :                         id = lowest_id;
     320             :                 }
     321          28 :                 if (id > highest_id) {
     322           0 :                         id = highest_id;
     323             :                 }
     324             : 
     325          28 :                 rec = smbXsrv_tcon_local_fetch_locked(db, id, mem_ctx);
     326          28 :                 if (rec == NULL) {
     327          23 :                         return NT_STATUS_INSUFFICIENT_RESOURCES;
     328             :                 }
     329             : 
     330          28 :                 val = dbwrap_record_get_value(rec);
     331          28 :                 if (val.dsize != 0) {
     332           0 :                         TALLOC_FREE(rec);
     333           0 :                         continue;
     334             :                 }
     335             : 
     336          28 :                 *_rec = rec;
     337          28 :                 *_id = id;
     338          28 :                 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      133828 : static void smbXsrv_tcon_local_fetch_parser(TDB_DATA key, TDB_DATA data,
     405             :                                             void *private_data)
     406             : {
     407      133828 :         struct smbXsrv_tcon_local_fetch_state *state =
     408             :                 (struct smbXsrv_tcon_local_fetch_state *)private_data;
     409             :         void *ptr;
     410             : 
     411      133828 :         if (data.dsize != sizeof(ptr)) {
     412           0 :                 state->status = NT_STATUS_INTERNAL_DB_ERROR;
     413           0 :                 return;
     414             :         }
     415             : 
     416      133828 :         memcpy(&ptr, data.dptr, data.dsize);
     417      133828 :         state->tcon = talloc_get_type_abort(ptr, struct smbXsrv_tcon);
     418      133828 :         state->status = NT_STATUS_OK;
     419             : }
     420             : 
     421      137479 : 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      137479 :         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      137479 :         *_tcon = NULL;
     435             : 
     436      137479 :         if (tcon_local_id == 0) {
     437        3641 :                 return NT_STATUS_NETWORK_NAME_DELETED;
     438             :         }
     439             : 
     440      133838 :         if (table == NULL) {
     441             :                 /* this might happen before the end of negprot */
     442           0 :                 return NT_STATUS_NETWORK_NAME_DELETED;
     443             :         }
     444             : 
     445      133838 :         if (table->local.db_ctx == NULL) {
     446           0 :                 return NT_STATUS_INTERNAL_ERROR;
     447             :         }
     448             : 
     449      133838 :         key = smbXsrv_tcon_local_id_to_key(tcon_local_id, key_buf);
     450             : 
     451      133838 :         status = dbwrap_parse_record(table->local.db_ctx, key,
     452             :                                      smbXsrv_tcon_local_fetch_parser,
     453             :                                      &state);
     454      133838 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     455          10 :                 return NT_STATUS_NETWORK_NAME_DELETED;
     456      133828 :         } else if (!NT_STATUS_IS_OK(status)) {
     457           0 :                 return status;
     458             :         }
     459      133828 :         if (!NT_STATUS_IS_OK(state.status)) {
     460           0 :                 return state.status;
     461             :         }
     462             : 
     463      133828 :         if (NT_STATUS_EQUAL(state.tcon->status, NT_STATUS_NETWORK_NAME_DELETED)) {
     464           0 :                 return NT_STATUS_NETWORK_NAME_DELETED;
     465             :         }
     466             : 
     467      133828 :         state.tcon->idle_time = now;
     468             : 
     469      133828 :         *_tcon = state.tcon;
     470      133828 :         return state.tcon->status;
     471             : }
     472             : 
     473        5635 : static int smbXsrv_tcon_global_destructor(struct smbXsrv_tcon_global0 *global)
     474             : {
     475        5635 :         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        5635 : 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        5635 :         struct smbXsrv_tcon_global0 *global = NULL;
     490        5635 :         uint32_t last_free = 0;
     491        5635 :         const uint32_t min_tries = 3;
     492             : 
     493        5635 :         *_global = NULL;
     494             : 
     495        5635 :         global = talloc_zero(mem_ctx, struct smbXsrv_tcon_global0);
     496        5635 :         if (global == NULL) {
     497           0 :                 return NT_STATUS_NO_MEMORY;
     498             :         }
     499        5635 :         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        5635 :         for (i = 0; i < UINT32_MAX; i++) {
     508        5635 :                 bool is_free = false;
     509        5635 :                 bool was_free = false;
     510             :                 uint32_t id;
     511             : 
     512        5635 :                 if (i >= min_tries && last_free != 0) {
     513           0 :                         id = last_free;
     514             :                 } else {
     515        5635 :                         id = generate_random();
     516             :                 }
     517        5635 :                 if (id == 0) {
     518           0 :                         id++;
     519             :                 }
     520        5635 :                 if (id == UINT32_MAX) {
     521           0 :                         id--;
     522             :                 }
     523             : 
     524        5635 :                 global->db_rec = smbXsrv_tcon_global_fetch_locked(db, id,
     525             :                                                                   mem_ctx);
     526        5635 :                 if (global->db_rec == NULL) {
     527           0 :                         talloc_free(global);
     528        3822 :                         return NT_STATUS_INSUFFICIENT_RESOURCES;
     529             :                 }
     530             : 
     531        5635 :                 smbXsrv_tcon_global_verify_record(global->db_rec,
     532             :                                                   &is_free,
     533             :                                                   &was_free,
     534             :                                                   NULL, NULL);
     535             : 
     536        5635 :                 if (!is_free) {
     537           0 :                         TALLOC_FREE(global->db_rec);
     538           0 :                         continue;
     539             :                 }
     540             : 
     541        5635 :                 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        5635 :                 global->tcon_global_id = id;
     560             : 
     561        5635 :                 *_global = global;
     562        5635 :                 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        5635 : 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        5635 :         struct smbXsrv_tcon_global0 *global = NULL;
     582             :         bool exists;
     583        5635 :         TALLOC_CTX *frame = talloc_stackframe();
     584             : 
     585        5635 :         *is_free = false;
     586             : 
     587        5635 :         if (was_free) {
     588        5635 :                 *was_free = false;
     589             :         }
     590        5635 :         if (_g) {
     591           0 :                 *_g = NULL;
     592             :         }
     593             : 
     594        5635 :         key = dbwrap_record_get_key(db_rec);
     595             : 
     596        5635 :         val = dbwrap_record_get_value(db_rec);
     597        5635 :         if (val.dsize == 0) {
     598        5635 :                 TALLOC_FREE(frame);
     599        5635 :                 *is_free = true;
     600        5635 :                 if (was_free) {
     601        5635 :                         *was_free = true;
     602             :                 }
     603        9457 :                 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       11110 : static NTSTATUS smbXsrv_tcon_global_store(struct smbXsrv_tcon_global0 *global)
     660             : {
     661             :         struct smbXsrv_tcon_globalB global_blob;
     662       11110 :         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       11110 :         if (global->db_rec == NULL) {
     675           0 :                 return NT_STATUS_INTERNAL_ERROR;
     676             :         }
     677             : 
     678       11110 :         key = dbwrap_record_get_key(global->db_rec);
     679       11110 :         val = dbwrap_record_get_value(global->db_rec);
     680             : 
     681       11110 :         ZERO_STRUCT(global_blob);
     682       11110 :         global_blob.version = smbXsrv_version_global_current();
     683       11110 :         if (val.dsize >= 8) {
     684        5475 :                 global_blob.seqnum = IVAL(val.dptr, 4);
     685             :         }
     686       11110 :         global_blob.seqnum += 1;
     687       11110 :         global_blob.info.info0 = global;
     688             : 
     689       11110 :         ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
     690             :                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_tcon_globalB);
     691       11110 :         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       11110 :         val = make_tdb_data(blob.data, blob.length);
     701       11110 :         status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
     702       11110 :         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       11110 :         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       11110 :         TALLOC_FREE(global->db_rec);
     717             : 
     718       11110 :         return NT_STATUS_OK;
     719             : }
     720             : 
     721        5635 : static int smbXsrv_tcon_destructor(struct smbXsrv_tcon *tcon)
     722             : {
     723             :         NTSTATUS status;
     724             : 
     725        5635 :         status = smbXsrv_tcon_disconnect(tcon, 0);
     726        5635 :         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        5635 :         TALLOC_FREE(tcon->global);
     733             : 
     734        5635 :         return 0;
     735             : }
     736             : 
     737        5635 : 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             :                                     uint32_t session_global_id,
     742             :                                     uint8_t encryption_flags,
     743             :                                     const char *share_name,
     744             :                                     struct smbXsrv_tcon **_tcon)
     745             : {
     746        5635 :         struct db_record *local_rec = NULL;
     747        5635 :         struct smbXsrv_tcon *tcon = NULL;
     748        5635 :         void *ptr = NULL;
     749             :         TDB_DATA val;
     750        5635 :         struct smbXsrv_tcon_global0 *global = NULL;
     751             :         NTSTATUS status;
     752             : 
     753        5635 :         if (table->local.num_tcons >= table->local.max_tcons) {
     754           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     755             :         }
     756             : 
     757        5635 :         tcon = talloc_zero(table, struct smbXsrv_tcon);
     758        5635 :         if (tcon == NULL) {
     759           0 :                 return NT_STATUS_NO_MEMORY;
     760             :         }
     761        5635 :         tcon->table = table;
     762        5635 :         tcon->status = NT_STATUS_INTERNAL_ERROR;
     763        5635 :         tcon->idle_time = now;
     764             : 
     765        5635 :         status = smbXsrv_tcon_global_allocate(table->global.db_ctx,
     766             :                                               tcon, &global);
     767        5635 :         if (!NT_STATUS_IS_OK(status)) {
     768           0 :                 TALLOC_FREE(tcon);
     769           0 :                 return status;
     770             :         }
     771        5635 :         tcon->global = global;
     772             : 
     773        5635 :         global->session_global_id = session_global_id;
     774        5635 :         global->encryption_flags = encryption_flags;
     775        5635 :         global->share_name = talloc_strdup(global, share_name);
     776        5635 :         if (global->share_name == NULL) {
     777           0 :                 TALLOC_FREE(tcon);
     778           0 :                 return NT_STATUS_NO_MEMORY;
     779             :         }
     780             : 
     781        5635 :         if (protocol >= PROTOCOL_SMB2_02) {
     782        5607 :                 uint64_t id = global->tcon_global_id;
     783             : 
     784        5607 :                 global->tcon_wire_id = id;
     785             : 
     786        5607 :                 tcon->local_id = global->tcon_global_id;
     787             : 
     788        5607 :                 local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx,
     789             :                                                         tcon->local_id,
     790             :                                                         tcon /* TALLOC_CTX */);
     791        5607 :                 if (local_rec == NULL) {
     792           0 :                         TALLOC_FREE(tcon);
     793           0 :                         return NT_STATUS_NO_MEMORY;
     794             :                 }
     795             : 
     796        5607 :                 val = dbwrap_record_get_value(local_rec);
     797        5607 :                 if (val.dsize != 0) {
     798           0 :                         TALLOC_FREE(tcon);
     799           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     800             :                 }
     801             :         } else {
     802             : 
     803          28 :                 status = smb1srv_tcon_local_allocate_id(table->local.db_ctx,
     804             :                                                         table->local.lowest_id,
     805             :                                                         table->local.highest_id,
     806             :                                                         tcon,
     807             :                                                         &local_rec,
     808             :                                                         &tcon->local_id);
     809          28 :                 if (!NT_STATUS_IS_OK(status)) {
     810           0 :                         TALLOC_FREE(tcon);
     811           0 :                         return status;
     812             :                 }
     813             : 
     814          28 :                 global->tcon_wire_id = tcon->local_id;
     815             :         }
     816             : 
     817        5635 :         global->creation_time = now;
     818             : 
     819        5635 :         global->server_id = server_id;
     820             : 
     821        5635 :         ptr = tcon;
     822        5635 :         val = make_tdb_data((uint8_t const *)&ptr, sizeof(ptr));
     823        5635 :         status = dbwrap_record_store(local_rec, val, TDB_REPLACE);
     824        5635 :         TALLOC_FREE(local_rec);
     825        5635 :         if (!NT_STATUS_IS_OK(status)) {
     826           0 :                 TALLOC_FREE(tcon);
     827           0 :                 return status;
     828             :         }
     829        5635 :         table->local.num_tcons += 1;
     830             : 
     831        5635 :         talloc_set_destructor(tcon, smbXsrv_tcon_destructor);
     832             : 
     833        5635 :         status = smbXsrv_tcon_global_store(global);
     834        5635 :         if (!NT_STATUS_IS_OK(status)) {
     835           0 :                 DEBUG(0,("smbXsrv_tcon_create: "
     836             :                          "global_id (0x%08x) store failed - %s\n",
     837             :                          tcon->global->tcon_global_id,
     838             :                          nt_errstr(status)));
     839           0 :                 TALLOC_FREE(tcon);
     840           0 :                 return status;
     841             :         }
     842             : 
     843        5635 :         if (DEBUGLVL(10)) {
     844           0 :                 struct smbXsrv_tconB tcon_blob = {
     845             :                         .version = SMBXSRV_VERSION_0,
     846             :                         .info.info0 = tcon,
     847             :                 };
     848             : 
     849           0 :                 DEBUG(10,("smbXsrv_tcon_create: global_id (0x%08x) stored\n",
     850             :                          tcon->global->tcon_global_id));
     851           0 :                 NDR_PRINT_DEBUG(smbXsrv_tconB, &tcon_blob);
     852             :         }
     853             : 
     854        5635 :         *_tcon = tcon;
     855        5635 :         return NT_STATUS_OK;
     856             : }
     857             : 
     858        5475 : NTSTATUS smbXsrv_tcon_update(struct smbXsrv_tcon *tcon)
     859             : {
     860        5475 :         struct smbXsrv_tcon_table *table = tcon->table;
     861             :         NTSTATUS status;
     862             : 
     863        5475 :         if (tcon->global->db_rec != NULL) {
     864           0 :                 DEBUG(0, ("smbXsrv_tcon_update(0x%08x): "
     865             :                           "Called with db_rec != NULL'\n",
     866             :                           tcon->global->tcon_global_id));
     867           0 :                 return NT_STATUS_INTERNAL_ERROR;
     868             :         }
     869             : 
     870        7209 :         tcon->global->db_rec = smbXsrv_tcon_global_fetch_locked(
     871             :                                                 table->global.db_ctx,
     872        5475 :                                                 tcon->global->tcon_global_id,
     873        5475 :                                                 tcon->global /* TALLOC_CTX */);
     874        5475 :         if (tcon->global->db_rec == NULL) {
     875           0 :                 return NT_STATUS_INTERNAL_DB_ERROR;
     876             :         }
     877             : 
     878        5475 :         status = smbXsrv_tcon_global_store(tcon->global);
     879        5475 :         if (!NT_STATUS_IS_OK(status)) {
     880           0 :                 DEBUG(0,("smbXsrv_tcon_update: "
     881             :                          "global_id (0x%08x) store failed - %s\n",
     882             :                          tcon->global->tcon_global_id,
     883             :                          nt_errstr(status)));
     884           0 :                 return status;
     885             :         }
     886             : 
     887        5475 :         if (DEBUGLVL(10)) {
     888           0 :                 struct smbXsrv_tconB tcon_blob = {
     889             :                         .version = SMBXSRV_VERSION_0,
     890             :                         .info.info0 = tcon,
     891             :                 };
     892             : 
     893           0 :                 DEBUG(10,("smbXsrv_tcon_update: global_id (0x%08x) stored\n",
     894             :                           tcon->global->tcon_global_id));
     895           0 :                 NDR_PRINT_DEBUG(smbXsrv_tconB, &tcon_blob);
     896             :         }
     897             : 
     898        5475 :         return NT_STATUS_OK;
     899             : }
     900             : 
     901       11258 : NTSTATUS smbXsrv_tcon_disconnect(struct smbXsrv_tcon *tcon, uint64_t vuid)
     902             : {
     903             :         struct smbXsrv_tcon_table *table;
     904       11258 :         struct db_record *local_rec = NULL;
     905       11258 :         struct db_record *global_rec = NULL;
     906             :         NTSTATUS status;
     907       11258 :         NTSTATUS error = NT_STATUS_OK;
     908             : 
     909       11258 :         if (tcon->table == NULL) {
     910        5623 :                 return NT_STATUS_OK;
     911             :         }
     912             : 
     913        5635 :         table = tcon->table;
     914        5635 :         tcon->table = NULL;
     915             : 
     916        5635 :         if (tcon->compat) {
     917             :                 bool ok;
     918             : 
     919        5623 :                 ok = chdir_current_service(tcon->compat);
     920        5623 :                 if (!ok) {
     921           8 :                         status = NT_STATUS_INTERNAL_ERROR;
     922           8 :                         DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
     923             :                                   "chdir_current_service() failed: %s\n",
     924             :                                   tcon->global->tcon_global_id,
     925             :                                   tcon->global->share_name,
     926             :                                   nt_errstr(status)));
     927             :                         /*
     928             :                          * We must call close_cnum() on
     929             :                          * error, as the caller is going
     930             :                          * to free tcon and tcon->compat
     931             :                          * so we must ensure tcon->compat is
     932             :                          * removed from the linked list
     933             :                          * conn->sconn->connections.
     934             :                          */
     935           8 :                         close_cnum(tcon->compat, vuid, ERROR_CLOSE);
     936           8 :                         tcon->compat = NULL;
     937           8 :                         return status;
     938             :                 }
     939             : 
     940        5615 :                 close_cnum(tcon->compat, vuid, SHUTDOWN_CLOSE);
     941        5615 :                 tcon->compat = NULL;
     942             :         }
     943             : 
     944        5627 :         tcon->status = NT_STATUS_NETWORK_NAME_DELETED;
     945             : 
     946        5627 :         global_rec = tcon->global->db_rec;
     947        5627 :         tcon->global->db_rec = NULL;
     948        5627 :         if (global_rec == NULL) {
     949        5627 :                 global_rec = smbXsrv_tcon_global_fetch_locked(
     950             :                                                 table->global.db_ctx,
     951        5627 :                                                 tcon->global->tcon_global_id,
     952        5627 :                                                 tcon->global /* TALLOC_CTX */);
     953        5627 :                 if (global_rec == NULL) {
     954           0 :                         error = NT_STATUS_INTERNAL_ERROR;
     955             :                 }
     956             :         }
     957             : 
     958        5627 :         if (global_rec != NULL) {
     959        5627 :                 status = dbwrap_record_delete(global_rec);
     960        5627 :                 if (!NT_STATUS_IS_OK(status)) {
     961           0 :                         TDB_DATA key = dbwrap_record_get_key(global_rec);
     962             : 
     963           0 :                         DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
     964             :                                   "failed to delete global key '%s': %s\n",
     965             :                                   tcon->global->tcon_global_id,
     966             :                                   tcon->global->share_name,
     967             :                                   hex_encode_talloc(global_rec, key.dptr,
     968             :                                                     key.dsize),
     969             :                                   nt_errstr(status)));
     970           0 :                         error = status;
     971             :                 }
     972             :         }
     973        5627 :         TALLOC_FREE(global_rec);
     974             : 
     975        5627 :         local_rec = tcon->db_rec;
     976        5627 :         if (local_rec == NULL) {
     977        2441 :                 local_rec = smbXsrv_tcon_local_fetch_locked(table->local.db_ctx,
     978             :                                                         tcon->local_id,
     979             :                                                         tcon /* TALLOC_CTX */);
     980        2441 :                 if (local_rec == NULL) {
     981           0 :                         error = NT_STATUS_INTERNAL_ERROR;
     982             :                 }
     983             :         }
     984             : 
     985        5627 :         if (local_rec != NULL) {
     986        5627 :                 status = dbwrap_record_delete(local_rec);
     987        5627 :                 if (!NT_STATUS_IS_OK(status)) {
     988           0 :                         TDB_DATA key = dbwrap_record_get_key(local_rec);
     989             : 
     990           0 :                         DEBUG(0, ("smbXsrv_tcon_disconnect(0x%08x, '%s'): "
     991             :                                   "failed to delete local key '%s': %s\n",
     992             :                                   tcon->global->tcon_global_id,
     993             :                                   tcon->global->share_name,
     994             :                                   hex_encode_talloc(local_rec, key.dptr,
     995             :                                                     key.dsize),
     996             :                                   nt_errstr(status)));
     997           0 :                         error = status;
     998             :                 }
     999        5627 :                 table->local.num_tcons -= 1;
    1000             :         }
    1001        5627 :         if (tcon->db_rec == NULL) {
    1002        2441 :                 TALLOC_FREE(local_rec);
    1003             :         }
    1004        5627 :         tcon->db_rec = NULL;
    1005             : 
    1006        5627 :         return error;
    1007             : }
    1008             : 
    1009             : struct smbXsrv_tcon_disconnect_all_state {
    1010             :         uint64_t vuid;
    1011             :         NTSTATUS first_status;
    1012             :         int errors;
    1013             : };
    1014             : 
    1015             : static int smbXsrv_tcon_disconnect_all_callback(struct db_record *local_rec,
    1016             :                                                 void *private_data);
    1017             : 
    1018       10190 : static NTSTATUS smbXsrv_tcon_disconnect_all(struct smbXsrv_tcon_table *table,
    1019             :                                             uint64_t vuid)
    1020             : {
    1021             :         struct smbXsrv_tcon_disconnect_all_state state;
    1022             :         NTSTATUS status;
    1023       10190 :         int count = 0;
    1024             : 
    1025       10190 :         if (table == NULL) {
    1026        5232 :                 return NT_STATUS_OK;
    1027             :         }
    1028             : 
    1029        4958 :         ZERO_STRUCT(state);
    1030        4958 :         state.vuid = vuid;
    1031             : 
    1032        4958 :         status = dbwrap_traverse(table->local.db_ctx,
    1033             :                                  smbXsrv_tcon_disconnect_all_callback,
    1034             :                                  &state, &count);
    1035        4958 :         if (!NT_STATUS_IS_OK(status)) {
    1036           0 :                 DEBUG(0, ("smbXsrv_tcon_disconnect_all: "
    1037             :                           "dbwrap_traverse() failed: %s\n",
    1038             :                           nt_errstr(status)));
    1039           0 :                 return status;
    1040             :         }
    1041             : 
    1042        4958 :         if (!NT_STATUS_IS_OK(state.first_status)) {
    1043           8 :                 DEBUG(0, ("smbXsrv_tcon_disconnect_all: "
    1044             :                           "count[%d] errors[%d] first[%s]\n",
    1045             :                           count, state.errors,
    1046             :                           nt_errstr(state.first_status)));
    1047           8 :                 return state.first_status;
    1048             :         }
    1049             : 
    1050        4950 :         return NT_STATUS_OK;
    1051             : }
    1052             : 
    1053        3194 : static int smbXsrv_tcon_disconnect_all_callback(struct db_record *local_rec,
    1054             :                                                 void *private_data)
    1055             : {
    1056        3194 :         struct smbXsrv_tcon_disconnect_all_state *state =
    1057             :                 (struct smbXsrv_tcon_disconnect_all_state *)private_data;
    1058             :         TDB_DATA val;
    1059        3194 :         void *ptr = NULL;
    1060        3194 :         struct smbXsrv_tcon *tcon = NULL;
    1061             :         uint64_t vuid;
    1062             :         NTSTATUS status;
    1063             : 
    1064        3194 :         val = dbwrap_record_get_value(local_rec);
    1065        3194 :         if (val.dsize != sizeof(ptr)) {
    1066           0 :                 status = NT_STATUS_INTERNAL_ERROR;
    1067           0 :                 if (NT_STATUS_IS_OK(state->first_status)) {
    1068           0 :                         state->first_status = status;
    1069             :                 }
    1070           0 :                 state->errors++;
    1071           0 :                 return 0;
    1072             :         }
    1073             : 
    1074        3194 :         memcpy(&ptr, val.dptr, val.dsize);
    1075        3194 :         tcon = talloc_get_type_abort(ptr, struct smbXsrv_tcon);
    1076             : 
    1077        3194 :         vuid = state->vuid;
    1078        3194 :         if (vuid == 0 && tcon->compat) {
    1079           0 :                 vuid = tcon->compat->vuid;
    1080             :         }
    1081             : 
    1082        3194 :         tcon->db_rec = local_rec;
    1083        3194 :         status = smbXsrv_tcon_disconnect(tcon, vuid);
    1084        3194 :         tcon->db_rec = NULL;
    1085        3194 :         if (!NT_STATUS_IS_OK(status)) {
    1086           8 :                 if (NT_STATUS_IS_OK(state->first_status)) {
    1087           8 :                         state->first_status = status;
    1088             :                 }
    1089           8 :                 state->errors++;
    1090           8 :                 return 0;
    1091             :         }
    1092             : 
    1093        3186 :         return 0;
    1094             : }
    1095             : 
    1096          38 : NTSTATUS smb1srv_tcon_table_init(struct smbXsrv_connection *conn)
    1097             : {
    1098          38 :         struct smbXsrv_client *client = conn->client;
    1099             : 
    1100             :         /*
    1101             :          * Allow a range from 1..65534 with 65534 values.
    1102             :          */
    1103          38 :         client->tcon_table = talloc_zero(client, struct smbXsrv_tcon_table);
    1104          38 :         if (client->tcon_table == NULL) {
    1105           0 :                 return NT_STATUS_NO_MEMORY;
    1106             :         }
    1107             : 
    1108          38 :         return smbXsrv_tcon_table_init(client, client->tcon_table,
    1109             :                                        1, UINT16_MAX - 1,
    1110             :                                        UINT16_MAX - 1);
    1111             : }
    1112             : 
    1113          28 : NTSTATUS smb1srv_tcon_create(struct smbXsrv_connection *conn,
    1114             :                              uint32_t session_global_id,
    1115             :                              const char *share_name,
    1116             :                              NTTIME now,
    1117             :                              struct smbXsrv_tcon **_tcon)
    1118             : {
    1119          28 :         struct server_id id = messaging_server_id(conn->client->msg_ctx);
    1120          28 :         const uint8_t encryption_flags = 0;
    1121             : 
    1122          28 :         return smbXsrv_tcon_create(conn->client->tcon_table,
    1123             :                                    conn->protocol,
    1124             :                                    id, now,
    1125             :                                    session_global_id,
    1126             :                                    encryption_flags,
    1127             :                                    share_name,
    1128             :                                    _tcon);
    1129             : }
    1130             : 
    1131        3677 : NTSTATUS smb1srv_tcon_lookup(struct smbXsrv_connection *conn,
    1132             :                              uint16_t tree_id, NTTIME now,
    1133             :                              struct smbXsrv_tcon **tcon)
    1134             : {
    1135        3677 :         uint32_t local_id = tree_id;
    1136             : 
    1137        3677 :         return smbXsrv_tcon_local_lookup(conn->client->tcon_table,
    1138             :                                          local_id, now, tcon);
    1139             : }
    1140             : 
    1141        5270 : NTSTATUS smb1srv_tcon_disconnect_all(struct smbXsrv_client *client)
    1142             : {
    1143             : 
    1144             :         /*
    1145             :          * We do not pass a vuid here,
    1146             :          * which means the vuid is taken from
    1147             :          * the tcon->compat->vuid.
    1148             :          *
    1149             :          * NOTE: that tcon->compat->vuid may point to
    1150             :          * a none existing vuid (or the wrong one)
    1151             :          * as the tcon can exist without a session
    1152             :          * in SMB1.
    1153             :          *
    1154             :          * This matches the old behavior of
    1155             :          * conn_close_all(), but we should think
    1156             :          * about how to fix this in future.
    1157             :          */
    1158        5270 :         return smbXsrv_tcon_disconnect_all(client->tcon_table, 0);
    1159             : }
    1160             : 
    1161        4920 : NTSTATUS smb2srv_tcon_table_init(struct smbXsrv_session *session)
    1162             : {
    1163             :         /*
    1164             :          * Allow a range from 1..4294967294 with 65534 (same as SMB1) values.
    1165             :          */
    1166        4920 :         session->tcon_table = talloc_zero(session, struct smbXsrv_tcon_table);
    1167        4920 :         if (session->tcon_table == NULL) {
    1168           0 :                 return NT_STATUS_NO_MEMORY;
    1169             :         }
    1170             : 
    1171        4920 :         return smbXsrv_tcon_table_init(session, session->tcon_table,
    1172             :                                        1, UINT32_MAX - 1,
    1173             :                                        UINT16_MAX - 1);
    1174             : }
    1175             : 
    1176        5607 : NTSTATUS smb2srv_tcon_create(struct smbXsrv_session *session,
    1177             :                              uint32_t session_global_id,
    1178             :                              uint8_t encryption_flags,
    1179             :                              const char *share_name,
    1180             :                              NTTIME now,
    1181             :                              struct smbXsrv_tcon **_tcon)
    1182             : {
    1183        5607 :         struct server_id id = messaging_server_id(session->client->msg_ctx);
    1184             : 
    1185        5607 :         return smbXsrv_tcon_create(session->tcon_table,
    1186             :                                    PROTOCOL_SMB2_02,
    1187             :                                    id, now,
    1188             :                                    session_global_id,
    1189             :                                    encryption_flags,
    1190             :                                    share_name,
    1191             :                                    _tcon);
    1192             : }
    1193             : 
    1194      133802 : NTSTATUS smb2srv_tcon_lookup(struct smbXsrv_session *session,
    1195             :                              uint32_t tree_id, NTTIME now,
    1196             :                              struct smbXsrv_tcon **tcon)
    1197             : {
    1198      133802 :         uint32_t local_id = tree_id;
    1199             : 
    1200      133802 :         return smbXsrv_tcon_local_lookup(session->tcon_table,
    1201             :                                          local_id, now, tcon);
    1202             : }
    1203             : 
    1204        4920 : NTSTATUS smb2srv_tcon_disconnect_all(struct smbXsrv_session *session)
    1205             : {
    1206        4920 :         uint64_t vuid = session->global->session_wire_id;
    1207             : 
    1208        4920 :         return smbXsrv_tcon_disconnect_all(session->tcon_table, vuid);
    1209             : }
    1210             : 
    1211             : struct smbXsrv_tcon_global_traverse_state {
    1212             :         int (*fn)(struct smbXsrv_tcon_global0 *, void *);
    1213             :         void *private_data;
    1214             : };
    1215             : 
    1216          91 : static int smbXsrv_tcon_global_traverse_fn(struct db_record *rec, void *data)
    1217             : {
    1218          91 :         int ret = -1;
    1219          91 :         struct smbXsrv_tcon_global_traverse_state *state =
    1220             :                 (struct smbXsrv_tcon_global_traverse_state*)data;
    1221          91 :         TDB_DATA key = dbwrap_record_get_key(rec);
    1222          91 :         TDB_DATA val = dbwrap_record_get_value(rec);
    1223          91 :         DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
    1224             :         struct smbXsrv_tcon_globalB global_blob;
    1225             :         enum ndr_err_code ndr_err;
    1226          91 :         TALLOC_CTX *frame = talloc_stackframe();
    1227             : 
    1228          91 :         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
    1229             :                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_tcon_globalB);
    1230          91 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1231           0 :                 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
    1232             :                          "key '%s' ndr_pull_struct_blob - %s\n",
    1233             :                          hex_encode_talloc(frame, key.dptr, key.dsize),
    1234             :                          ndr_errstr(ndr_err)));
    1235           0 :                 goto done;
    1236             :         }
    1237             : 
    1238          91 :         if (global_blob.version != SMBXSRV_VERSION_0) {
    1239           0 :                 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
    1240             :                          "key '%s' unsupported version - %d\n",
    1241             :                          hex_encode_talloc(frame, key.dptr, key.dsize),
    1242             :                          (int)global_blob.version));
    1243           0 :                 goto done;
    1244             :         }
    1245             : 
    1246          91 :         if (global_blob.info.info0 == NULL) {
    1247           0 :                 DEBUG(1,("Invalid record in smbXsrv_tcon_global.tdb:"
    1248             :                          "key '%s' info0 NULL pointer\n",
    1249             :                          hex_encode_talloc(frame, key.dptr, key.dsize)));
    1250           0 :                 goto done;
    1251             :         }
    1252             : 
    1253          91 :         global_blob.info.info0->db_rec = rec;
    1254          91 :         ret = state->fn(global_blob.info.info0, state->private_data);
    1255          91 : done:
    1256          91 :         TALLOC_FREE(frame);
    1257          91 :         return ret;
    1258             : }
    1259             : 
    1260          21 : NTSTATUS smbXsrv_tcon_global_traverse(
    1261             :                         int (*fn)(struct smbXsrv_tcon_global0 *, void *),
    1262             :                         void *private_data)
    1263             : {
    1264             :         NTSTATUS status;
    1265          21 :         int count = 0;
    1266          21 :         struct smbXsrv_tcon_global_traverse_state state = {
    1267             :                 .fn = fn,
    1268             :                 .private_data = private_data,
    1269             :         };
    1270             : 
    1271          21 :         become_root();
    1272          21 :         status = smbXsrv_tcon_global_init();
    1273          21 :         if (!NT_STATUS_IS_OK(status)) {
    1274           0 :                 unbecome_root();
    1275           0 :                 DEBUG(0, ("Failed to initialize tcon_global: %s\n",
    1276             :                           nt_errstr(status)));
    1277           0 :                 return status;
    1278             :         }
    1279             : 
    1280          21 :         status = dbwrap_traverse_read(smbXsrv_tcon_global_db_ctx,
    1281             :                                       smbXsrv_tcon_global_traverse_fn,
    1282             :                                       &state,
    1283             :                                       &count);
    1284          21 :         unbecome_root();
    1285             : 
    1286          21 :         return status;
    1287             : }

Generated by: LCOV version 1.13