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

Generated by: LCOV version 1.14