Coverage Report

Created: 2026-07-25 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/samba/source3/smbd/durable.c
Line
Count
Source
1
/*
2
   Unix SMB/CIFS implementation.
3
   Durable Handle default VFS implementation
4
5
   Copyright (C) Stefan Metzmacher 2012
6
   Copyright (C) Michael Adam 2012
7
   Copyright (C) Volker Lendecke 2012
8
9
   This program is free software; you can redistribute it and/or modify
10
   it under the terms of the GNU General Public License as published by
11
   the Free Software Foundation; either version 3 of the License, or
12
   (at your option) any later version.
13
14
   This program is distributed in the hope that it will be useful,
15
   but WITHOUT ANY WARRANTY; without even the implied warranty of
16
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
   GNU General Public License for more details.
18
19
   You should have received a copy of the GNU General Public License
20
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
*/
22
23
#include "includes.h"
24
#include "system/filesys.h"
25
#include "lib/util/server_id.h"
26
#include "locking/share_mode_lock.h"
27
#include "smbd/smbd.h"
28
#include "smbd/globals.h"
29
#include "libcli/security/security.h"
30
#include "messages.h"
31
#include "librpc/gen_ndr/ndr_open_files.h"
32
#include "serverid.h"
33
#include "fake_file.h"
34
#include "locking/leases_db.h"
35
36
NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
37
            TALLOC_CTX *mem_ctx,
38
            DATA_BLOB *cookie_blob)
39
0
{
40
0
  struct connection_struct *conn = fsp->conn;
41
0
  enum ndr_err_code ndr_err;
42
0
  struct vfs_default_durable_cookie cookie;
43
44
0
  if (!lp_durable_handles(SNUM(conn))) {
45
0
    return NT_STATUS_NOT_SUPPORTED;
46
0
  }
47
48
0
  if (lp_kernel_share_modes(SNUM(conn))) {
49
    /*
50
     * We do not support durable handles
51
     * if file system sharemodes are used
52
     */
53
0
    return NT_STATUS_NOT_SUPPORTED;
54
0
  }
55
56
0
  if (lp_kernel_oplocks(SNUM(conn))) {
57
    /*
58
     * We do not support durable handles
59
     * if kernel oplocks are used
60
     */
61
0
    return NT_STATUS_NOT_SUPPORTED;
62
0
  }
63
64
0
  if ((fsp->current_lock_count > 0) &&
65
0
      lp_posix_locking(fsp->conn->params))
66
0
  {
67
    /*
68
     * We do not support durable handles
69
     * if the handle has posix locks.
70
     */
71
0
    return NT_STATUS_NOT_SUPPORTED;
72
0
  }
73
74
0
  if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
75
    /* We only support Durable Handles on regular files ... */
76
0
    if (!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
77
0
      return NT_STATUS_NOT_SUPPORTED;
78
0
    }
79
    /* ... but we do support Persistent Handles on directories */
80
0
    if (!fsp->op->global->persistent) {
81
0
      return NT_STATUS_NOT_SUPPORTED;
82
0
    }
83
0
  }
84
85
0
  if (fsp_is_alternate_stream(fsp)) {
86
    /*
87
     * We do not support durable handles
88
     * on streams for now.
89
     */
90
0
    return NT_STATUS_NOT_SUPPORTED;
91
0
  }
92
93
0
  if (is_fake_file(fsp->fsp_name)) {
94
    /*
95
     * We do not support durable handles
96
     * on fake files.
97
     */
98
0
    return NT_STATUS_NOT_SUPPORTED;
99
0
  }
100
101
0
  ZERO_STRUCT(cookie);
102
0
  cookie.id = fsp->file_id;
103
0
  cookie.servicepath = conn->connectpath;
104
0
  cookie.base_name = fsp->fsp_name->base_name;
105
0
  cookie.initial_allocation_size = fsp->initial_allocation_size;
106
0
  cookie.position_information = fh_get_position_information(fsp->fh);
107
0
  cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
108
0
  if (fsp->op->global->persistent) {
109
0
    cookie.initial_delete_on_close =
110
0
      fsp->fsp_flags.initial_delete_on_close;
111
0
  }
112
113
0
  cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
114
0
  cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
115
0
  cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
116
0
  cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
117
0
  cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
118
0
  cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
119
0
  cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
120
0
  cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
121
0
  cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
122
0
  cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
123
0
  cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
124
0
  cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
125
0
  cookie.stat_info.st_ex_iflags = fsp->fsp_name->st.st_ex_iflags;
126
0
  cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
127
0
  cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
128
0
  cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
129
130
0
  if (fsp->op->global->persistent) {
131
0
    cookie.allow_reconnect = true;
132
0
  }
133
134
0
  if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
135
0
    DBG_DEBUG("Fresh cookie\n");
136
0
    NDR_PRINT_DEBUG(vfs_default_durable_cookie, &cookie);
137
0
  }
138
139
0
  ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
140
0
      (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
141
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
142
0
    NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
143
0
    return status;
144
0
  }
145
146
0
  return NT_STATUS_OK;
147
0
}
148
149
struct durable_disconnect_state {
150
  NTSTATUS status;
151
  struct files_struct *fsp;
152
};
153
154
static void default_durable_disconnect_fn(struct share_mode_lock *lck,
155
            struct byte_range_lock *br_lck,
156
            void *private_data)
