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

Generated by: LCOV version 1.14