Coverage Report

Created: 2025-07-23 07:04

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