157
0
{
158
0
  struct durable_disconnect_state *state = private_data;
159
0
  struct files_struct *fsp = state->fsp;
160
0
  bool ok;
161
162
0
  ok = mark_share_mode_disconnected(lck, fsp);
163
0
  if (!ok) {
164
0
    state->status = NT_STATUS_UNSUCCESSFUL;
165
0
    return;
166
0
  }
167
168
0
  if (br_lck == NULL) {
169
0
    state->status = NT_STATUS_OK;
170
0
    return;
171
0
  }
172
173
0
  ok = brl_mark_disconnected(fsp, br_lck);
174
0
  if (!ok) {
175
0
    state->status = NT_STATUS_UNSUCCESSFUL;
176
0
    return;
177
0
  }
178
0
  state->status = NT_STATUS_OK;
179
0
}
180
181
NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
182
          const DATA_BLOB old_cookie,
183
          TALLOC_CTX *mem_ctx,
184
          DATA_BLOB *new_cookie)
185
0
{
186
0
  struct connection_struct *conn = fsp->conn;
187
0
  NTSTATUS status;
188
0
  enum ndr_err_code ndr_err;
189
0
  struct vfs_default_durable_cookie cookie;
190
0
  DATA_BLOB new_cookie_blob = data_blob_null;
191
0
  struct durable_disconnect_state state;
192
193
0
  *new_cookie = data_blob_null;
194
195
0
  ZERO_STRUCT(cookie);
196
197
0
  ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
198
0
      (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
199
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
200
0
    status = ndr_map_error2ntstatus(ndr_err);
201
0
    return status;
202
0
  }
203
204
0
  if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
205
0
    DBG_DEBUG("Old cookie\n");
206
0
    NDR_PRINT_DEBUG(vfs_default_durable_cookie, &cookie);
207
0
  }
208
209
0
  if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
210
0
    return NT_STATUS_INVALID_PARAMETER;
211
0
  }
212
213
0
  if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
214
0
    return NT_STATUS_INVALID_PARAMETER;
215
0
  }
216
217
0
  if (!file_id_equal(&fsp->file_id, &cookie.id)) {
218
0
    return NT_STATUS_INVALID_PARAMETER;
219
0
  }
220
221
0
  if (fsp->op->global->persistent) {
222
0
    new_cookie_blob = data_blob_dup_talloc(mem_ctx, old_cookie);
223
0
    if (new_cookie_blob.data == NULL) {
224
0
      return NT_STATUS_NO_MEMORY;
225
0
    }
226
0
    goto do_close;
227
0
  }
228
229
0
  if ((fsp_lease_type(fsp) & SMB2_LEASE_HANDLE) == 0) {
230
0
    return NT_STATUS_NOT_SUPPORTED;
231
0
  }
232
233
0
  if (fsp->current_lock_count != 0 &&
234
0
      (fsp_lease_type(fsp) & SMB2_LEASE_WRITE) == 0)
235
0
  {
236
0
    return NT_STATUS_NOT_SUPPORTED;
237
0
  }
238
239
  /*
240
   * For now let it be simple and do not keep
241
   * delete on close files durable open
242
   */
243
0
  if (fsp->fsp_flags.initial_delete_on_close) {
244
0
    return NT_STATUS_NOT_SUPPORTED;
245
0
  }
246
0
  if (fsp->fsp_flags.delete_on_close) {
247
0
    return NT_STATUS_NOT_SUPPORTED;
248
0
  }
249
250
0
  if (!VALID_STAT(fsp->fsp_name->st)) {
251
0
    return NT_STATUS_NOT_SUPPORTED;
252
0
  }
253
254
0
  if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
255
0
    return NT_STATUS_NOT_SUPPORTED;
256
0
  }
257
258
0
  state = (struct durable_disconnect_state) {
259
0
    .fsp = fsp,
260
0
  };
261
262
0
  status = share_mode_do_locked_brl(fsp,
263
0
            default_durable_disconnect_fn,
264
0
            &state);
265
0
  if (!NT_STATUS_IS_OK(status)) {
266
0
    DBG_ERR("share_mode_do_locked_brl [%s] failed: %s\n",
267
0
      fsp_str_dbg(fsp), nt_errstr(status));
268
0
    return status;
269
0
  }
270
0
  if (!NT_STATUS_IS_OK(state.status)) {
271
0
    DBG_ERR("default_durable_disconnect_fn [%s] failed: %s\n",
272
0
      fsp_str_dbg(fsp), nt_errstr(state.status));
273
0
    return state.status;
274
0
  }
275
276
0
  status = vfs_stat_fsp(fsp);
277
0
  if (!NT_STATUS_IS_OK(status)) {
278
0
    return status;
279
0
  }
280
281
0
  ZERO_STRUCT(cookie);
282
0
  cookie.allow_reconnect = true;
283
0
  cookie.id = fsp->file_id;
284
0
  cookie.servicepath = conn->connectpath;
285
0
  cookie.base_name = fsp_str_dbg(fsp);
286
0
  cookie.initial_allocation_size = fsp->initial_allocation_size;
287
0
  cookie.position_information = fh_get_position_information(fsp->fh);
288
0
  cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
289
290
0
  cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
291
0
  cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
292
0
  cookie.stat_info.st_ex_mode = fsp->fsp_name->st.st_ex_mode;
293
0
  cookie.stat_info.st_ex_nlink = fsp->fsp_name->st.st_ex_nlink;
294
0
  cookie.stat_info.st_ex_uid = fsp->fsp_name->st.st_ex_uid;
295
0
  cookie.stat_info.st_ex_gid = fsp->fsp_name->st.st_ex_gid;
296
0
  cookie.stat_info.st_ex_rdev = fsp->fsp_name->st.st_ex_rdev;
297
0
  cookie.stat_info.st_ex_size = fsp->fsp_name->st.st_ex_size;
298
0
  cookie.stat_info.st_ex_atime = fsp->fsp_name->st.st_ex_atime;
299
0
  cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
300
0
  cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
301
0
  cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
