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

Generated by: LCOV version 1.14