LCOV - code coverage report
Current view: top level - source3/smbd - smbXsrv_client.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 418 710 58.9 %
Date: 2024-04-21 15:09:00 Functions: 23 25 92.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Copyright (C) Stefan Metzmacher 2014
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "system/filesys.h"
      22             : #include <tevent.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 "dbwrap/dbwrap_watch.h"
      30             : #include "session.h"
      31             : #include "auth.h"
      32             : #include "auth/gensec/gensec.h"
      33             : #include "../lib/tsocket/tsocket.h"
      34             : #include "../libcli/security/security.h"
      35             : #include "messages.h"
      36             : #include "lib/util/util_tdb.h"
      37             : #include "librpc/gen_ndr/ndr_smbXsrv.h"
      38             : #include "serverid.h"
      39             : #include "lib/util/tevent_ntstatus.h"
      40             : #include "lib/util/iov_buf.h"
      41             : #include "lib/global_contexts.h"
      42             : #include "source3/include/util_tdb.h"
      43             : 
      44             : struct smbXsrv_client_table {
      45             :         struct {
      46             :                 uint32_t max_clients;
      47             :                 uint32_t num_clients;
      48             :         } local;
      49             :         struct {
      50             :                 struct db_context *db_ctx;
      51             :         } global;
      52             : };
      53             : 
      54             : static struct db_context *smbXsrv_client_global_db_ctx = NULL;
      55             : 
      56       31563 : NTSTATUS smbXsrv_client_global_init(void)
      57             : {
      58       31563 :         const char *global_path = NULL;
      59       31563 :         struct db_context *backend = NULL;
      60       31563 :         struct db_context *db_ctx = NULL;
      61             : 
      62       31563 :         if (smbXsrv_client_global_db_ctx != NULL) {
      63       31563 :                 return NT_STATUS_OK;
      64             :         }
      65             : 
      66             :         /*
      67             :          * This contains secret information like client keys!
      68             :          */
      69           0 :         global_path = lock_path(talloc_tos(), "smbXsrv_client_global.tdb");
      70           0 :         if (global_path == NULL) {
      71           0 :                 return NT_STATUS_NO_MEMORY;
      72             :         }
      73             : 
      74           0 :         backend = db_open(NULL, global_path,
      75             :                           0, /* hash_size */
      76             :                           TDB_DEFAULT |
      77             :                           TDB_CLEAR_IF_FIRST |
      78             :                           TDB_INCOMPATIBLE_HASH,
      79             :                           O_RDWR | O_CREAT, 0600,
      80             :                           DBWRAP_LOCK_ORDER_1,
      81             :                           DBWRAP_FLAG_NONE);
      82           0 :         if (backend == NULL) {
      83           0 :                 NTSTATUS status;
      84             : 
      85           0 :                 status = map_nt_error_from_unix_common(errno);
      86             : 
      87           0 :                 return status;
      88             :         }
      89             : 
      90           0 :         db_ctx = db_open_watched(NULL, &backend, global_messaging_context());
      91           0 :         if (db_ctx == NULL) {
      92           0 :                 TALLOC_FREE(backend);
      93           0 :                 return NT_STATUS_NO_MEMORY;
      94             :         }
      95             : 
      96           0 :         smbXsrv_client_global_db_ctx = db_ctx;
      97             : 
      98           0 :         return NT_STATUS_OK;
      99             : }
     100             : 
     101             : #define SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE 16
     102             : 
     103       48877 : static TDB_DATA smbXsrv_client_global_id_to_key(const struct GUID *client_guid,
     104             :                                                 uint8_t *key_buf)
     105             : {
     106       48877 :         TDB_DATA key = { .dsize = 0, };
     107       48877 :         struct GUID_ndr_buf buf = { .buf = {0}, };
     108             : 
     109       48877 :         GUID_to_ndr_buf(client_guid, &buf);
     110       48877 :         memcpy(key_buf, buf.buf, SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE);
     111             : 
     112       48877 :         key = make_tdb_data(key_buf, SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE);
     113             : 
     114       48877 :         return key;
     115             : }
     116             : 
     117       48877 : static struct db_record *smbXsrv_client_global_fetch_locked(
     118             :                         struct db_context *db,
     119             :                         const struct GUID *client_guid,
     120             :                         TALLOC_CTX *mem_ctx)
     121             : {
     122        1342 :         TDB_DATA key;
     123        1342 :         uint8_t key_buf[SMBXSRV_CLIENT_GLOBAL_TDB_KEY_SIZE];
     124       48877 :         struct db_record *rec = NULL;
     125             : 
     126       48877 :         key = smbXsrv_client_global_id_to_key(client_guid, key_buf);
     127             : 
     128       48877 :         rec = dbwrap_fetch_locked(db, mem_ctx, key);
     129             : 
     130       48877 :         if (rec == NULL) {
     131           0 :                 struct GUID_txt_buf buf;
     132           0 :                 DBG_DEBUG("Failed to lock guid [%s], key '%s'\n",
     133             :                           GUID_buf_string(client_guid, &buf),
     134             :                           tdb_data_dbg(key));
     135             :         }
     136             : 
     137       48877 :         return rec;
     138             : }
     139             : 
     140       31563 : static NTSTATUS smbXsrv_client_table_create(TALLOC_CTX *mem_ctx,
     141             :                                             struct messaging_context *msg_ctx,
     142             :                                             uint32_t max_clients,
     143             :                                             struct smbXsrv_client_table **_table)
     144             : {
     145         842 :         struct smbXsrv_client_table *table;
     146         842 :         NTSTATUS status;
     147             : 
     148       31563 :         if (max_clients > 1) {
     149           0 :                 return NT_STATUS_INTERNAL_ERROR;
     150             :         }
     151             : 
     152       31563 :         table = talloc_zero(mem_ctx, struct smbXsrv_client_table);
     153       31563 :         if (table == NULL) {
     154           0 :                 return NT_STATUS_NO_MEMORY;
     155             :         }
     156             : 
     157       31563 :         table->local.max_clients = max_clients;
     158             : 
     159       31563 :         status = smbXsrv_client_global_init();
     160       31563 :         if (!NT_STATUS_IS_OK(status)) {
     161           0 :                 TALLOC_FREE(table);
     162           0 :                 return status;
     163             :         }
     164             : 
     165       31563 :         table->global.db_ctx = smbXsrv_client_global_db_ctx;
     166             : 
     167       31563 :         *_table = table;
     168       31563 :         return NT_STATUS_OK;
     169             : }
     170             : 
     171       31549 : static int smbXsrv_client_global_destructor(struct smbXsrv_client_global0 *global)
     172             : {
     173       31549 :         return 0;
     174             : }
     175             : 
     176       25043 : static void smbXsrv_client_global_verify_record(struct db_record *db_rec,
     177             :                                         bool *is_free,
     178             :                                         bool *was_free,
     179             :                                         TALLOC_CTX *mem_ctx,
     180             :                                         const struct server_id *dead_server_id,
     181             :                                         struct smbXsrv_client_global0 **_g,
     182             :                                         uint32_t *pseqnum)
     183             : {
     184         697 :         TDB_DATA key;
     185         697 :         TDB_DATA val;
     186         697 :         DATA_BLOB blob;
     187         697 :         struct smbXsrv_client_globalB global_blob;
     188         697 :         enum ndr_err_code ndr_err;
     189       25043 :         struct smbXsrv_client_global0 *global = NULL;
     190       25043 :         bool dead = false;
     191         697 :         bool exists;
     192       25043 :         TALLOC_CTX *frame = talloc_stackframe();
     193             : 
     194       25043 :         *is_free = false;
     195             : 
     196       25043 :         if (was_free) {
     197           0 :                 *was_free = false;
     198             :         }
     199       25043 :         if (_g) {
     200       25043 :                 *_g = NULL;
     201             :         }
     202       25043 :         if (pseqnum) {
     203       25043 :                 *pseqnum = 0;
     204             :         }
     205             : 
     206       25043 :         key = dbwrap_record_get_key(db_rec);
     207             : 
     208       25043 :         val = dbwrap_record_get_value(db_rec);
     209       25043 :         if (val.dsize == 0) {
     210       23834 :                 TALLOC_FREE(frame);
     211       23834 :                 *is_free = true;
     212       23834 :                 if (was_free) {
     213           0 :                         *was_free = true;
     214             :                 }
     215       23836 :                 return;
     216             :         }
     217             : 
     218        1209 :         blob = data_blob_const(val.dptr, val.dsize);
     219             : 
     220        1209 :         ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
     221             :                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_client_globalB);
     222        1209 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     223           0 :                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
     224           0 :                 DBG_WARNING("key '%s' ndr_pull_struct_blob - %s\n",
     225             :                             tdb_data_dbg(key),
     226             :                             nt_errstr(status));
     227           0 :                 TALLOC_FREE(frame);
     228           0 :                 return;
     229             :         }
     230             : 
     231        1209 :         DBG_DEBUG("client_global:\n");
     232        1209 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
     233           0 :                 NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
     234             :         }
     235             : 
     236        1209 :         if (global_blob.version != SMBXSRV_VERSION_0) {
     237           0 :                 DBG_ERR("key '%s' uses unsupported version %u\n",
     238             :                         tdb_data_dbg(key),
     239             :                         global_blob.version);
     240           0 :                 NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
     241           0 :                 TALLOC_FREE(frame);
     242           0 :                 return;
     243             :         }
     244             : 
     245        1209 :         global = global_blob.info.info0;
     246             : 
     247        1209 :         dead = server_id_equal(dead_server_id, &global->server_id);
     248        1209 :         if (dead) {
     249           0 :                 struct server_id_buf tmp;
     250             : 
     251           0 :                 DBG_NOTICE("key '%s' server_id %s is already dead.\n",
     252             :                            tdb_data_dbg(key),
     253             :                            server_id_str_buf(global->server_id, &tmp));
     254           0 :                 if (DEBUGLVL(DBGLVL_NOTICE)) {
     255           0 :                         NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
     256             :                 }
     257           0 :                 TALLOC_FREE(frame);
     258           0 :                 dbwrap_record_delete(db_rec);
     259           0 :                 *is_free = true;
     260           0 :                 return;
     261             :         }
     262             : 
     263        1209 :         exists = serverid_exists(&global->server_id);
     264        1209 :         if (!exists) {
     265           0 :                 struct server_id_buf tmp;
     266             : 
     267           2 :                 DBG_NOTICE("key '%s' server_id %s does not exist.\n",
     268             :                            tdb_data_dbg(key),
     269             :                            server_id_str_buf(global->server_id, &tmp));
     270           2 :                 if (DEBUGLVL(DBGLVL_NOTICE)) {
     271           0 :                         NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
     272             :                 }
     273           2 :                 TALLOC_FREE(frame);
     274           2 :                 dbwrap_record_delete(db_rec);
     275           2 :                 *is_free = true;
     276           2 :                 return;
     277             :         }
     278             : 
     279        1207 :         if (_g) {
     280        1207 :                 *_g = talloc_move(mem_ctx, &global);
     281             :         }
     282        1207 :         if (pseqnum) {
     283        1207 :                 *pseqnum = global_blob.seqnum;
     284             :         }
     285        1207 :         TALLOC_FREE(frame);
     286             : }
     287             : 
     288        1168 : static NTSTATUS smb2srv_client_connection_pass(struct smbd_smb2_request *smb2req,
     289             :                                                struct smbXsrv_client_global0 *global)
     290             : {
     291          52 :         DATA_BLOB blob;
     292          52 :         enum ndr_err_code ndr_err;
     293          52 :         NTSTATUS status;
     294          52 :         struct smbXsrv_connection_pass0 pass_info0;
     295          52 :         struct smbXsrv_connection_passB pass_blob;
     296          52 :         ssize_t reqlen;
     297          52 :         struct iovec iov;
     298             : 
     299        1168 :         pass_info0 = (struct smbXsrv_connection_pass0) {
     300        1116 :                 .client_guid = global->client_guid,
     301        1168 :                 .src_server_id = smb2req->xconn->client->global->server_id,
     302        1168 :                 .xconn_connect_time = smb2req->xconn->client->global->initial_connect_time,
     303        1116 :                 .dst_server_id = global->server_id,
     304        1168 :                 .client_connect_time = global->initial_connect_time,
     305             :         };
     306             : 
     307        1168 :         reqlen = iov_buflen(smb2req->in.vector, smb2req->in.vector_count);
     308        1168 :         if (reqlen == -1) {
     309           0 :                 return NT_STATUS_INVALID_BUFFER_SIZE;
     310             :         }
     311             : 
     312        1168 :         pass_info0.negotiate_request.length = reqlen;
     313        1168 :         pass_info0.negotiate_request.data = talloc_array(talloc_tos(), uint8_t,
     314             :                                                          reqlen);
     315        1168 :         if (pass_info0.negotiate_request.data == NULL) {
     316           0 :                 return NT_STATUS_NO_MEMORY;
     317             :         }
     318        1168 :         iov_buf(smb2req->in.vector, smb2req->in.vector_count,
     319             :                 pass_info0.negotiate_request.data,
     320             :                 pass_info0.negotiate_request.length);
     321             : 
     322        1168 :         ZERO_STRUCT(pass_blob);
     323        1168 :         pass_blob.version = smbXsrv_version_global_current();
     324        1168 :         pass_blob.info.info0 = &pass_info0;
     325             : 
     326        1168 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
     327           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
     328             :         }
     329             : 
     330        1168 :         ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &pass_blob,
     331             :                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_connection_passB);
     332        1168 :         data_blob_free(&pass_info0.negotiate_request);
     333        1168 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     334           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     335           0 :                 return status;
     336             :         }
     337             : 
     338        1168 :         iov.iov_base = blob.data;
     339        1168 :         iov.iov_len = blob.length;
     340             : 
     341        1168 :         status = messaging_send_iov(smb2req->xconn->client->msg_ctx,
     342             :                                     global->server_id,
     343             :                                     MSG_SMBXSRV_CONNECTION_PASS,
     344             :                                     &iov, 1,
     345        1168 :                                     &smb2req->xconn->transport.sock, 1);
     346        1168 :         data_blob_free(&blob);
     347        1168 :         if (!NT_STATUS_IS_OK(status)) {
     348           0 :                 return status;
     349             :         }
     350             : 
     351        1168 :         return NT_STATUS_OK;
     352             : }
     353             : 
     354           0 : static NTSTATUS smb2srv_client_connection_drop(struct smbd_smb2_request *smb2req,
     355             :                                                struct smbXsrv_client_global0 *global)
     356             : {
     357           0 :         DATA_BLOB blob;
     358           0 :         enum ndr_err_code ndr_err;
     359           0 :         NTSTATUS status;
     360           0 :         struct smbXsrv_connection_drop0 drop_info0;
     361           0 :         struct smbXsrv_connection_dropB drop_blob;
     362           0 :         struct iovec iov;
     363             : 
     364           0 :         drop_info0 = (struct smbXsrv_connection_drop0) {
     365           0 :                 .client_guid = global->client_guid,
     366           0 :                 .src_server_id = smb2req->xconn->client->global->server_id,
     367           0 :                 .xconn_connect_time = smb2req->xconn->client->global->initial_connect_time,
     368           0 :                 .dst_server_id = global->server_id,
     369           0 :                 .client_connect_time = global->initial_connect_time,
     370             :         };
     371             : 
     372           0 :         ZERO_STRUCT(drop_blob);
     373           0 :         drop_blob.version = smbXsrv_version_global_current();
     374           0 :         drop_blob.info.info0 = &drop_info0;
     375             : 
     376           0 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
     377           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_dropB, &drop_blob);
     378             :         }
     379             : 
     380           0 :         ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &drop_blob,
     381             :                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_connection_dropB);
     382           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     383           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     384           0 :                 return status;
     385             :         }
     386             : 
     387           0 :         iov.iov_base = blob.data;
     388           0 :         iov.iov_len = blob.length;
     389             : 
     390           0 :         status = messaging_send_iov(smb2req->xconn->client->msg_ctx,
     391             :                                     global->server_id,
     392             :                                     MSG_SMBXSRV_CONNECTION_DROP,
     393             :                                     &iov, 1,
     394             :                                     NULL, 0);
     395           0 :         data_blob_free(&blob);
     396           0 :         if (!NT_STATUS_IS_OK(status)) {
     397           0 :                 return status;
     398             :         }
     399             : 
     400           0 :         return NT_STATUS_OK;
     401             : }
     402             : 
     403       23836 : static NTSTATUS smbXsrv_client_global_store(struct smbXsrv_client_global0 *global)
     404             : {
     405         645 :         struct smbXsrv_client_globalB global_blob;
     406       23836 :         DATA_BLOB blob = data_blob_null;
     407         645 :         TDB_DATA key;
     408         645 :         TDB_DATA val;
     409         645 :         NTSTATUS status;
     410         645 :         enum ndr_err_code ndr_err;
     411       23836 :         bool saved_stored = global->stored;
     412             : 
     413             :         /*
     414             :          * TODO: if we use other versions than '0'
     415             :          * we would add glue code here, that would be able to
     416             :          * store the information in the old format.
     417             :          */
     418             : 
     419       23836 :         SMB_ASSERT(global->local_address != NULL);
     420       23836 :         SMB_ASSERT(global->remote_address != NULL);
     421       23836 :         SMB_ASSERT(global->remote_name != NULL);
     422             : 
     423       23836 :         if (global->db_rec == NULL) {
     424           0 :                 return NT_STATUS_INTERNAL_ERROR;
     425             :         }
     426             : 
     427       23836 :         key = dbwrap_record_get_key(global->db_rec);
     428       23836 :         val = dbwrap_record_get_value(global->db_rec);
     429             : 
     430       23836 :         ZERO_STRUCT(global_blob);
     431       23836 :         global_blob.version = smbXsrv_version_global_current();
     432       23836 :         if (val.dsize >= 8) {
     433           0 :                 global_blob.seqnum = IVAL(val.dptr, 4);
     434             :         }
     435       23836 :         global_blob.seqnum += 1;
     436       23836 :         global_blob.info.info0 = global;
     437             : 
     438       23836 :         global->stored = true;
     439       23836 :         ndr_err = ndr_push_struct_blob(&blob, global->db_rec, &global_blob,
     440             :                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_client_globalB);
     441       23836 :         global->stored = saved_stored;
     442       23836 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     443           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     444           0 :                 DBG_WARNING("key '%s' ndr_push - %s\n",
     445             :                         tdb_data_dbg(key),
     446             :                         nt_errstr(status));
     447           0 :                 TALLOC_FREE(global->db_rec);
     448           0 :                 return status;
     449             :         }
     450             : 
     451       23836 :         val = make_tdb_data(blob.data, blob.length);
     452       23836 :         status = dbwrap_record_store(global->db_rec, val, TDB_REPLACE);
     453       23836 :         if (!NT_STATUS_IS_OK(status)) {
     454           0 :                 DBG_WARNING("key '%s' store - %s\n",
     455             :                         tdb_data_dbg(key),
     456             :                         nt_errstr(status));
     457           0 :                 TALLOC_FREE(global->db_rec);
     458           0 :                 return status;
     459             :         }
     460             : 
     461       23836 :         global->stored = true;
     462             : 
     463       23836 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
     464           0 :                 DBG_DEBUG("key '%s' stored\n",
     465             :                           tdb_data_dbg(key));
     466           0 :                 NDR_PRINT_DEBUG(smbXsrv_client_globalB, &global_blob);
     467             :         }
     468             : 
     469       23836 :         TALLOC_FREE(global->db_rec);
     470             : 
     471       23836 :         return NT_STATUS_OK;
     472             : }
     473             : 
     474             : struct smb2srv_client_mc_negprot_state {
     475             :         struct tevent_context *ev;
     476             :         struct smbd_smb2_request *smb2req;
     477             :         struct db_record *db_rec;
     478             :         struct server_id sent_server_id;
     479             :         uint64_t watch_instance;
     480             :         uint32_t last_seqnum;
     481             :         struct tevent_req *filter_subreq;
     482             : };
     483             : 
     484       50008 : static void smb2srv_client_mc_negprot_cleanup(struct tevent_req *req,
     485             :                                               enum tevent_req_state req_state)
     486             : {
     487        1394 :         struct smb2srv_client_mc_negprot_state *state =
     488       50008 :                 tevent_req_data(req,
     489             :                 struct smb2srv_client_mc_negprot_state);
     490             : 
     491       50008 :         if (state->db_rec != NULL) {
     492           0 :                 dbwrap_watched_watch_remove_instance(state->db_rec,
     493             :                                                      state->watch_instance);
     494           0 :                 state->watch_instance = 0;
     495           0 :                 TALLOC_FREE(state->db_rec);
     496             :         }
     497       50008 : }
     498             : 
     499             : static void smb2srv_client_mc_negprot_next(struct tevent_req *req);
     500             : static bool smb2srv_client_mc_negprot_filter(struct messaging_rec *rec, void *private_data);
     501             : static void smb2srv_client_mc_negprot_done(struct tevent_req *subreq);
     502             : static void smb2srv_client_mc_negprot_watched(struct tevent_req *subreq);
     503             : 
     504       25004 : struct tevent_req *smb2srv_client_mc_negprot_send(TALLOC_CTX *mem_ctx,
     505             :                                                   struct tevent_context *ev,
     506             :                                                   struct smbd_smb2_request *smb2req)
     507             : {
     508       25004 :         struct tevent_req *req = NULL;
     509       25004 :         struct smb2srv_client_mc_negprot_state *state = NULL;
     510             : 
     511       25004 :         req = tevent_req_create(mem_ctx, &state,
     512             :                                 struct smb2srv_client_mc_negprot_state);
     513       25004 :         if (req == NULL) {
     514           0 :                 return NULL;
     515             :         }
     516       25004 :         state->ev = ev;
     517       25004 :         state->smb2req = smb2req;
     518             : 
     519       25004 :         tevent_req_set_cleanup_fn(req, smb2srv_client_mc_negprot_cleanup);
     520             : 
     521       25004 :         server_id_set_disconnected(&state->sent_server_id);
     522             : 
     523       25004 :         smb2srv_client_mc_negprot_next(req);
     524             : 
     525       25004 :         if (!tevent_req_is_in_progress(req)) {
     526       23836 :                 return tevent_req_post(req, ev);
     527             :         }
     528             : 
     529        1116 :         return req;
     530             : }
     531             : 
     532       25043 : static void smb2srv_client_mc_negprot_next(struct tevent_req *req)
     533             : {
     534         697 :         struct smb2srv_client_mc_negprot_state *state =
     535       25043 :                 tevent_req_data(req,
     536             :                 struct smb2srv_client_mc_negprot_state);
     537       25043 :         struct smbXsrv_connection *xconn = state->smb2req->xconn;
     538       25043 :         struct smbXsrv_client *client = xconn->client;
     539       25043 :         struct smbXsrv_client_table *table = client->table;
     540       25043 :         struct GUID client_guid = xconn->smb2.client.guid;
     541       25043 :         struct smbXsrv_client_global0 *global = NULL;
     542       25043 :         bool is_free = false;
     543       25043 :         struct tevent_req *subreq = NULL;
     544         697 :         NTSTATUS status;
     545       25043 :         uint32_t seqnum = 0;
     546       25043 :         struct server_id last_server_id = { .pid = 0, };
     547             : 
     548       25043 :         SMB_ASSERT(state->db_rec == NULL);
     549       25043 :         state->db_rec = smbXsrv_client_global_fetch_locked(table->global.db_ctx,
     550             :                                                            &client_guid,
     551             :                                                            state);
     552       25043 :         if (state->db_rec == NULL) {
     553           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_DB_ERROR);
     554           0 :                 return;
     555             :         }
     556             : 
     557       25043 : verify_again:
     558       25043 :         TALLOC_FREE(global);
     559             : 
     560       25043 :         smbXsrv_client_global_verify_record(state->db_rec,
     561             :                                             &is_free,
     562             :                                             NULL,
     563             :                                             state,
     564             :                                             &last_server_id,
     565             :                                             &global,
     566             :                                             &seqnum);
     567       25043 :         if (is_free) {
     568       23836 :                 dbwrap_watched_watch_remove_instance(state->db_rec,
     569             :                                                      state->watch_instance);
     570       23836 :                 state->watch_instance = 0;
     571             : 
     572             :                 /*
     573             :                  * This stores the new client information in
     574             :                  * smbXsrv_client_global.tdb
     575             :                  */
     576       23836 :                 client->global->client_guid = xconn->smb2.client.guid;
     577             : 
     578       23836 :                 client->global->db_rec = state->db_rec;
     579       23836 :                 state->db_rec = NULL;
     580       23836 :                 status = smbXsrv_client_global_store(client->global);
     581       23836 :                 SMB_ASSERT(client->global->db_rec == NULL);
     582       23836 :                 if (!NT_STATUS_IS_OK(status)) {
     583           0 :                         struct GUID_txt_buf buf;
     584           0 :                         DBG_ERR("client_guid[%s] store failed - %s\n",
     585             :                                 GUID_buf_string(&client->global->client_guid,
     586             :                                                 &buf),
     587             :                                 nt_errstr(status));
     588           0 :                         tevent_req_nterror(req, status);
     589           0 :                         return;
     590             :                 }
     591             : 
     592       23836 :                 if (DEBUGLVL(DBGLVL_DEBUG)) {
     593           0 :                         struct smbXsrv_clientB client_blob = {
     594             :                                 .version = SMBXSRV_VERSION_0,
     595             :                                 .info.info0 = client,
     596             :                         };
     597           0 :                         struct GUID_txt_buf buf;
     598             : 
     599           0 :                         DBG_DEBUG("client_guid[%s] stored\n",
     600             :                                   GUID_buf_string(&client->global->client_guid,
     601             :                                                   &buf));
     602           0 :                         NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob);
     603             :                 }
     604             : 
     605       23836 :                 xconn->smb2.client.guid_verified = true;
     606       23836 :                 tevent_req_done(req);
     607       23836 :                 return;
     608             :         }
     609             : 
     610        1207 :         if (global == NULL) {
     611             :                 /*
     612             :                  * most likely ndr_pull_struct_blob() failed
     613             :                  */
     614           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_DB_CORRUPTION);
     615           0 :                 return;
     616             :         }
     617             : 
     618        1207 :         if (server_id_equal(&state->sent_server_id, &global->server_id)) {
     619             :                 /*
     620             :                  * We hit a race with other concurrent connections,
     621             :                  * which have woken us.
     622             :                  *
     623             :                  * We already sent the pass or drop message to
     624             :                  * the process, so we need to wait for a
     625             :                  * response and not pass the connection
     626             :                  * again! Otherwise the process would
     627             :                  * receive the same tcp connection via
     628             :                  * more than one file descriptor and
     629             :                  * create more than one smbXsrv_connection
     630             :                  * structure for the same tcp connection,
     631             :                  * which means the client would see more
     632             :                  * than one SMB2 negprot response to its
     633             :                  * single SMB2 netprot request and we
     634             :                  * as server get the session keys and
     635             :                  * message id validation wrong
     636             :                  */
     637          39 :                 goto watch_again;
     638             :         }
     639             : 
     640        1168 :         server_id_set_disconnected(&state->sent_server_id);
     641             : 
     642             :         /*
     643             :          * If last_server_id is set, we expect
     644             :          * smbXsrv_client_global_verify_record()
     645             :          * to detect the already dead global->server_id
     646             :          * as state->db_rec is still locked and its
     647             :          * value didn't change.
     648             :          */
     649        1168 :         SMB_ASSERT(last_server_id.pid == 0);
     650        1168 :         last_server_id = global->server_id;
     651             : 
     652        1168 :         TALLOC_FREE(state->filter_subreq);
     653        1168 :         if (procid_is_local(&global->server_id)) {
     654        1168 :                 subreq = messaging_filtered_read_send(state,
     655             :                                                       state->ev,
     656             :                                                       client->msg_ctx,
     657             :                                                       smb2srv_client_mc_negprot_filter,
     658             :                                                       NULL);
     659        1168 :                 if (tevent_req_nomem(subreq, req)) {
     660           0 :                         return;
     661             :                 }
     662        1168 :                 tevent_req_set_callback(subreq, smb2srv_client_mc_negprot_done, req);
     663        1168 :                 state->filter_subreq = subreq;
     664             :         }
     665             : 
     666        1168 :         if (procid_is_local(&global->server_id)) {
     667        1168 :                 status = smb2srv_client_connection_pass(state->smb2req,
     668             :                                                         global);
     669        1168 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
     670             :                         /*
     671             :                          * We remembered last_server_id = global->server_id
     672             :                          * above, so we'll treat it as dead in the
     673             :                          * next round to smbXsrv_client_global_verify_record().
     674             :                          */
     675           0 :                         goto verify_again;
     676             :                 }
     677        1168 :                 state->sent_server_id = global->server_id;
     678        1168 :                 if (tevent_req_nterror(req, status)) {
     679           0 :                         return;
     680             :                 }
     681             :         } else {
     682           0 :                 status = smb2srv_client_connection_drop(state->smb2req,
     683             :                                                         global);
     684           0 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
     685             :                         /*
     686             :                          * We remembered last_server_id = global->server_id
     687             :                          * above, so we'll treat it as dead in the
     688             :                          * next round to smbXsrv_client_global_verify_record().
     689             :                          */
     690           0 :                         goto verify_again;
     691             :                 }
     692           0 :                 state->sent_server_id = global->server_id;
     693           0 :                 if (tevent_req_nterror(req, status)) {
     694           0 :                         return;
     695             :                 }
     696             :         }
     697             : 
     698           0 : watch_again:
     699             : 
     700             :         /*
     701             :          * If the record changed, but we are not happy with the change yet,
     702             :          * we better remove ourself from the waiter list
     703             :          * (most likely the first position)
     704             :          * and re-add us at the end of the list.
     705             :          *
     706             :          * This gives other waiters a change
     707             :          * to make progress.
     708             :          *
     709             :          * Otherwise we'll keep our waiter instance alive,
     710             :          * keep waiting (most likely at first position).
     711             :          * It means the order of watchers stays fair.
     712             :          */
     713        1207 :         if (state->last_seqnum != seqnum) {
     714        1168 :                 state->last_seqnum = seqnum;
     715        1168 :                 dbwrap_watched_watch_remove_instance(state->db_rec,
     716             :                                                      state->watch_instance);
     717        1168 :                 state->watch_instance =
     718        1168 :                         dbwrap_watched_watch_add_instance(state->db_rec);
     719             :         }
     720             : 
     721        1207 :         subreq = dbwrap_watched_watch_send(state,
     722             :                                            state->ev,
     723             :                                            state->db_rec,
     724             :                                            state->watch_instance,
     725        1155 :                                            global->server_id);
     726        1207 :         if (tevent_req_nomem(subreq, req)) {
     727           0 :                 return;
     728             :         }
     729        1207 :         tevent_req_set_callback(subreq, smb2srv_client_mc_negprot_watched, req);
     730             : 
     731        1207 :         TALLOC_FREE(global);
     732        1207 :         TALLOC_FREE(state->db_rec);
     733        1155 :         return;
     734             : }
     735             : 
     736        1207 : static bool smb2srv_client_mc_negprot_filter(struct messaging_rec *rec, void *private_data)
     737             : {
     738        1207 :         if (rec->msg_type != MSG_SMBXSRV_CONNECTION_PASSED) {
     739          39 :                 return false;
     740             :         }
     741             : 
     742        1168 :         if (rec->num_fds != 0) {
     743           0 :                 return false;
     744             :         }
     745             : 
     746        1116 :         return true;
     747             : }
     748             : 
     749        1168 : static void smb2srv_client_mc_negprot_done(struct tevent_req *subreq)
     750             : {
     751          52 :         struct tevent_req *req =
     752        1168 :                 tevent_req_callback_data(subreq,
     753             :                 struct tevent_req);
     754          52 :         struct smb2srv_client_mc_negprot_state *state =
     755        1168 :                 tevent_req_data(req,
     756             :                 struct smb2srv_client_mc_negprot_state);
     757        1168 :         struct smbXsrv_connection *xconn = state->smb2req->xconn;
     758        1168 :         struct smbXsrv_client *client = xconn->client;
     759        1168 :         struct messaging_rec *rec = NULL;
     760          52 :         struct smbXsrv_connection_passB passed_blob;
     761          52 :         enum ndr_err_code ndr_err;
     762        1168 :         struct smbXsrv_connection_pass0 *passed_info0 = NULL;
     763          52 :         NTSTATUS status;
     764          52 :         int ret;
     765             : 
     766        1168 :         SMB_ASSERT(state->filter_subreq == subreq);
     767        1168 :         state->filter_subreq = NULL;
     768             : 
     769        1168 :         ret = messaging_filtered_read_recv(subreq, state, &rec);
     770        1168 :         TALLOC_FREE(subreq);
     771        1168 :         if (ret != 0) {
     772           0 :                 status = map_nt_error_from_unix_common(ret);
     773           0 :                 DBG_ERR("messaging_filtered_read_recv() - %s\n",
     774             :                         nt_errstr(status));
     775           0 :                 tevent_req_nterror(req, status);
     776           0 :                 return;
     777             :         }
     778             : 
     779        1168 :         DBG_DEBUG("MSG_SMBXSRV_CONNECTION_PASSED: received...\n");
     780             : 
     781        1168 :         ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &passed_blob,
     782             :                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_connection_passB);
     783        1168 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     784           0 :                 status = ndr_map_error2ntstatus(ndr_err);
     785           0 :                 DBG_ERR("ndr_pull_struct_blob - %s\n", nt_errstr(status));
     786           0 :                 tevent_req_nterror(req, status);
     787           0 :                 return;
     788             :         }
     789             : 
     790        1168 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
     791           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
     792             :         }
     793             : 
     794        1168 :         if (passed_blob.version != SMBXSRV_VERSION_0) {
     795           0 :                 DBG_ERR("ignore invalid version %u\n", passed_blob.version);
     796           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
     797           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     798           0 :                 return;
     799             :         }
     800             : 
     801        1168 :         passed_info0 = passed_blob.info.info0;
     802        1168 :         if (passed_info0 == NULL) {
     803           0 :                 DBG_ERR("ignore NULL info %u\n", passed_blob.version);
     804           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
     805           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     806           0 :                 return;
     807             :         }
     808             : 
     809        1168 :         if (!GUID_equal(&xconn->smb2.client.guid, &passed_info0->client_guid)) {
     810           0 :                 struct GUID_txt_buf buf1, buf2;
     811             : 
     812           0 :                 DBG_ERR("client's client_guid [%s] != passed guid [%s]\n",
     813             :                         GUID_buf_string(&xconn->smb2.client.guid,
     814             :                                         &buf1),
     815             :                         GUID_buf_string(&passed_info0->client_guid,
     816             :                                         &buf2));
     817           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
     818           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     819           0 :                 return;
     820             :         }
     821             : 
     822        1168 :         if (client->global->initial_connect_time !=
     823        1168 :             passed_info0->xconn_connect_time)
     824             :         {
     825           0 :                 DBG_ERR("client's initial connect time [%s] (%llu) != "
     826             :                         "passed xconn connect time [%s] (%llu)\n",
     827             :                         nt_time_string(talloc_tos(),
     828             :                                        client->global->initial_connect_time),
     829             :                         (unsigned long long)client->global->initial_connect_time,
     830             :                         nt_time_string(talloc_tos(),
     831             :                                        passed_info0->xconn_connect_time),
     832             :                         (unsigned long long)passed_info0->xconn_connect_time);
     833           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
     834           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     835           0 :                 return;
     836             :         }
     837             : 
     838        1168 :         if (passed_info0->negotiate_request.length != 0) {
     839           0 :                 DBG_ERR("negotiate_request.length[%zu]\n",
     840             :                         passed_info0->negotiate_request.length);
     841           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
     842           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     843           0 :                 return;
     844             :         }
     845             : 
     846        1168 :         tevent_req_nterror(req, NT_STATUS_MESSAGE_RETRIEVED);
     847             : }
     848             : 
     849          39 : static void smb2srv_client_mc_negprot_watched(struct tevent_req *subreq)
     850             : {
     851           0 :         struct tevent_req *req =
     852          39 :                 tevent_req_callback_data(subreq,
     853             :                 struct tevent_req);
     854           0 :         struct smb2srv_client_mc_negprot_state *state =
     855          39 :                 tevent_req_data(req,
     856             :                 struct smb2srv_client_mc_negprot_state);
     857           0 :         NTSTATUS status;
     858          39 :         uint64_t instance = 0;
     859             : 
     860          39 :         status = dbwrap_watched_watch_recv(subreq, &instance, NULL, NULL);
     861          39 :         TALLOC_FREE(subreq);
     862          39 :         if (tevent_req_nterror(req, status)) {
     863           0 :                 return;
     864             :         }
     865             : 
     866          39 :         state->watch_instance = instance;
     867             : 
     868          39 :         smb2srv_client_mc_negprot_next(req);
     869             : }
     870             : 
     871       25004 : NTSTATUS smb2srv_client_mc_negprot_recv(struct tevent_req *req)
     872             : {
     873       25004 :         return tevent_req_simple_recv_ntstatus(req);
     874             : }
     875             : 
     876       23834 : static NTSTATUS smbXsrv_client_global_remove(struct smbXsrv_client_global0 *global)
     877             : {
     878         645 :         TDB_DATA key;
     879         645 :         NTSTATUS status;
     880             : 
     881             :         /*
     882             :          * TODO: if we use other versions than '0'
     883             :          * we would add glue code here, that would be able to
     884             :          * store the information in the old format.
     885             :          */
     886             : 
     887       23834 :         if (global->db_rec == NULL) {
     888           0 :                 return NT_STATUS_INTERNAL_ERROR;
     889             :         }
     890             : 
     891       23834 :         key = dbwrap_record_get_key(global->db_rec);
     892             : 
     893       23834 :         status = dbwrap_record_delete(global->db_rec);
     894       23834 :         if (!NT_STATUS_IS_OK(status)) {
     895           0 :                 DBG_WARNING("key '%s' delete - %s\n",
     896             :                         tdb_data_dbg(key),
     897             :                         nt_errstr(status));
     898           0 :                 TALLOC_FREE(global->db_rec);
     899           0 :                 return status;
     900             :         }
     901       23834 :         global->stored = false;
     902       23834 :         DBG_DEBUG("key '%s' delete\n", tdb_data_dbg(key));
     903             : 
     904       23834 :         TALLOC_FREE(global->db_rec);
     905             : 
     906       23834 :         return NT_STATUS_OK;
     907             : }
     908             : 
     909       31549 : static int smbXsrv_client_destructor(struct smbXsrv_client *client)
     910             : {
     911         842 :         NTSTATUS status;
     912             : 
     913       31549 :         status = smbXsrv_client_remove(client);
     914       31549 :         if (!NT_STATUS_IS_OK(status)) {
     915           0 :                 DBG_ERR("smbXsrv_client_remove() failed: %s\n",
     916             :                         nt_errstr(status));
     917             :         }
     918             : 
     919       31549 :         TALLOC_FREE(client->global);
     920             : 
     921       31549 :         return 0;
     922             : }
     923             : 
     924             : static bool smbXsrv_client_connection_pass_filter(struct messaging_rec *rec, void *private_data);
     925             : static void smbXsrv_client_connection_pass_loop(struct tevent_req *subreq);
     926             : static bool smbXsrv_client_connection_drop_filter(struct messaging_rec *rec, void *private_data);
     927             : static void smbXsrv_client_connection_drop_loop(struct tevent_req *subreq);
     928             : 
     929       31563 : NTSTATUS smbXsrv_client_create(TALLOC_CTX *mem_ctx,
     930             :                                struct tevent_context *ev_ctx,
     931             :                                struct messaging_context *msg_ctx,
     932             :                                NTTIME now,
     933             :                                struct smbXsrv_client **_client)
     934             : {
     935         842 :         struct smbXsrv_client_table *table;
     936       31563 :         struct smbXsrv_client *client = NULL;
     937       31563 :         struct smbXsrv_client_global0 *global = NULL;
     938         842 :         NTSTATUS status;
     939       31563 :         struct tevent_req *subreq = NULL;
     940             : 
     941       31563 :         status = smbXsrv_client_table_create(mem_ctx,
     942             :                                              msg_ctx,
     943             :                                              1, /* max_clients */
     944             :                                              &table);
     945       31563 :         if (!NT_STATUS_IS_OK(status)) {
     946           0 :                 return status;
     947             :         }
     948             : 
     949       31563 :         if (table->local.num_clients >= table->local.max_clients) {
     950           0 :                 TALLOC_FREE(table);
     951           0 :                 return NT_STATUS_INSUFFICIENT_RESOURCES;
     952             :         }
     953             : 
     954       31563 :         client = talloc_zero(mem_ctx, struct smbXsrv_client);
     955       31563 :         if (client == NULL) {
     956           0 :                 TALLOC_FREE(table);
     957           0 :                 return NT_STATUS_NO_MEMORY;
     958             :         }
     959       31563 :         client->raw_ev_ctx = ev_ctx;
     960       31563 :         client->msg_ctx = msg_ctx;
     961             : 
     962       32405 :         client->server_multi_channel_enabled =
     963       31563 :                 smbXsrv_server_multi_channel_enabled();
     964       31563 :         if (client->server_multi_channel_enabled) {
     965       31563 :                 client->next_channel_id = 1;
     966             :         }
     967       31563 :         client->table = talloc_move(client, &table);
     968       31563 :         table = client->table;
     969             : 
     970       31563 :         global = talloc_zero(client, struct smbXsrv_client_global0);
     971       31563 :         if (global == NULL) {
     972           0 :                 TALLOC_FREE(client);
     973           0 :                 return NT_STATUS_NO_MEMORY;
     974             :         }
     975       31563 :         talloc_set_destructor(global, smbXsrv_client_global_destructor);
     976       31563 :         client->global = global;
     977             : 
     978       31563 :         global->initial_connect_time = now;
     979             : 
     980       31563 :         global->server_id = messaging_server_id(client->msg_ctx);
     981             : 
     982       31563 :         table->local.num_clients += 1;
     983             : 
     984       31563 :         talloc_set_destructor(client, smbXsrv_client_destructor);
     985             : 
     986       31563 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
     987           0 :                 struct smbXsrv_clientB client_blob = {
     988             :                         .version = SMBXSRV_VERSION_0,
     989             :                         .info.info0 = client,
     990             :                 };
     991           0 :                 struct GUID_txt_buf buf;
     992             : 
     993           0 :                 DBG_DEBUG("client_guid[%s] created\n",
     994             :                           GUID_buf_string(&global->client_guid, &buf));
     995           0 :                 NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob);
     996             :         }
     997             : 
     998       31563 :         subreq = messaging_filtered_read_send(client,
     999             :                                         client->raw_ev_ctx,
    1000             :                                         client->msg_ctx,
    1001             :                                         smbXsrv_client_connection_pass_filter,
    1002             :                                         client);
    1003       31563 :         if (subreq == NULL) {
    1004           0 :                 TALLOC_FREE(client);
    1005           0 :                 return NT_STATUS_NO_MEMORY;
    1006             :         }
    1007       31563 :         tevent_req_set_callback(subreq, smbXsrv_client_connection_pass_loop, client);
    1008       31563 :         client->connection_pass_subreq = subreq;
    1009             : 
    1010       31563 :         subreq = messaging_filtered_read_send(client,
    1011             :                                         client->raw_ev_ctx,
    1012             :                                         client->msg_ctx,
    1013             :                                         smbXsrv_client_connection_drop_filter,
    1014             :                                         client);
    1015       31563 :         if (subreq == NULL) {
    1016           0 :                 TALLOC_FREE(client);
    1017           0 :                 return NT_STATUS_NO_MEMORY;
    1018             :         }
    1019       31563 :         tevent_req_set_callback(subreq, smbXsrv_client_connection_drop_loop, client);
    1020       31563 :         client->connection_drop_subreq = subreq;
    1021             : 
    1022       31563 :         *_client = client;
    1023       31563 :         return NT_STATUS_OK;
    1024             : }
    1025             : 
    1026        1106 : static NTSTATUS smb2srv_client_connection_passed(struct smbXsrv_client *client,
    1027             :                                 const struct smbXsrv_connection_pass0 *recv_info0)
    1028             : {
    1029          52 :         DATA_BLOB blob;
    1030          52 :         enum ndr_err_code ndr_err;
    1031          52 :         NTSTATUS status;
    1032          52 :         struct smbXsrv_connection_pass0 passed_info0;
    1033          52 :         struct smbXsrv_connection_passB passed_blob;
    1034          52 :         struct iovec iov;
    1035             : 
    1036             :         /*
    1037             :          * We echo back the message with a cleared negotiate_request
    1038             :          */
    1039        1106 :         passed_info0 = *recv_info0;
    1040        1106 :         passed_info0.negotiate_request = data_blob_null;
    1041             : 
    1042        1106 :         ZERO_STRUCT(passed_blob);
    1043        1106 :         passed_blob.version = smbXsrv_version_global_current();
    1044        1106 :         passed_blob.info.info0 = &passed_info0;
    1045             : 
    1046        1106 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
    1047           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &passed_blob);
    1048             :         }
    1049             : 
    1050        1106 :         ndr_err = ndr_push_struct_blob(&blob, talloc_tos(), &passed_blob,
    1051             :                         (ndr_push_flags_fn_t)ndr_push_smbXsrv_connection_passB);
    1052        1106 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1053           0 :                 status = ndr_map_error2ntstatus(ndr_err);
    1054           0 :                 return status;
    1055             :         }
    1056             : 
    1057        1106 :         iov.iov_base = blob.data;
    1058        1106 :         iov.iov_len = blob.length;
    1059             : 
    1060        1106 :         status = messaging_send_iov(client->msg_ctx,
    1061             :                                     recv_info0->src_server_id,
    1062             :                                     MSG_SMBXSRV_CONNECTION_PASSED,
    1063             :                                     &iov, 1,
    1064             :                                     NULL, 0);
    1065        1106 :         data_blob_free(&blob);
    1066        1106 :         if (!NT_STATUS_IS_OK(status)) {
    1067           0 :                 return status;
    1068             :         }
    1069             : 
    1070        1106 :         return NT_STATUS_OK;
    1071             : }
    1072             : 
    1073       25700 : static bool smbXsrv_client_connection_pass_filter(struct messaging_rec *rec, void *private_data)
    1074             : {
    1075       25700 :         if (rec->msg_type != MSG_SMBXSRV_CONNECTION_PASS) {
    1076       24528 :                 return false;
    1077             :         }
    1078             : 
    1079        1106 :         if (rec->num_fds != 1) {
    1080           0 :                 return false;
    1081             :         }
    1082             : 
    1083        1054 :         return true;
    1084             : }
    1085             : 
    1086        1106 : static void smbXsrv_client_connection_pass_loop(struct tevent_req *subreq)
    1087             : {
    1088          52 :         struct smbXsrv_client *client =
    1089        1106 :                 tevent_req_callback_data(subreq,
    1090             :                 struct smbXsrv_client);
    1091        1106 :         struct smbXsrv_connection *xconn = NULL;
    1092          52 :         int ret;
    1093        1106 :         struct messaging_rec *rec = NULL;
    1094          52 :         struct smbXsrv_connection_passB pass_blob;
    1095          52 :         enum ndr_err_code ndr_err;
    1096        1106 :         struct smbXsrv_connection_pass0 *pass_info0 = NULL;
    1097          52 :         NTSTATUS status;
    1098        1106 :         int sock_fd = -1;
    1099          52 :         uint64_t seq_low;
    1100             : 
    1101        1106 :         client->connection_pass_subreq = NULL;
    1102             : 
    1103        1106 :         ret = messaging_filtered_read_recv(subreq, talloc_tos(), &rec);
    1104        1106 :         TALLOC_FREE(subreq);
    1105        1106 :         if (ret != 0) {
    1106           0 :                 goto next;
    1107             :         }
    1108             : 
    1109        1106 :         if (rec->num_fds != 1) {
    1110           0 :                 DBG_ERR("MSG_SMBXSRV_CONNECTION_PASS: num_fds[%u]\n",
    1111             :                         rec->num_fds);
    1112           0 :                 goto next;
    1113             :         }
    1114             : 
    1115        1106 :         sock_fd = rec->fds[0];
    1116        1106 :         DBG_DEBUG("MSG_SMBXSRV_CONNECTION_PASS: got sock_fd[%d]\n", sock_fd);
    1117             : 
    1118        1106 :         ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &pass_blob,
    1119             :                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_connection_passB);
    1120        1106 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1121           0 :                 status = ndr_map_error2ntstatus(ndr_err);
    1122           0 :                 DBG_WARNING("ndr_pull_struct_blob - %s\n", nt_errstr(status));
    1123           0 :                 goto next;
    1124             :         }
    1125             : 
    1126        1106 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
    1127           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
    1128             :         }
    1129             : 
    1130        1106 :         if (pass_blob.version != SMBXSRV_VERSION_0) {
    1131           0 :                 DBG_ERR("ignore invalid version %u\n", pass_blob.version);
    1132           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
    1133           0 :                 goto next;
    1134             :         }
    1135             : 
    1136        1106 :         pass_info0 = pass_blob.info.info0;
    1137        1106 :         if (pass_info0 == NULL) {
    1138           0 :                 DBG_ERR("ignore NULL info %u\n", pass_blob.version);
    1139           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
    1140           0 :                 goto next;
    1141             :         }
    1142             : 
    1143        1106 :         if (!GUID_equal(&client->global->client_guid, &pass_info0->client_guid))
    1144             :         {
    1145           0 :                 struct GUID_txt_buf buf1, buf2;
    1146             : 
    1147           0 :                 DBG_WARNING("client's client_guid [%s] != passed guid [%s]\n",
    1148             :                             GUID_buf_string(&client->global->client_guid,
    1149             :                                             &buf1),
    1150             :                             GUID_buf_string(&pass_info0->client_guid,
    1151             :                                             &buf2));
    1152           0 :                 if (DEBUGLVL(DBGLVL_WARNING)) {
    1153           0 :                         NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
    1154             :                 }
    1155           0 :                 goto next;
    1156             :         }
    1157             : 
    1158        1106 :         if (client->global->initial_connect_time !=
    1159        1106 :             pass_info0->client_connect_time)
    1160             :         {
    1161           0 :                 DBG_WARNING("client's initial connect time [%s] (%llu) != "
    1162             :                         "passed initial connect time [%s] (%llu)\n",
    1163             :                         nt_time_string(talloc_tos(),
    1164             :                                        client->global->initial_connect_time),
    1165             :                         (unsigned long long)client->global->initial_connect_time,
    1166             :                         nt_time_string(talloc_tos(),
    1167             :                                        pass_info0->client_connect_time),
    1168             :                         (unsigned long long)pass_info0->client_connect_time);
    1169           0 :                 if (DEBUGLVL(DBGLVL_WARNING)) {
    1170           0 :                         NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
    1171             :                 }
    1172           0 :                 goto next;
    1173             :         }
    1174             : 
    1175        1106 :         if (pass_info0->negotiate_request.length < SMB2_HDR_BODY) {
    1176           0 :                 DBG_WARNING("negotiate_request.length[%zu]\n",
    1177             :                             pass_info0->negotiate_request.length);
    1178           0 :                 if (DEBUGLVL(DBGLVL_WARNING)) {
    1179           0 :                         NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
    1180             :                 }
    1181           0 :                 goto next;
    1182             :         }
    1183             : 
    1184        1106 :         status = smb2srv_client_connection_passed(client, pass_info0);
    1185        1106 :         if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
    1186             :                 /*
    1187             :                  * We hit a race where, the client dropped the connection
    1188             :                  * while the socket was passed to us and the origin
    1189             :                  * process already existed.
    1190             :                  */
    1191           0 :                 DBG_DEBUG("smb2srv_client_connection_passed() ignore %s\n",
    1192             :                           nt_errstr(status));
    1193           0 :                 status = NT_STATUS_OK;
    1194             :         }
    1195        1106 :         if (!NT_STATUS_IS_OK(status)) {
    1196           0 :                 const char *r = "smb2srv_client_connection_passed() failed";
    1197           0 :                 DBG_ERR("%s => %s\n", r, nt_errstr(status));
    1198           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
    1199           0 :                 exit_server_cleanly(r);
    1200             :                 return;
    1201             :         }
    1202             : 
    1203        1106 :         status = smbd_add_connection(client,
    1204             :                                      sock_fd,
    1205             :                                      pass_info0->xconn_connect_time,
    1206             :                                      &xconn);
    1207        1106 :         if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
    1208           0 :                 rec->num_fds = 0;
    1209           0 :                 smbd_server_connection_terminate(xconn, nt_errstr(status));
    1210             :         }
    1211        1106 :         if (!NT_STATUS_IS_OK(status)) {
    1212           0 :                 DBG_ERR("smbd_add_connection => %s\n", nt_errstr(status));
    1213           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_passB, &pass_blob);
    1214           0 :                 goto next;
    1215             :         }
    1216        1106 :         rec->num_fds = 0;
    1217             : 
    1218             :         /*
    1219             :          * Set seq_low to mid received in negprot
    1220             :          */
    1221        1106 :         seq_low = BVAL(pass_info0->negotiate_request.data,
    1222             :                        SMB2_HDR_MESSAGE_ID);
    1223             : 
    1224        1106 :         xconn->smb2.client.guid_verified = true;
    1225        1106 :         smbd_smb2_process_negprot(xconn, seq_low,
    1226        1054 :                                   pass_info0->negotiate_request.data,
    1227             :                                   pass_info0->negotiate_request.length);
    1228             : 
    1229        1106 : next:
    1230        1106 :         if (rec != NULL) {
    1231             :                 uint8_t fd_idx;
    1232             : 
    1233        1106 :                 for (fd_idx = 0; fd_idx < rec->num_fds; fd_idx++) {
    1234           0 :                         sock_fd = rec->fds[fd_idx];
    1235           0 :                         close(sock_fd);
    1236             :                 }
    1237        1106 :                 rec->num_fds = 0;
    1238             : 
    1239        1106 :                 TALLOC_FREE(rec);
    1240             :         }
    1241             : 
    1242        1106 :         subreq = messaging_filtered_read_send(client,
    1243             :                                         client->raw_ev_ctx,
    1244             :                                         client->msg_ctx,
    1245             :                                         smbXsrv_client_connection_pass_filter,
    1246             :                                         client);
    1247        1106 :         if (subreq == NULL) {
    1248           0 :                 const char *r;
    1249           0 :                 r = "messaging_read_send(MSG_SMBXSRV_CONNECTION_PASS failed";
    1250           0 :                 exit_server_cleanly(r);
    1251             :                 return;
    1252             :         }
    1253        1106 :         tevent_req_set_callback(subreq, smbXsrv_client_connection_pass_loop, client);
    1254        1106 :         client->connection_pass_subreq = subreq;
    1255             : }
    1256             : 
    1257       25304 : static bool smbXsrv_client_connection_drop_filter(struct messaging_rec *rec, void *private_data)
    1258             : {
    1259       25304 :         if (rec->msg_type != MSG_SMBXSRV_CONNECTION_DROP) {
    1260       25234 :                 return false;
    1261             :         }
    1262             : 
    1263           0 :         if (rec->num_fds != 0) {
    1264           0 :                 return false;
    1265             :         }
    1266             : 
    1267           0 :         return true;
    1268             : }
    1269             : 
    1270           0 : static void smbXsrv_client_connection_drop_loop(struct tevent_req *subreq)
    1271             : {
    1272           0 :         struct smbXsrv_client *client =
    1273           0 :                 tevent_req_callback_data(subreq,
    1274             :                 struct smbXsrv_client);
    1275           0 :         int ret;
    1276           0 :         struct messaging_rec *rec = NULL;
    1277           0 :         struct smbXsrv_connection_dropB drop_blob;
    1278           0 :         enum ndr_err_code ndr_err;
    1279           0 :         struct smbXsrv_connection_drop0 *drop_info0 = NULL;
    1280           0 :         struct server_id_buf src_server_id_buf = {};
    1281           0 :         NTSTATUS status;
    1282             : 
    1283           0 :         client->connection_drop_subreq = NULL;
    1284             : 
    1285           0 :         ret = messaging_filtered_read_recv(subreq, talloc_tos(), &rec);
    1286           0 :         TALLOC_FREE(subreq);
    1287           0 :         if (ret != 0) {
    1288           0 :                 goto next;
    1289             :         }
    1290             : 
    1291           0 :         if (rec->num_fds != 0) {
    1292           0 :                 DBG_ERR("MSG_SMBXSRV_CONNECTION_DROP: num_fds[%u]\n",
    1293             :                         rec->num_fds);
    1294           0 :                 goto next;
    1295             :         }
    1296             : 
    1297           0 :         ndr_err = ndr_pull_struct_blob(&rec->buf, rec, &drop_blob,
    1298             :                         (ndr_pull_flags_fn_t)ndr_pull_smbXsrv_connection_dropB);
    1299           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1300           0 :                 status = ndr_map_error2ntstatus(ndr_err);
    1301           0 :                 DBG_WARNING("ndr_pull_struct_blob - %s\n", nt_errstr(status));
    1302           0 :                 goto next;
    1303             :         }
    1304             : 
    1305           0 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
    1306           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_dropB, &drop_blob);
    1307             :         }
    1308             : 
    1309           0 :         if (drop_blob.version != SMBXSRV_VERSION_0) {
    1310           0 :                 DBG_ERR("ignore invalid version %u\n", drop_blob.version);
    1311           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_dropB, &drop_blob);
    1312           0 :                 goto next;
    1313             :         }
    1314             : 
    1315           0 :         drop_info0 = drop_blob.info.info0;
    1316           0 :         if (drop_info0 == NULL) {
    1317           0 :                 DBG_ERR("ignore NULL info %u\n", drop_blob.version);
    1318           0 :                 NDR_PRINT_DEBUG(smbXsrv_connection_dropB, &drop_blob);
    1319           0 :                 goto next;
    1320             :         }
    1321             : 
    1322           0 :         if (!GUID_equal(&client->global->client_guid, &drop_info0->client_guid))
    1323             :         {
    1324           0 :                 struct GUID_txt_buf buf1, buf2;
    1325             : 
    1326           0 :                 DBG_WARNING("client's client_guid [%s] != dropped guid [%s]\n",
    1327             :                             GUID_buf_string(&client->global->client_guid,
    1328             :                                             &buf1),
    1329             :                             GUID_buf_string(&drop_info0->client_guid,
    1330             :                                             &buf2));
    1331           0 :                 if (DEBUGLVL(DBGLVL_WARNING)) {
    1332           0 :                         NDR_PRINT_DEBUG(smbXsrv_connection_dropB, &drop_blob);
    1333             :                 }
    1334           0 :                 goto next;
    1335             :         }
    1336             : 
    1337           0 :         if (client->global->initial_connect_time !=
    1338           0 :             drop_info0->client_connect_time)
    1339             :         {
    1340           0 :                 DBG_WARNING("client's initial connect time [%s] (%llu) != "
    1341             :                         "dropped initial connect time [%s] (%llu)\n",
    1342             :                         nt_time_string(talloc_tos(),
    1343             :                                        client->global->initial_connect_time),
    1344             :                         (unsigned long long)client->global->initial_connect_time,
    1345             :                         nt_time_string(talloc_tos(),
    1346             :                                        drop_info0->client_connect_time),
    1347             :                         (unsigned long long)drop_info0->client_connect_time);
    1348           0 :                 if (DEBUGLVL(DBGLVL_WARNING)) {
    1349           0 :                         NDR_PRINT_DEBUG(smbXsrv_connection_dropB, &drop_blob);
    1350             :                 }
    1351           0 :                 goto next;
    1352             :         }
    1353             : 
    1354             :         /*
    1355             :          * Disconnect all client connections, which means we will tear down all
    1356             :          * sessions, tcons and non-durable opens. At the end we will remove our
    1357             :          * smbXsrv_client_global.tdb record, which will wake up the watcher on
    1358             :          * the other node in order to let it take over the client.
    1359             :          *
    1360             :          * The client will have to reopen all sessions, tcons and durable opens.
    1361             :          */
    1362           0 :         smbd_server_disconnect_client(client,
    1363             :                 server_id_str_buf(drop_info0->src_server_id, &src_server_id_buf));
    1364           0 :         return;
    1365             : 
    1366           0 : next:
    1367           0 :         if (rec != NULL) {
    1368             :                 int sock_fd;
    1369             :                 uint8_t fd_idx;
    1370             : 
    1371           0 :                 for (fd_idx = 0; fd_idx < rec->num_fds; fd_idx++) {
    1372           0 :                         sock_fd = rec->fds[fd_idx];
    1373           0 :                         close(sock_fd);
    1374             :                 }
    1375           0 :                 rec->num_fds = 0;
    1376             : 
    1377           0 :                 TALLOC_FREE(rec);
    1378             :         }
    1379             : 
    1380           0 :         subreq = messaging_filtered_read_send(client,
    1381             :                                         client->raw_ev_ctx,
    1382             :                                         client->msg_ctx,
    1383             :                                         smbXsrv_client_connection_drop_filter,
    1384             :                                         client);
    1385           0 :         if (subreq == NULL) {
    1386           0 :                 const char *r;
    1387           0 :                 r = "messaging_read_send(MSG_SMBXSRV_CONNECTION_DROP failed";
    1388           0 :                 exit_server_cleanly(r);
    1389             :                 return;
    1390             :         }
    1391           0 :         tevent_req_set_callback(subreq, smbXsrv_client_connection_drop_loop, client);
    1392           0 :         client->connection_drop_subreq = subreq;
    1393             : }
    1394             : 
    1395       63098 : NTSTATUS smbXsrv_client_remove(struct smbXsrv_client *client)
    1396             : {
    1397       63098 :         struct smbXsrv_client_table *table = client->table;
    1398        1684 :         NTSTATUS status;
    1399             : 
    1400       63098 :         if (client->global->db_rec != NULL) {
    1401           0 :                 struct GUID_txt_buf buf;
    1402           0 :                 DBG_ERR("client_guid[%s]: Called with db_rec != NULL'\n",
    1403             :                         GUID_buf_string(&client->global->client_guid,
    1404             :                                         &buf));
    1405           0 :                 return NT_STATUS_INTERNAL_ERROR;
    1406             :         }
    1407             : 
    1408       63098 :         if (!client->global->stored) {
    1409       39264 :                 return NT_STATUS_OK;
    1410             :         }
    1411             : 
    1412       23834 :         TALLOC_FREE(client->connection_pass_subreq);
    1413       23834 :         TALLOC_FREE(client->connection_drop_subreq);
    1414             : 
    1415       47668 :         client->global->db_rec = smbXsrv_client_global_fetch_locked(
    1416             :                                         table->global.db_ctx,
    1417       23834 :                                         &client->global->client_guid,
    1418       23834 :                                         client->global /* TALLOC_CTX */);
    1419       23834 :         if (client->global->db_rec == NULL) {
    1420           0 :                 return NT_STATUS_INTERNAL_DB_ERROR;
    1421             :         }
    1422             : 
    1423       23834 :         status = smbXsrv_client_global_remove(client->global);
    1424       23834 :         if (!NT_STATUS_IS_OK(status)) {
    1425           0 :                 struct GUID_txt_buf buf;
    1426           0 :                 DBG_ERR("client_guid[%s] store failed - %s\n",
    1427             :                         GUID_buf_string(&client->global->client_guid, &buf),
    1428             :                         nt_errstr(status));
    1429           0 :                 return status;
    1430             :         }
    1431             : 
    1432       23834 :         if (DEBUGLVL(DBGLVL_DEBUG)) {
    1433           0 :                 struct smbXsrv_clientB client_blob = {
    1434             :                         .version = SMBXSRV_VERSION_0,
    1435             :                         .info.info0 = client,
    1436             :                 };
    1437           0 :                 struct GUID_txt_buf buf;
    1438             : 
    1439           0 :                 DBG_DEBUG("client_guid[%s] stored\n",
    1440             :                           GUID_buf_string(&client->global->client_guid, &buf));
    1441           0 :                 NDR_PRINT_DEBUG(smbXsrv_clientB, &client_blob);
    1442             :         }
    1443             : 
    1444       23834 :         return NT_STATUS_OK;
    1445             : }

Generated by: LCOV version 1.14