302
0
  cookie.stat_info.st_ex_iflags = fsp->fsp_name->st.st_ex_iflags;
303
0
  cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
304
0
  cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
305
0
  cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
306
307
0
  ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
308
0
      (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
309
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
310
0
    status = ndr_map_error2ntstatus(ndr_err);
311
0
    return status;
312
0
  }
313
314
0
  if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
315
0
    DBG_DEBUG("New cookie\n");
316
0
    NDR_PRINT_DEBUG(vfs_default_durable_cookie, &cookie);
317
0
  }
318
319
0
do_close:
320
0
  status = fd_close(fsp);
321
0
  if (!NT_STATUS_IS_OK(status)) {
322
0
    data_blob_free(&new_cookie_blob);
323
0
    return status;
324
0
  }
325
326
0
  *new_cookie = new_cookie_blob;
327
0
  return NT_STATUS_OK;
328
0
}
329
330
331
/**
332
 * Check whether a cookie-stored struct info is the same
333
 * as a given SMB_STRUCT_STAT, as coming with the fsp.
334
 */
335
static bool vfs_default_durable_reconnect_check_stat(
336
        struct vfs_default_durable_stat *cookie_st,
337
        struct files_struct *fsp)
338
0
{
339
0
  SMB_STRUCT_STAT *fsp_st = &fsp->fsp_name->st;
340
0
  bool equal;
341
342
0
  if (fsp->op->global->persistent) {
343
0
    return true;
344
0
  }
345
346
0
  if (cookie_st->st_ex_mode != fsp_st->st_ex_mode) {
347
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
348
0
        "stat_ex.%s differs: "
349
0
        "cookie:%llu != stat:%llu, "
350
0
        "denying durable reconnect\n",
351
0
        fsp_str_dbg(fsp),
352
0
        "st_ex_mode",
353
0
        (unsigned long long)cookie_st->st_ex_mode,
354
0
        (unsigned long long)fsp_st->st_ex_mode));
355
0
    return false;
356
0
  }
357
358
0
  if (cookie_st->st_ex_nlink != fsp_st->st_ex_nlink) {
359
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
360
0
        "stat_ex.%s differs: "
361
0
        "cookie:%llu != stat:%llu, "
362
0
        "denying durable reconnect\n",
363
0
        fsp_str_dbg(fsp),
364
0
        "st_ex_nlink",
365
0
        (unsigned long long)cookie_st->st_ex_nlink,
366
0
        (unsigned long long)fsp_st->st_ex_nlink));
367
0
    return false;
368
0
  }
369
370
0
  if (cookie_st->st_ex_uid != fsp_st->st_ex_uid) {
371
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
372
0
        "stat_ex.%s differs: "
373
0
        "cookie:%llu != stat:%llu, "
374
0
        "denying durable reconnect\n",
375
0
        fsp_str_dbg(fsp),
376
0
        "st_ex_uid",
377
0
        (unsigned long long)cookie_st->st_ex_uid,
378
0
        (unsigned long long)fsp_st->st_ex_uid));
379
0
    return false;
380
0
  }
381
382
0
  if (cookie_st->st_ex_gid != fsp_st->st_ex_gid) {
383
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
384
0
        "stat_ex.%s differs: "
385
0
        "cookie:%llu != stat:%llu, "
386
0
        "denying durable reconnect\n",
387
0
        fsp_str_dbg(fsp),
388
0
        "st_ex_gid",
389
0
        (unsigned long long)cookie_st->st_ex_gid,
390
0
        (unsigned long long)fsp_st->st_ex_gid));
391
0
    return false;
392
0
  }
393
394
0
  if (cookie_st->st_ex_rdev != fsp_st->st_ex_rdev) {
395
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
396
0
        "stat_ex.%s differs: "
397
0
        "cookie:%llu != stat:%llu, "
398
0
        "denying durable reconnect\n",
399
0
        fsp_str_dbg(fsp),
400
0
        "st_ex_rdev",
401
0
        (unsigned long long)cookie_st->st_ex_rdev,
402
0
        (unsigned long long)fsp_st->st_ex_rdev));
403
0
    return false;
404
0
  }
405
406
0
  if (cookie_st->st_ex_size != fsp_st->st_ex_size) {
407
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
408
0
        "stat_ex.%s differs: "
409
0
        "cookie:%llu != stat:%llu, "
410
0
        "denying durable reconnect\n",
411
0
        fsp_str_dbg(fsp),
412
0
        "st_ex_size",
413
0
        (unsigned long long)cookie_st->st_ex_size,
414
0
        (unsigned long long)fsp_st->st_ex_size));
415
0
    return false;
416
0
  }
417
418
0
  equal = timespec_equal(&cookie_st->st_ex_atime, &fsp_st->st_ex_atime);
419
0
  if (!equal) {
420
0
    struct timeval tc, ts;
421
0
    tc = convert_timespec_to_timeval(cookie_st->st_ex_atime);
422
0
    ts = convert_timespec_to_timeval(fsp_st->st_ex_atime);
423
424
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
425
0
        "stat_ex.%s differs: "
426
0
        "cookie:'%s' != stat:'%s', "
427
0
        "denying durable reconnect\n",
428
0
        fsp_str_dbg(fsp),
429
0
        "st_ex_atime",
430
0
        timeval_string(talloc_tos(), &tc, true),
431
0
        timeval_string(talloc_tos(), &ts, true)));
432
0
    return false;
433
0
  }
434
435
0
  equal = timespec_equal(&cookie_st->st_ex_mtime, &fsp_st->st_ex_mtime);
436
0
  if (!equal) {
437
0
    struct timeval tc, ts;
438
0
    tc = convert_timespec_to_timeval(cookie_st->st_ex_mtime);
439
0
    ts = convert_timespec_to_timeval(fsp_st->st_ex_mtime);
440
441
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
442
0
        "stat_ex.%s differs: "
443
0
        "cookie:'%s' != stat:'%s', "
444
0
        "denying durable reconnect\n",
445
0
        fsp_str_dbg(fsp),
446
0
        "st_ex_mtime",
447
0
        timeval_string(talloc_tos(), &tc, true),
448
0
        timeval_string(talloc_tos(), &ts, true)));
449
0
    return false;
450
0
  }
451
452
0
  equal = timespec_equal(&cookie_st->st_ex_ctime, &fsp_st->st_ex_ctime);
453
0
  if (!equal) {
454
0
    struct timeval tc, ts;
455
0
    tc = convert_timespec_to_timeval(cookie_st->st_ex_ctime);
456
0
    ts = convert_timespec_to_timeval(fsp_st->st_ex_ctime);
457
458
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
459
0
        "stat_ex.%s differs: "
460
0
        "cookie:'%s' != stat:'%s', "
461
0
        "denying durable reconnect\n",
462
0
        fsp_str_dbg(fsp),
463
0
        "st_ex_ctime",
464
0
        timeval_string(talloc_tos(), &tc, true),
465
0
        timeval_string(talloc_tos(), &ts, true)));
466
0
    return false;
467
0
  }
468
469
0
  equal = timespec_equal(&cookie_st->st_ex_btime, &fsp_st->st_ex_btime);
470
0
  if (!equal) {
471
0
    struct timeval tc, ts;
472
0
    tc = convert_timespec_to_timeval(cookie_st->st_ex_btime);
473
0
    ts = convert_timespec_to_timeval(fsp_st->st_ex_btime);
474
475
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
476
0
        "stat_ex.%s differs: "
477
0
        "cookie:'%s' != stat:'%s', "
478
0
        "denying durable reconnect\n",
479
0
        fsp_str_dbg(fsp),
480
0
        "st_ex_btime",
481
0
        timeval_string(talloc_tos(), &tc, true),
482
0
        timeval_string(talloc_tos(), &ts, true)));
483
0
    return false;
484
0
  }
485
486
0
  if (cookie_st->st_ex_iflags != fsp_st->st_ex_iflags) {
487
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
488
0
        "stat_ex.%s differs: "
489
0
        "cookie:%llu != stat:%llu, "
490
0
        "denying durable reconnect\n",
491
0
        fsp_str_dbg(fsp),
492
0
        "st_ex_calculated_birthtime",
493
0
        (unsigned long long)cookie_st->st_ex_iflags,
494
0
        (unsigned long long)fsp_st->st_ex_iflags));
495
0
    return false;
496
0
  }
497
498
0
  if (cookie_st->st_ex_blksize != fsp_st->st_ex_blksize) {
499
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
500
0
        "stat_ex.%s differs: "
501
0
        "cookie:%llu != stat:%llu, "
502
0
        "denying durable reconnect\n",
503
0
        fsp_str_dbg(fsp),
504
0
        "st_ex_blksize",
505
0
        (unsigned long long)cookie_st->st_ex_blksize,
506
0
        (unsigned long long)fsp_st->st_ex_blksize));
507
0
    return false;
508
0
  }
509
510
0
  if (cookie_st->st_ex_blocks != fsp_st->st_ex_blocks) {
511
0
    DEBUG(1, ("vfs_default_durable_reconnect (%s): "
512
0
        "stat_ex.%s differs: "
513
0
        "cookie:%llu != stat:%llu, "
514
0
        "denying durable reconnect\n",
515
0
        fsp_str_dbg(fsp),
516
0
        "st_ex_blocks",
517
0
        (unsigned long long)cookie_st->st_ex_blocks,
518
0
        (unsigned long long)fsp_st->st_ex_blocks));
519
0
    return false;
520
0
  }
521
522
0
  if (cookie_st->st_ex_flags != fsp_st->st_ex_flags) {
523
0
    DBG_WARNING(" (%s): "
524
0
          "stat_ex.%s differs: "
525
0
          "cookie:%"PRIu32" != stat:%"PRIu32", "
526
0
          "denying durable reconnect\n",
527
0
          fsp_str_dbg(fsp),
528
0
          "st_ex_flags",
529
0
          cookie_st->st_ex_flags,
530
0
          fsp_st->st_ex_flags);
531
0
    return false;
532
0
  }
533
534
0
  return true;
535
0
}
536
537
struct durable_reconnect_state {
538
  struct smbXsrv_open *op;
539
  struct share_mode_entry *e;
540
};
541
542
static bool share_mode_entry_durable_reconnect_cb(
543
  struct share_mode_entry *e,
544
  bool *modified,
545
  void *private_data)
546
0
{
547
0
  struct durable_reconnect_state *state = private_data;
548
0
  struct smbXsrv_open_global0 *global = state->op->global;
549
0
  uint64_t id = global->open_persistent_id;
550
551
0
  if (e->share_file_id != id) {
552
0
    return false; /* Look at potential other entries */
553
0
  }
554
0
  if (state->e->share_file_id == id) {
555
0
    DBG_INFO("Found more than one entry, invalidating previous\n");
556
0
    *state->e = (struct share_mode_entry) { .pid = { .pid = 0, }};
557
0
    return true; /* end the loop through share mode entries */
558
0
  }
559
560
0
  if (global->persistent) {
561
0
    if (!(e->flags & SHARE_ENTRY_FLAG_PERSISTENT_OPEN)) {
562
0
      DBG_WARNING("Persistent not set on sharemode entry\n");
563
0
      return false;
564
0
    }
565
0
    if (serverid_exists(&e->pid)) {
566
0
      return false; /* Look at potential other entries */
567
0
    }
568
0
    if (!GUID_equal(&e->create_guid, &global->create_guid)) {
569
0
      return false; /* Look at potential other entries */
570
0
    }
571
0
    if (GUID_equal(&state->e->create_guid, &global->create_guid)) {
572
0
      DBG_INFO("Found more than one entry, "
573
0
         "invalidating previous\n");
574
0
      *state->e = (struct share_mode_entry) {
575
0
        .pid = { .pid = 0, },
576
0
      };
577
0
      return true; /* end the loop */
578
0
    }
579
0
    *state->e = *e;
580
0
    return false; /* Look at potential other entries */
581
0
  }
582
583
0
  if (!server_id_is_disconnected(&e->pid)) {
584
0
    return false; /* Look at potential other entries */
585
0
  }
586
587
0
  *state->e = *e;
588
0
  return false;   /* Look at potential other entries */
589
0
}
590
591
struct vfs_default_durable_reconnect_state {
592
  NTSTATUS status;
593
  TALLOC_CTX *mem_ctx;
594
  struct smb_request *smb1req;
595
  struct smbXsrv_open *op;
596
  const struct smb2_lease *lease;
597
  struct vfs_default_durable_cookie cookie;
598
  struct files_struct *fsp;
599
  struct files_struct *dirfsp;
600
  struct smb_filename *rel_fname;
601
  DATA_BLOB new_cookie_blob;
602
};
603
604
static NTSTATUS vfs_default_durable_reconnect_lease(
605
  struct vfs_default_durable_reconnect_state *state,
606
  struct share_mode_lock *lck,
607
  struct share_mode_entry *e)
608
0
{
609
0
  struct files_struct *fsp = state->fsp;
610
0
  struct smb2_lease lease;
611
0
  uint32_t current_state = 0;
612
0
  uint32_t breaking_to_requested = 0;
613
0
  uint32_t breaking_to_required = 0;
614
0
  uint16_t lease_version = 0, epoch = 0;
615
0
  bool breaking = false;
616
0
  NTSTATUS status;
617
618
0
  if (fsp->oplock_type != LEASE_OPLOCK) {
619
0
    return NT_STATUS_OK;
620
0
  }
621
622
  /*
623
   * Ensure the existing client guid matches the
624
   * stored one in the share_mode_entry.
625
   */
626
0
  if (!GUID_equal(fsp_client_guid(fsp), &e->client_guid)) {
627
0
    return NT_STATUS_OBJECT_NAME_NOT_FOUND;
628
0
  }
629
630
0
  status = leases_db_get(&e->client_guid,
631
0
             &e->lease_key,
632
0
             &fsp->file_id,
633
0
             &current_state,
634
0
             &breaking,
635
0
             &breaking_to_requested,
636
0
             &breaking_to_required,
637
0
             &lease_version,
638
0
             &epoch);
639
0
  if (!NT_STATUS_IS_OK(status) &&
640
0
      !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND))
641
0
  {
642
0
    return status;
643
0
  }
644
645
0
  if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
646
    /*
647
     * The lease was lost due to a node failure, we have to recreate
648
     * it.
649
     */
650
0
    if (!state->op->global->persistent) {
651
0
      return NT_STATUS_OBJECT_NAME_NOT_FOUND;
652
0
    }
653
0
    lease = *state->lease;
654
0
    lease.lease_state &= fsp->conn->tcon->smb_max_lease_mask;
655
656
0
    if (!(lease.lease_state & SMB2_LEASE_WRITE) &&
657
0
        !(fsp->conn->tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT) &&
658
0
        file_has_brlocks(fsp))
659
0
    {
660
      /*
661
       * Shared leases (R and RH) are discarded when
662
       * reconnecting on a failover cluster
663
       * (SMB2_SHARE_CAP_SCALEOUT not set) if the file
664
       * has byterange locks.
665
       */
666
0
      lease.lease_state = 0;
667
0
    }
668
669
0
    if (lease.lease_state == SMB2_LEASE_READ) {
670
      /*
671
       * A pure R-lease is always "reacquired" and hence the
672
       * epoch is incremented. Other leases are "protected"
673
       * and the epoch must be taken unchanged from the client
674
       * lease request.
675
       */
676
0
      lease.lease_epoch++;
677
0
    }
678
0
    return grant_new_fsp_lease(fsp,
679
0
             lck,
680
0
             fsp_client_guid(fsp),
681
0
             &lease,
682
0
             lease.lease_state,
683
0
             false);
684
0
  }
685
686
0
  if (!state->op->global->persistent) {
687
0
    goto fsp_lease;
688
0
  }
689
690
0
  if (breaking) {
691
    /*
692
     * Assert only a persistent open can trigger this "stored" lease
693
     * break codepath.
694
     */
695
0
    SMB_ASSERT(state->op->global->persistent);
696
697
    /*
698
     * A "saved" break from when the handle was disconnected, send
699
     * it out now. Assert that the current leases state is still
700
     * the same as breaking_to_requested.
701
     */
702
0
    SMB_ASSERT(current_state == breaking_to_requested);
703
0
    SMB_ASSERT(breaking_to_requested != breaking_to_required);
704
705
    /*
706
     * process_oplock_break_message() will set
707
     * breaking_to_requested = breaking_to_required
708
     */
709
0
    send_break_message(fsp->conn->sconn->msg_ctx,
710
0
           &fsp->file_id,
711
0
           e,
712
0
           breaking_to_required);
713
714
0
    goto fsp_lease;
715
0
  }
716
717
0
  if (!(current_state & SMB2_LEASE_WRITE) &&
718
0
      !(fsp->conn->tcon->capabilities & SMB2_SHARE_CAP_SCALEOUT) &&
719
0
      file_has_brlocks(fsp))
720
0
  {
721
    /*
722
     * Shared leases (R and RH) are discarded when
723
     * reconnecting on a failover cluster
724
     * (SMB2_SHARE_CAP_SCALEOUT not set) if the file
725
     * has byterange locks.
726
     */
727
0
    current_state = 0;
728
0
  }
729
0
  if (!(current_state & SMB2_LEASE_HANDLE)) {
730
    /*
731
     * Without a H-lease the epoch is taken from the request as if a
732
     * new lease was granted.
733
     */
734
0
    epoch = state->lease->lease_epoch;
735
0
  }
736
0
  if (current_state == SMB2_LEASE_READ) {
737
    /*
738
     * A R-only lease is only handled as if freshly acquired, hence
739
     * the epoch is taken from the client request and incremented by
740
     * one.
741
     */
742
0
    epoch++;
743
0
  }
744
745
0
  status = leases_db_set(&e->client_guid,
746
0
             &e->lease_key,
747
0
             current_state,
748
0
             breaking,
749
0
             breaking_to_requested,
750
0
             breaking_to_required,
751
0
             lease_version,
752
0
             epoch);
753
0
  if (!NT_STATUS_IS_OK(status)) {
754
0
    return status;
755
0
  }
756
757
0
fsp_lease:
758
0
  fsp->lease = find_fsp_lease(fsp,
759
0
            &e->lease_key,
760
0
            current_state,
761
0
            lease_version,
762
0
            epoch);
763
0
  if (fsp->lease == NULL) {
764
0
    return NT_STATUS_NO_MEMORY;
765
0
  }
766
767
0
  return NT_STATUS_OK;
768
0
}
769
770
static void vfs_default_durable_reconnect_fn(struct share_mode_lock *lck,
771
               struct byte_range_lock *br_lck,
772
               void *private_data)
773
0
{
774
0
  struct vfs_default_durable_reconnect_state *state = private_data;
775
0
  const struct loadparm_substitution *lp_sub =
776
0
    loadparm_s3_global_substitution();
777
0
  struct files_struct *fsp = state->fsp;
778
0
  struct share_mode_entry e = { .pid = { .pid = 0, }};
779
0
  struct durable_reconnect_state rstate = { .op = state->op, .e = &e, };
780
0
  struct vfs_open_how how = { .flags = 0, };
781
0
  struct file_id file_id;
782
0
  struct server_id old_pid;
783
0
  bool have_share_mode_entry = false;
784
0
  uint32_t dosmode;
785
0
  int ret;
786
0
  bool ok;
787
788
0
  ok = share_mode_forall_entries(lck,
789
0
               share_mode_entry_durable_reconnect_cb,
790
0
               &rstate);
791
0
  if (!ok) {
792
0
    DBG_WARNING("share_mode_forall_entries failed\n");
793
0
    state->status = NT_STATUS_INTERNAL_DB_ERROR;
794
0
    goto fail;
795
0
  }
796
797
0
  if (e.pid.pid == 0) {
798
0
    DBG_WARNING("Did not find a unique valid share mode entry\n");
799
0
    state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
800
0
    goto fail;
801
0
  }
802
803
0
  if ((e.access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
804
0
      !CAN_WRITE(fsp->conn))
805
0
  {
806
0
    DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
807
0
        "share[%s] is not writeable anymore\n",
808
0
        lp_servicename(talloc_tos(), lp_sub, SNUM(fsp->conn))));
809
0
    state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
810
0
    goto fail;
811
0
  }
812
813
0
  if ((e.op_type == LEASE_OPLOCK) && (state->lease == NULL)) {
814
    /*
815
     * The client didn't send a lease context when reconnecting,
816
     * although the handle did have a lease.
817
     */
818
0
    DBG_WARNING("Trying to reconnect handle with lease without lease context on [%s]\n",
819
0
          fsp_str_dbg(fsp));
820
0
    state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
821
0
    goto fail;
822
0
  }
823
824
0
  fsp_apply_share_entry_flags(fsp, e.flags);
825
0
  fsp->open_time = e.time;
826
0
  fsp->access_mask = e.access_mask;
827
0
  if (S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
828
0
    fsp->fsp_flags.can_read = ((fsp->access_mask & FILE_READ_DATA) != 0);
829
0
    fsp->fsp_flags.can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
830
0
  } else {
831
0
    fsp->fsp_flags.can_read = false;
832
0
    fsp->fsp_flags.can_write = false;
833
0
  }
834
835
0
  fsp->oplock_type = e.op_type;
836
837
0
  fsp->initial_allocation_size = state->cookie.initial_allocation_size;
838
0
  fh_set_position_information(fsp->fh, state->cookie.position_information);
839
0
  fsp->fsp_flags.write_time_forced = state->cookie.write_time_forced;
840
0
  if (state->op->global->persistent) {
841
0
    fsp->fsp_flags.initial_delete_on_close =
842
0
      state->cookie.initial_delete_on_close;
843
0
    fsp->fsp_flags.delete_on_close = is_delete_on_close_set(
844
0
      lck, fsp->name_hash);
845
0
  }
846
847
0
  state->op->compat = fsp;
848
0
  fsp->op = state->op;
849
850
0
  old_pid = e.pid;
851
0
  e.pid = messaging_server_id(fsp->conn->sconn->msg_ctx);
852
853
0
  ok = reset_share_mode_entry(
854
0
    lck,
855
0
    old_pid,
856
0
    e.share_file_id,
857
0
    e.pid,
858
0
    state->smb1req->mid);
859
0
  if (!ok) {
860
0
    DBG_DEBUG("Could not set new share_mode_entry values\n");
861
0
    state->status = NT_STATUS_INTERNAL_ERROR;
862
0
    goto fail;
863
0
  }
864
0
  have_share_mode_entry = true;
865
866
0
  state->status = vfs_default_durable_reconnect_lease(state, lck, &e);
867
0
  if (!NT_STATUS_IS_OK(state->status)) {
868
0
    DBG_WARNING("vfs_default_durable_reconnect_lease failed\n");
869
0
    goto fail;
870
0
  }
871
872
0
  if (br_lck != NULL) {
873
0
    ok = brl_reconnect_disconnected(fsp, br_lck);
874
0
    if (!ok) {
875
0
      state->status = NT_STATUS_INTERNAL_ERROR;
876
0
      DBG_ERR("failed to reopen brlocks: %s\n",
877
0
        nt_errstr(state->status));
878
0
      goto fail;
879
0
    }
880
0
  }
881
882
  /*
883
   * TODO: properly calculate open flags
884
   */
885
0
  if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
886
0
    how.flags = O_RDONLY | O_DIRECTORY;
887
0
  } else if (fsp->fsp_flags.can_write && fsp->fsp_flags.can_read) {
888
0
    how.flags = O_RDWR;
889
0
  } else if (fsp->fsp_flags.can_write) {
890
0
    how.flags = O_WRONLY;
891
0
  } else if (fsp->fsp_flags.can_read) {
892
0
    how.flags = O_RDONLY;
893
0
  }
894
895
0
  state->status = fd_openat(state->dirfsp, state->rel_fname, fsp, &how);
896
0
  if (!NT_STATUS_IS_OK(state->status)) {
897
0
    DBG_ERR("failed to open file: %s\n", nt_errstr(state->status));
898
0
    goto fail;
899
0
  }
900
901
  /*
902
   * We now check the stat info stored in the cookie against
903
   * the current stat data from the file we just opened.
904
   * If any detail differs, we deny the durable reconnect,
905
   * because in that case it is very likely that someone
906
   * opened the file while the handle was disconnected,
907
   * which has to be interpreted as an oplock break.
908
   */
909
910
0
  ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
911
0
  if (ret == -1) {
912
0
    state->status = map_nt_error_from_unix_common(errno);
913
0
    DBG_ERR("Unable to fstat stream: %s => %s\n",
914
0
      fsp_str_dbg(fsp),
915
0
      nt_errstr(state->status));
916
0
    goto fail;
917
0
  }
918
919
0
  if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) &&
920
0
      !fsp->op->global->persistent)
921
0
  {
922
0
    state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
923
0
    goto fail;
924
0
  }
925
926
0
  file_id = vfs_file_id_from_sbuf(fsp->conn, &fsp->fsp_name->st);
927
0
  if (!file_id_equal(&state->cookie.id, &file_id)) {
928
0
    state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
929
0
    goto fail;
930
0
  }
931
932
0
  dosmode = fdos_mode(fsp);
933
0
  fsp->fsp_flags.is_sparse = (dosmode & FILE_ATTRIBUTE_SPARSE);
934
0
  fsp->fsp_flags.is_sparse |= e.flags & SHARE_ENTRY_FLAG_POSIX_OPEN;
935
936
0
  ok = vfs_default_durable_reconnect_check_stat(&state->cookie.stat_info,
937
0
                  fsp);
938
0
  if (!ok) {
939
0
    state->status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
940
0
    goto fail;
941
0
  }
942
943
0
  state->status = set_file_oplock(fsp);
944
0
  if (!NT_STATUS_IS_OK(state->status)) {
945
0
    goto fail;
946
0
  }
947
948
0
  state->status = vfs_default_durable_cookie(fsp,
949
0
               state->mem_ctx,
950
0
               &state->new_cookie_blob);
951
0
  if (!NT_STATUS_IS_OK(state->status)) {
952
0
    DBG_ERR("vfs_default_durable_cookie - %s\n",
953
0
      nt_errstr(state->status));
954
0
    goto fail;
955
0
  }
956
957
0
  state->smb1req->chain_fsp = fsp;
958
0
  state->smb1req->smb2req->compat_chain_fsp = fsp;
959
960
0
  DBG_DEBUG("opened file '%s'\n", fsp_str_dbg(fsp));
961
962
0
  fsp->fsp_flags.is_fsa = true;
963
964
0
  state->status = NT_STATUS_OK;
965
0
  return;
966
967
0
fail:
968
0
  if (have_share_mode_entry) {
969
    /*
970
     * Something is screwed up, delete the sharemode entry.
971
     */
972
0
    del_share_mode(lck, fsp);
973
0
  }
974
0
  if (fsp_get_pathref_fd(fsp) != -1) {
975
0
    NTSTATUS close_status;
976
0
    close_status = fd_close(fsp);
977
0
    if (!NT_STATUS_IS_OK(close_status)) {
978
0
      DBG_ERR("fd_close failed (%s), leaking fd\n",
979
0
        nt_errstr(close_status));
980
0
    }
981
0
  }
982
0
  state->op->compat = NULL;
983
0
  fsp->op = NULL;
984
0
}
985
986
NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
987
               struct smb_request *smb1req,
988
               struct smbXsrv_open *op,
989
               const DATA_BLOB old_cookie,
990
               const struct smb2_lease *lease,
991
               TALLOC_CTX *mem_ctx,
992
               files_struct **result,
993
               DATA_BLOB *new_cookie)
994
0
{
995
0
  struct vfs_default_durable_reconnect_state state;
996
0
  struct smb_filename *smb_fname = NULL;
997
0
  struct file_id file_id;
998
0
  NTSTATUS status;
999
0
  enum ndr_err_code ndr_err;
1000
0
  bool ok;
1001
1002
0
  *result = NULL;
1003
0
  *new_cookie = data_blob_null;
1004
1005
0
  if (!lp_durable_handles(SNUM(conn))) {
1006
0
    return NT_STATUS_NOT_SUPPORTED;
1007
0
  }
1008
1009
0
  state = (struct vfs_default_durable_reconnect_state) {
1010
0
    .mem_ctx = mem_ctx,
1011
0
    .smb1req = smb1req,
1012
0
    .op = op,
1013
0
    .lease = lease,
1014
0
  };
1015
1016
  /*
1017
   * the checks for kernel oplocks
1018
   * and similar things are done
1019
   * in the vfs_default_durable_cookie()
1020
   * call below.
1021
   */
1022
1023
0
  ndr_err = ndr_pull_struct_blob_all(
1024
0
    &old_cookie,
1025
0
    talloc_tos(),
1026
0
    &state.cookie,
1027
0
    (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
1028
0
  if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1029
0
    status = ndr_map_error2ntstatus(ndr_err);
1030
0
    return status;
1031
0
  }
1032
1033
0
  if (CHECK_DEBUGLVL(DBGLVL_DEBUG)) {
1034
0
    DBG_DEBUG("Cookie:\n");
1035
0
    NDR_PRINT_DEBUG(vfs_default_durable_cookie, &state.cookie);
1036
0
  }
1037
1038
0
  if (strcmp(state.cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
1039
0
    return NT_STATUS_INVALID_PARAMETER;
1040
0
  }
1041
1042
0
  if (state.cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
1043
0
    return NT_STATUS_INVALID_PARAMETER;
1044
0
  }
1045
1046
0
  if (!state.cookie.allow_reconnect) {
1047
0
    return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1048
0
  }
1049
1050
0
  if (strcmp(state.cookie.servicepath, conn->connectpath) != 0) {
1051
0
    return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1052
0
  }
1053
1054
0
  status = filename_convert_dirfsp_rel(talloc_tos(),
1055
0
               conn,
1056
0
               conn->cwd_fsp,
1057
0
               state.cookie.base_name,
1058
0
               UCF_LCOMP_LNK_OK,
1059
0
               0,
1060
0
               &state.dirfsp,
1061
0
               &smb_fname,
1062
0
               &state.rel_fname);
1063
0
  if (!NT_STATUS_IS_OK(status)) {
1064
0
    return status;
1065
0
  }
1066
0
  if (!VALID_STAT(smb_fname->st)) {
1067
0
    return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1068
0
  }
1069
0
  if (!S_ISREG(smb_fname->st.st_ex_mode)) {
1070
0
    if (!S_ISDIR(smb_fname->st.st_ex_mode)) {
1071
0
      return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1072
0
    }
1073
0
    if (!op->global->persistent) {
1074
0
      return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1075
0
    }
1076
0
  }
1077
1078
0
  file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
1079
0
  if (!file_id_equal(&state.cookie.id, &file_id)) {
1080
0
    return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1081
0
  }
1082
1083
0
  state.fsp = fsp_new(conn, conn);
1084
0
  if (state.fsp == NULL) {
1085
0
    DBG_ERR("failed to create new fsp\n");
1086
0
    return NT_STATUS_NO_MEMORY;
1087
0
  }
1088
0
  state.fsp->file_id = file_id;
1089
0
  state.fsp->file_pid = smb1req->smbpid;
1090
0
  state.fsp->vuid = smb1req->vuid;
1091
0
  state.fsp->fnum = op->local_id;
1092
0
  fh_set_gen_id(state.fsp->fh, op->global->open_global_id);
1093
1094
0
  ok = fsp_set_smb_fname(state.fsp, smb_fname);
1095
0
  if (!ok) {
1096
0
    DBG_ERR("fsp_set_smb_fname failed\n");
1097
0
    file_free(smb1req, state.fsp);
1098
0
    return NT_STATUS_NO_MEMORY;
1099
0
  }
1100
1101
  /*
1102
   * TODO:
1103
   * Do we need to store the modified flag in the DB?
1104
   */
1105
0
  state.fsp->fsp_flags.modified = false;
1106
0
  state.fsp->fsp_flags.is_directory = S_ISDIR(smb_fname->st.st_ex_mode);
1107
  /*
1108
   * For normal files, can_lock == !is_directory
1109
   */
1110
0
  state.fsp->fsp_flags.can_lock = !state.fsp->fsp_flags.is_directory;
1111
  /*
1112
   * We do not support aio write behind for smb2
1113
   */
1114
0
  state.fsp->fsp_flags.aio_write_behind = false;
1115
1116
0
  status = share_mode_do_locked_brl(state.fsp,
1117
0
            vfs_default_durable_reconnect_fn,
1118
0
            &state);
1119
0
  if (!NT_STATUS_IS_OK(status)) {
1120
0
    DBG_ERR("share_mode_do_locked_brl [%s] failed: %s\n",
1121
0
      smb_fname_str_dbg(smb_fname), nt_errstr(status));
1122
0
    file_free(smb1req, state.fsp);
1123
0
    return status;
1124
0
  }
1125
0
  if (!NT_STATUS_IS_OK(state.status)) {
1126
0
    DBG_ERR("default_durable_reconnect_fn [%s] failed: %s\n",
1127
0
      smb_fname_str_dbg(smb_fname),
1128
0
      nt_errstr(state.status));
1129
0
    file_free(smb1req, state.fsp);
1130
0
    return state.status;
1131
0
  }
1132
1133
0
  *result = state.fsp;
1134
0
  *new_cookie = state.new_cookie_blob;
1135
1136
0
  return NT_STATUS_OK;
1137
0
}